|
|
 |
| 浅析注入漏洞的查与补 |
| 作者:佚名 来源:转载 发布时间:2008-11-10 1:02:51 发布人:黑客动画吧 |
减小字体 增大字体
阿D、NBSI、HDSI等工具可以帮我们快速的拿下一个有注入漏洞的站点。但如果不懂注入原理,即便用这些工具进入无数个网站,最终还是一个工具菜鸟。所以我们菜鸟要进化,就不能停留在工具方面。我们要深入到程序内部,从源码入手,掌握注入的第一手资料。想了解注入漏洞的内幕吗?那就跟我来吧! 注入点的查找 当我们想要测试某个站点时,一般会架上注入工具对其狂轰乱炸。这样做虽然没错,但是比较盲目。我个人认为:如果有源码的话就从源码入手,在源码中查找注入点。对于源码的阅读,有些朋友可能会认为这很难。其实源码并不神秘,它也有一定的语法规则。看一套优秀的源码就像是在欣赏一部精美的电影,只要我们坚持每天看一些优秀源码,再加上百度这个老师的指点,用不了多久源码的神秘面纱就会被你揭去。 下面我们就开始查找注入点,目标有两个:一是Request,二是SQL语句。 Request 是ASP的一个内建对象,它是用来获取客户端信息的,有五种方法。而会出现注入点的一般有以下三种: 1.Request.QueryString:取得客户端提交的信息。当Form以Get方法提交信息,或是直接在URL中提交变量值时,在服务器端接收数据时采用的就是这种方法。 2.Request.Form:同样也是取得客户端提交的信息,但它接收的是Form以Post方法提交的信息。 3.Request.Cookies:取得客户端浏览器的Cookies信息。如用户名、密码。 有些程序员为了减少错误,会用Request来取得客户端提交的前两种信息,此法虽可通吃Request.QueryString和Request.Form,但如果过滤的不好,就会被漏洞反咬一口。 了解过一些Request的知识后,下面就在“查找”中输入“request”进行搜索。当找到上面所列的三项Request语句后,再看一下程序对这些Request语句是否做了过滤:比如ID值是否用INT过滤,如“id=int(request("id"))”。字符串值是否用replace()或instr()等函数进行过滤,如“username=replace(request("username"),"'","")”。或者程序是否采用本身的一些过滤函数来过滤提交值。从查找到request参数起,一直到SQL语句中使用这个提交值为止。如果中间没有上面的层层关卡,那么一个注入点基本上就形成了。 小知识:SQL查询语句。 1、查询语句:Select [(<字段名1> [,<字段名2>, ...])] FROM <表名> [Where <条件表达式> [AND|OR <条件表达式>...] 2、更新语句:Update <表名> SET 列名1 = 常量表达式1[,列名2 = 常量表达式2 ...] Where <条件表达式> [AND|OR <条件表达式>...] 3、删除语句:Delete FROM〈表名〉[Where <条件表达式> [AND|OR <条件表达式>...]] 在SQL语句中,注入点出现频率最高的是Select语句。而注入参数的出没地通常都是在Where之后的条件中。当一个没有过滤的Request语句进入SQL语句后,就是注入大显身手的时候了。不过在进行注入之前还要先看一下该参数是直接引入,还是用单引号引入的。另外还要注意该参数是否还应用于其它SQL语句中,然后根据不同的信息选择不同的处理方式:或直接暴破,或UNION查询。如果存在注入点的程序使用的是SQL数据库,那我们就不仅仅是得到一些重要信息了,甚至有可能添加管理员! 下面以“蚂蚁影院3.0”版注销用户(wantlogin.asp)中的一段源码做个介绍: <% if request("userid1")<>"" then set rst=server.createobject("adodb.recordset") sql="select money,online from users where userid='"&request("userid1")&"' and password='"&md5(request("pws"))&"'" rst.open sql,conn,1,3 if rst.eof and rst.bof then response.write"<script>alert('用户名或密码错误!');history.back();</Script>" else response.write"<script>alert('恢复成功你现在可以登录!');</Script>" response.write"<script Language=Javascript>location.href = 'index.asp';</script>" rst.close set rst=nothing conn.close set conn=nothing end if end if %> 在其流程中,首先判断取得的提交值userid1是否为空,不为空的话就进入SQL语句中验证取得的用户名及密码是否和数据库内的用户名及密码一致。如果不一致则弹出“用户名及密码错误”,一致就弹出“恢复成功”。这也是一段典型的注入漏洞源码,并且接收的方式还是使用的request,这就给我们提交注入语句提供了很大的方便。 我们在URL中提交如下字符:“http://127.0.0.1/wantlogin.asp?userid1=aa&pws=bb”,因为没有aa这个用户,所以弹出了错误窗口。而我们将aa换成如下字符:“aa' or 1=1 or '1'='1”,pws保持不变。提交语句变成了这样:“select money,online from users where userid1='aa' or 1=1 or '1'='1' and password='md5(bb)'”, 以往我们所见到的测试代码一般为“or 1=1”,而这里却多用了一个 or 。解释一下:在逻辑运算符中,and的优先级别高于or ,程序运行后会先运算后面的“'1'='1' and password='md5(bb)'”,因为密码是随便输入的,所以and后的password值为假,而and前的'1'='1'虽然为真,但真and假=假,所以这个and的运算值为假。再来看or运算,因为前面的用户名也是不存在的,其值当然为假。如此一来,Where后的逻辑运算就成了如下表达式:假or真or假,结果值还是为真,这样就会弹出“恢复成功”窗口。如果将其中的or 1=1 改为or 1=2,那逻辑表达式则成了:假or假or假,值当然也为假,弹出的则是“用户名或密码错误”的窗口。 我们根据弹出窗口的不同可以构造一些特殊字符,然后猜测出需要的数据。如查询管理员ID的语句,将or后的1=1更改为:“1=(Select top 1 id from admin)”,这里暂用admin表示管理员表名。如果存在ID为1的管理员,那么就会弹出“恢复成功”的窗口,如果不是则要用其它数字来测试了。猜出管理员ID后,我们还可以猜长度、名称。如此循环,最终就能获得管理员的用户名和密码。 上面提到的是Request.QueryString和Request.Form的注入方法,而使用Request.Cookies注入则需要要通过修改本地的Cookies值来实现。Cookies注入相对麻烦一些,但原理和前面的注入是一样的,这里不在赘述。 注入点的修补 攻守之间是对立互补的。明白了什么地方存在注入点,再来修补也就容易多了。每个程序对注入的过滤函数都不相同,我们在修补自已站点上的注入点时,可参照其它程序中的过滤函数,也可根据自已的需要,单独过滤一些敏感的字符。这里以上面的例子说明一下如何修补注入点。前面的SQL语句中有这一句:“userid='"&request("userid1")&"'”,这其中对提交来的参数是用单引号来引入的,我们加入一个replace()函数对单引号进行过滤,修改后的语句为:“userid='"&replace(request("userid1"),"'","")&"'”。以后用户再提交带有单引号的字符时,Replace()会将单引号过滤为空。如此一来,提交的特殊字符也就失去了意义。 当然,我们还可以在userid1进入SQL语句之前,对其长度进行一下判断。如果超过规定的长度,就弹出错误,中止页面执行并返回到指定的页面。总之注入漏洞是可以避免的,即使出现了注入点,只要我们能够明白它出现的原因,就能很容易地为其修补了!
|
|
| [
]
[返回上一页]
[打 印]
[收 藏] |
|
|
|
|
|
![]() |
|