网站后台验证相当重要,特别是一些网站后台权限很大的网站。如果你拿到一个网站的后台管理员帐号,基本上已经拿下这个网站,然后通过上传木马什么的拿到服务器权限。
一提到绕过后台登陆验证直接进入网站后台管理系统,想必大家都能想到经典的万能密码:or=or吧。
or=or原理
我们都知道后台登陆验证一般的方式都是 将用户在登录口输入的账号密码拿去与数据库中的记录做验证,并且要求输入的账号密码要等于数据库中某条记录的账号密码,验证通过则程序就会给用户一个 sssion,然后进入后台,否则就返回到登陆口。而对于or=or漏洞,我们先来看以下代码:
<% pwd = request.form("pwd") '获取用户输入的密码,再把值赋给pwd name = request.form("name") '获取用户输入的用户名再把值赋给name '都没有进行任何过滤 Set rs = Server.CreateObject("ADODB.Connection") sql = "select * from Manage_User where UserName=" & name & " And PassWord="&encrypt(pwd)&"" '将用户名和密码放入查询语句中查询数据库, Set rs = conn.Execute(sql) '执行SQL语句,执行后并得到rs对象结果,“真”或“假” If Not rs.EOF = True Then '如果是真则执行以下代码 Session("Name") = rs("UserName") '将UserName的属性赋给Name的Session自定义变量 Session("pwd") = rs("PassWord") '将PassWord的属性赋给pwd的Session自定义变量 Response.Redirect("Manage.asp")'利用Response对象的Redirect方法重定向Manage.asp Else '否则执行以下代码 Response.Redirect "Loginsb.asp?msg=您输入了错误的帐号或口令,请再次输入!" End If %>
针对以上例子我们只需要在用户名处提交or=or,这样就使得SQL语句变成:select * from Manage_User where UserName=’or‘=or And PassWord=123456。执行后得到rs对象的结果为真,这样就能顺利的进入后台了。
现在的目的就是使
sql = "select * from Manage_User where UserName=" & name & " And PassWord="&encrypt(pwd)&""
这条语句执行为真,要达到这个目的就要用到我们的OR登陆,只要我们构造一个特殊的用户名,就可以绕过程序的验证,直接达到后台。之所以有OR登陆就是因为前面的用户名过滤不严格导致的。在上面的后台登陆代码中我们只要在用户名处输入1′ or 1=1 or ‘1′=’1,密码处我输入123,其实随便输入什么符号都可以,点击登陆就进入后台了。
上面输入的数据达到我们服务器后就要执行SQL查询语句了,这个时候那条SQL查询语句就变成了:sql = "select * from Manage_User where UserName=‘" 1′ or 1=1 or ‘1′=’1′and password=’123′”。
注意,第一个单引号是为了跟UserName='后的单引号闭合从而构造OR运算,这样跟name配对的单引号还需一个单引号才能闭合,所以有了'1'='1。这就相当于将name=''变成了name=' 1'or'1'='1 '。
所以我们在用户名处输入’1′ or 1=1 or ‘1′=’1′,密码输入任何字符之后,我们的SQL查询语句的结果为真了。
SQL注入防范方法
为了避免出现这个漏洞,现在基本上的后台验证都不会使用这类方式,而是取得用户输入的账号和密码,在SQL中先将用户名与数据库中的记录做对比,若 数据库中某条记录的用户名等于用户输入的用户名,则取出该条记录中的密码,然后再与用户输入的密码对比,正确就通过,不正确就返回。例如:
<% pwd = request.form("pwd") 获取用户输入的密码,再把值赋给pwd name = request.form("name") 获取用户输入的用户名再把值赋给name 都没有进行任何过滤 Set rs = Server.CreateObject("ADODB.Connection") sql = "select * from Manage_User where UserName=" & name & "" 将用户名和密码放入查询语句中查询数据库, Set rs = conn.Execute(sql) 执行SQL语句,执行后并得到rs对象结果,“真”或“假” If Not rs.EOF = True Then 如果是真则执行以下代码 password=rs("password") 取得密码数据 if password=md5(pwd) then Session("Name") = rs("UserName") 将UserName的属性赋给Name的Session自定义变量 Session("pwd") = rs("PassWord") 将PassWord的属性赋给pwd的Session自定义变量 Response.Redirect("Manage.asp")了 利用Response对象的Redirect方法重定向Manage.asp else response.write "密码错误!!!!" end if Else 否则执行以下代码 Response.Redirect "Loginsb.asp?msg=您输入了错误的帐号或口令,请再次输入!" End If %>
通过以上例子可知道,密码的验证不再是直接在SQL语句中做验证了,而是根据用户名,取出对应的密码,然后再与用户输入的做对比。这样一来就造成了 我们不能使用or=or绕过了。有的朋友在这里可能有疑问了,若我们提交or=or那么SQL语句就变成:
select * from Manage_User where UserName=or=or,
这样一来得到的结果也应该是真啊,为什么就不能绕过呢?
其实就算SQL查询的地方得到的值是真,可别忘了后面还有密码的验证,若我们提交以上SQL,得到账号是真的,那么后面根据账号去数据库中取出来的密码与用户提交的密码是绝对通不过的。
好了,对于or=or漏洞的分析先就暂且说到这里,以上的均为我个人对该漏洞的理解,并不代表就是完全正确的,若有不当的地方还望大家多多指教。