'or'='or'经典漏洞代码分析

经典'or'='or'漏洞也叫身份验证登陆漏洞,这是一个比较老的漏洞,不过目前很多系统还是存在这样的漏洞。前面我们已经知道了利用'or'='or'这个漏洞我们就可以顺利的登陆网站后台,那么为什么输入这样的代码就可以进入后台呢?在讲这个漏洞之前我们先来回顾一点点数学知识。就是AND和OR运算符的运算规则,在第5章也讲了,不过为了给大家加深印象,这里还把他们的运算规则列出来。如果在一个关系式里,同时了AND和OR运算符,就会有一个优先级的问题,如果是相同的逻辑符,则按照从左到右的运算顺序。逻辑运算符AND和OR的运算优先次序是:先运算AND运算符在运算OR运算符。

AND运算符是对两个表达式进行逻辑“与”运算,他们的运算式子为:reslut=expression1 AND expression2。其中reslut为结果,expression1和expression2为任意表达式。表7-1就是AND的运算规则。

expression1的结果

expression2的结果

  AND运算之后的结果

    真

    真

    真

    真

    假

    假

    假

    真

    假

    假

    假

    假

                       表7-1  AND的运算规则

 OR运算符是对两个表达式进行逻辑“或”运算,他们的运算式子为:reslut=expression1 OR expression2。其中reslut为结果,expression1和expression2为任意表达式。表7-2就是OR的运算规则。

expression1的结果

expression2的结果

  OR运算之后的结果

    真

    真

    真

    真

    假

    真

    假

    真

    真

    假

    假

    假

                            表7-2  OR的运算规则

   前面我们说了,这个漏洞是发生在登陆口,只有登陆口才会出现这样的漏洞。下面就给大家讲解存在'or'='or'漏洞的后台登陆代码。

(1)、session

先来看第一种后台登陆程序,关键代码如下所示:

name=trim(request.Form("adminusername"))

//获得客户端输入的用户名,并过滤用户名两边的空格,并把值赋给name

pass=trim(request.Form("password"))

//获得客户端输入的密码,并过滤密码两边的空格,并把值赋给pass

 

set rs=server.createobject("adodb.recordset")

//利用server对象的createobject方法创建ADO组件的RecordSet(游标)对象

sql="select * from admin where name='"&name&"'and password='"&pass&"'"

//将用户名和密码放入查询语句中查询数据库,这里大家要注意的是在SQL语句//中的变量先是用一个单引号,再用一个双引号,最后用一对&包围上。

rs.open sql,conn,1,1

//利用RecordSet对象的方法执行我们前面编写的查询语句

if not rs.eof then 

//rs.eof表示当前的记录位置位于RecordSet对象的最后一个纪录之后,这里//的意思是相反,是位于最后一个记录之前,因为其前面有一个not

username=rs("name") 

//将RecordSet对象的name属性赋给username

session("lifeuser")=username

//将username赋给lifeuser的session自定义变量

session.Timeout=10

//设置session的超时时间为10分钟

rs.close

//关闭RecordSet对象

set rs=nothing

//释放RecordSet对象

conn.close

//关闭连接

set conn=nothing

//释放连接

response.redirect "index.asp?user="&username

//利用response对象的redirect方法重定向到"index.asp?user="&username

      上面我已经对每一条代码进行解释了,现在我来整理一下其完整思路:先是得到客户端输入的用户名和密码并过滤两边的空格,然后就查询数据库。如果查询的结果是位于最后一记录之前,那么就将RecordSet对象的name属性赋给username。同时设置session变量lifeuser的值为username,同时session的超时时间为10分钟,最后关闭及释放RecordSet对象和连接,并重定向到"index.asp?user="&username。

    上面的代码可以很好的完成我们的后台登陆,看上去好像没什么问题一样,但实际上确出现了很大的安全问题。问题就出在第一句和第二句中,他们的功能是获得客户端输入的用户名和密码并过滤他们两边的空格。注意了仅仅是过滤了两边的空格。这是在编程的时候一个非常大的安全缺陷,它并不会去检查我们输入的数据,也就是说不会检查我们输入的数据中到底是什么东西。如果我们输入了具有某些功能的代码呢?那么它也会不知道,那么就可以实现我们攻击的目的了。所以在编程的时候一定要对输入的参数进行有效的检查。

     因为上面只过滤了空格,所以我们现在的目的就是使sql="select * from admin where name='"&name&"'and password='"&pass&"'"这条语句执行为真,要达到这个目的就要用到我们的OR登陆,只要我们构造一个特殊的用户名,就可以绕过程序的验证,直接达到后台。之所以有OR登陆就是因为前面的用户名过滤不严格导致的。在上面的后台登陆代码中我们只要在用户名处输入1' or 1=1 or '1'='1(不含双引号,以下相同),密码处我输入123,其实随便输入什么符号都可以,点击登陆就进入后台了。

上面输入的数据达到我们服务器后就要执行SQL查询语句了,这个时候那条SQL查询语句就变成了:sql="select * from admin where name='1' or 1=1 or '1'='1'and password='123'"。

