黄金眼——SQL注入扫描器的制作(1)
( 作者:mikespook | 发布日期:2004-5-16 | 浏览次数:125 )
关键字:黄金眼,SQL注入,扫描器,C# | ||||
本文最早是为《黑客安全基地》撰写的。后来由于一些原因,该杂志停刊。所以现在整理后发到我的站上,给大家观赏吧。因为“黄金眼”从我发布到现在已经有大半年的时间,所以如果您的站还受到这个扫描器的困扰,那我只能说抱歉,您太懒了,该打补丁了! 本文内容具有一定的攻击性,这里仅为研究探讨。作者不对由于本文引起的任何后果负责。我希望阅读本文的朋友应该有一定的编程基础,因为本文将涉及大量的数据结构方面的知识。 经常有朋友问我:“我也想学黑客技术,学编程。我该怎么学?从哪开始学?”。今天,我就和大家探讨一下“黄金眼”SQL注入扫描器的编写思路以及技术细节。这里我并不是希望大家看过本文之后只会照猫画虎的去写扫描器去扫网站帐号,而是希望我在编写这个扫描器中的一些想法对大家有启发。 两个问题:1. 什么是“黄金眼” “黄金眼”是我在2003年9月初发布的一款针对“金梅在线电影免费会员版”存在的SQL注漏洞获取管理员帐号的扫描器。先后经历了1.0、1.1、1.2和最新版本1.3四个版本。其中我只发布了1.0、1.1、1.3三个版本。在每一次升级我都对内核部分的扫描算法进行了改进。使扫描速度成倍提高。 2. 什么是SQL注入漏洞,如何利用该漏洞 在我印象中,类似的文章已经不少了。老版本动网论坛、早期孤独剑客的网站、以及本扫描器针对的“金梅在线电影免费会员版”(为了方便期间,下文简称“金梅”系统。)这些动态页面程序都存在SQL注入漏洞。为了方便我后面的程序讲解下面我再重复一下什么是SQL注入漏洞。这里我使用ASP作为讲解的语言。当然如果你不懂ASP也没有关系。你只要理解我下面说的内容就可以了。 我们知道在动态页面的编写中,可以通过页面地址所带的参数获得数据。即GET方法。比如http://www.abc.com/movie.asp?id=123。这里问号后面的“id=123”就是GET方法传入的内容。变量名为“id”,变量值为“123”。而后台页面中操作这个变量,其实很简单。以ASP页面为例:
这里“request.querystring(“id”)”返回的就是传入的内容“123”。当然,如果你用“movie.asp?id=hello world”访问,那么“request.querystring(“id”)”返回的就是“hello world”。 那这里会出现什么漏洞呢?当然,如果只是这样的页面就什么漏洞也没有。如果是下面的程序呢:
写过ASP的朋友都知道,这是从“admin”这张表中查找字段“aID”为“request.querystring(“id”)”的记录。比如前面说的“123”。实际在“rs.open sql,conn,1,1”执行SQL语句的时候是在执行“SELECT * FROM admin WHERE aID=123”这句。上面这段程序,正常执行肯定没有问题。但是我们期望“request.querystring(“id”)”是一个合法的字段值。比如索引编号必须为数字。如果“request.querystring(“id”)”是数字会怎么样呢?当然是出错了。我们使用下面的地址访问movie.asp这个页面:“movie.asp?id=hello world”。这时候,会提示出错。因为“aID”这个字段是一个编号,必须为数字。而我们输入的是一个字符串。实际执行时候的SQL语句是“SELECT * FROM admin WHERE aID=hello world”,这当然会出错! 大家请注意:出错的地方就是我们的突破口! 大家再来看看使用“movie.asp?id=123 and 1=1”访问会有什么样的结果。这时候实际执行的SQL语句是“SELECT * FROM admin WHERE aID=123 and 1=1”我们知道“1”一定是等于“1”的。那么这个SQL语句执行的效果和“SELECT * FROM admin WHERE aID=123”是完全一样。是不会出错的!但是如果你将“and 1=1”改为“and 1=2”就会出现使用“hello word”访问的时候出现的错误。 如果我们能用语句查找字段内容,返回查找的值。我们不就可以用“and 1=X”来测试么?只有当X等于“1”时,才能正确显示页面。 以“金梅”系统为例。它使用ACCESS数据库。管理员帐号是存在数据表“password”中。有三个字段:“id”、“name”、“pwd”。分别存放“序号”、“管理员名”、“密码”。非常巧合的是,“金梅”系统只有一个管理员。并且“id”为“1”。 好了,其实我们的入侵代码已经很好写了: 使用“SELECT id FROM password WHERE name=admin”可以测试管理员名是不是“admin”。如果管理员名是“admin”则该SQL语句返回值“1”。否则为其他值。使用刚才提到的“and 1=1”判断,就可以知道我们猜测的管理员名是不是“admin”。完整的入侵代码如下: “movie.asp?id=123 and 1=(SELECT id FROM password WHERE name=admin)” 但是这里有个问题是我们必须穷举才能测试出管理员名是多少。有没有更快速更简单的方法呢?有! ACCESS给我们提供了很多函数以简化操作。比如len()可以获得一个字段值的长度: “movie.asp?id=123 and 1=(SELECT id FROM password WHERE len(name)=10)” 当管理员名长度为10的时候,访问成功。当然,我们也可以用“大于”、“小于”来大概判断一下管理员名的长度: “movie.asp?id=123 and 1=(SELECT id FROM password WHERE len(name)<10)” 当上面的地址访问成功的时候,说明管理员名长度小于10。反之管理员名长度大于或等于10。 当确定了管理员名的长度,我们就可以确定管理员名的内容。这里还有两个函数需要简单介绍:mid(str, index, len)与asc()。mid()函数返回指定序号,指定长度的子串。有三个参数:str为输入的字符串,index为标号,len为长度。比如mid(“abcdefg”, 3, 3)会返回字符串“cde”。函数asc()是返回参数的ASCII码。asc(‘M’)返回的就是十进制数77。利用这两个函数,我们可以逐位测试出管理员名: 测试管理员名第一位的ASCII码是不是小于99:“movie.asp?id=123 and 1=(SELECT id FROM password WHERE asc(mid(name,1,1))<99)” 测试管理员名第一位的ASCII码是不是大于97:“movie.asp?id=123 and 1=(SELECT id FROM password WHERE asc(mid(name,1,1))>97)” 测试管理员名第一位的ASCII码是不是等于98:“movie.asp?id=123 and 1=(SELECT id FROM password WHERE asc(mid(name,1,1))=98)” ………… 这样也就测试出管理员名的第一位,然后接着测试第二位第三位…… …… “movie.asp?id=123 and 1=(SELECT id FROM password WHERE asc(mid(name,2,1))<97)” …… “movie.asp?id=123 and 1=(SELECT id FROM password WHERE asc(mid(name,3,1))>98)” …… 每次只记录访问成功的页面的时候的ASCII值,然后换算成字母。得到的就是管理员名了。在查找密码的时候同样的道理,只要把“asc(mid(name,3,1))”中的name字段名换为pwd就可以了,比如测试密码第4位字符的ASCII码是不是小于104: “movie.asp?id=123 and 1=(SELECT id FROM password WHERE asc(mid(pwd,4,1))<104)” 现在我想你对SQL注入漏洞已经有一个大体的了解了。我希望你能下载一个“金梅”系统,搭建一个实验环境。自己动手试试,体会一下SQL注入漏洞的使用。这对你继续后面的内容很有帮助。 |