这个时候前面给大家讲的数学知识就派上用场了。现在我们把where后的字符用逻辑真假来表示,在逻辑表达中'1'是为假的;1=1肯定是正确的,所以为真;'1'='1'也是正确的,所以也为真;密码我们是随便输入的,这里我输入的是123,所以密码是错误的,即它为假,所以他们有了如下的关系:假or真or真and假。

根据前面的数学基础知识,大家不懂可以去查表。如果一个表达式中,同时了AND和OR运算符,就会有一个优先级的问题,如果是相同的逻辑符,则按照从左到右的运算顺序。逻辑运算符AND和OR的运算优先次序是:先运算AND运算符在运算OR运算符。所以我们要先运算AND运算符,“真and假”的运算结果我们可以通过查表得到为假,所以关系就变成了:假or真or假。现在就剩下了or运算符了,按照从左到右的原则。“假or真”的运算结果为真,所以现在就剩下了“真or假”,查表可以得到它的结果为真。

所以我们在用户名处输入'1' or 1=1 or '1'='1',密码输入任何字符之后,我们的SQL查询语句的结果为真了。至于后面的rs("name")则是因为找不到1' or 1=1 or '1'='1这个用户名,而自动转到数据库的最后一条记录,不过这个对我们的攻击并不会受到很大的影响。

因为上面用到了session,所以我们还可以用来进行session欺骗攻击。假设这个系统的管理员的用户名是admin,那么只需要在用户名处输入admin;密码处输入1' or '1'='1就可以达到session欺骗的目的了。当输入上面的代码后,在SQL查询语句中就变成了sql="select * from admin where name='admin'and password='1' or '1'='1'。因为在数据库中存在admin的用户,所以name='admin'为真;password='1'肯定是错误的了,所以为假;'1'='1'是正确的,所以为真。那么在where后的语句转换成逻辑表达式后为:真and假or真,通过查表可以知道他们的最后结果也是为真。

因为系统管理员的用户名是admin,所以rs("name")就等于admin,也就是username为admin。那么最后登陆后就会被重定向到index.asp?user=admin,这样我们就成功的进入了管理员的后台页面了。

(2)、cookie

前面我们讲的后台登陆是采用的session验证,在ASP中还有很多系统采用cookie来验证。下面来给大家一个采用cookie的后台登陆程序,代码如下所示:

<%set rs=server.createobject("adodb.recordset")

//利用server对象的createobject方法创建ADO组件的RecordSet(游标)对象

sql="select * from admin where admin='"&request.Form("username")&"'and pass='"&md5(trim(request.Form("password")))&"'"

//通过获得客户端输入的用户名和密码来构造查询语句

//其中密码经过了md5加密算法加密

rs.open sql,conn,3,1

// 执行查询的SQL语句

if rs.eof then

//如果当前的记录位置位于RecordSet对象的最后一个纪录之后,则

response.write "<script>alert('密码错误')</script>"

//弹出一个对话框,显示密码错误

response.write "<script>history.back(1)</script>"

//页面返回到前一页

else   //否则

response.cookies("admin")=rs("admin")

//将RecordSet对象的admin属性赋给cookie变量,实现cookie保存

response.cookies("pass")=rs("pass")

//和上面的功能一样

response.write "<script>location.href='step1.asp'</script>"

//跳转到step1.asp页面

end if

rs.close

set rs=nothing

conn.close

set conn=nothing

%>

通过上面的学习,大家应该就可以看到在SQL的查询语句中,存在经典的'or'='or'漏洞。在

sql="select * from admin where admin='"&request.Form("username")&"'and pass='"&md5(trim(request.Form("password")))&"'"中,用户名没有经过任何的过滤就进行查询了,而密码先经过过滤两边空格然后进行md5加密。和上面不同的是,因为这里的密码用了加密系统,所以我们的密码在数据库中都会被转换成密文,所以密码是无法利用的。不象上面一样,密码我们也输入攻击代码,这里确不可以,也就说这里只有用户名我们有利用价值,不过这已经足够了。

在用户名中我们输入or'='or,密码随便输入什么字符,那么where后的语句转换成逻辑语句后为:假or真or假and假,通过查表就可以得到结果为真。因为结果为真,所以系统会将admin和pass作为cookie保存起来,并跳转到step1.asp,这样我们就进入了后台。

(3)、总结

     不管系统的后台采用的是session还是cookie,它都要获得我们客户端输入的用户名和密码。如果系统没有对我们输入的用户名和密码进行全面的过滤,仅仅是过滤了两边的空格或者根本没有过滤任何字符,就进行我们的数据库查询。那么这个登陆页面就存在'or'='or'(身份验证)漏洞。要成功实现攻击这个漏洞要利用到or和and运算符,利用他们的组合使得SQL的查询语句执行之后的结果为真,那么这样就可以成功的进入后台。关键就是要使SQL查询语句的执行结果为真。

关于这个漏洞的修补很简单,因为不管怎么构造出的攻击代码都含有单引号,所以我们只要把单引号过滤就可以完全防御这个漏洞了。在过滤单引号的时候最好是把单引号转换成两个单引号,过滤代码如下所示:

name=Replace(trim(request.Form("adminname")),"'","''")

pass=Replace(trim(request.Form("password")),"'","''")

posted @ 2012-11-16 19:53  山貓  阅读(1276)  评论(0编辑  收藏  举报