sql2="select * from bbsuser where password='"&request("password")&"'"
set rs2=server.createobject("adodb.recordset")
rs2.open sql2, conn,1,1
response.write rs2.recordcount & "<br />"
%>
<%="执行的SQL语句是:"&sql2%>
<p>
执行后的数据库资料:
<p>
<%do while not rs2.eof%>
<%="id="&rs2.fields("id")%><br>
<%="username="&rs2.fields("username")%><br>
<%="password="&rs2.fields("password")%><br>
<%rs2.movenext%>
<BR>
<%loop%>
<%
rs2.close
set rs2=nothing
conn.close
set conn=nothing
%>
★
源码应当一看就懂,就是在图1所示的密码框内添入密码进行查盾,如果密码对了的话就是图2所示的样子了(我的数据库库名是bbs,表名是bbsuser,列名是id、username、password,都是varchar 类型的,列名值分别1、admin,12345,大家最好拿这两个源码试一下就是明白了)。
有的时候,你会发现像图1中那样你添入错误的密码后,抓包得到的链接是无法注入的,非得需要一个正确的值才可以,这时候只能手工来确定了。可以这样,用●' having 1=1--●确定了第一个表名和字段名,如图3、图4所示。
在图4中可以看到得到了表名是bbsuser,第一个列名是id。然后再用●' group by bbsuser.id having 1=1--●来确定出第二个列名是username,依次再用●' group by bbsuser.id,bbsuser.username having 1=1--●来确定第三个列名,依次类推,很快会推算出当前表中所有的列名。
写这个的主要原因是有两个,一个是像nbsi或hdis等工具都没有用到此语句,第二个是如果工具可以跑的话,当你一下跑出了100多个表和库的时候,你可以用此语句快速判断像后台的登陆密码在哪个表中。
类似的语句还有●' union select sum(id) from bbsuser--●这样的来确定列名的类型。
★
值得注意的是我在f.asp中用到的语句是●select * from bbsuser where password='"&request("password")&"'"●,所以我在每个注入语句中前边都写了个单引号,是为了打破sql语句中的引号限制,实际注入的时候,你可以去掉单引号,直接用注入语句来试一下。
★
三、巧妙union查循直接进后台
应当最有创意的地方就在这里了,我拿一个网站来做实地测试,然后再讲一下原理。网站页面如图5所示。我在email框内写入1'union select 1--的时候,密码我任意写,结果如图6所示。暴出路径是它网站做的设置不好,与注入语句关系不大;它的主要意思是说包含 union 运算符的 SQL 语句中的所有查询都必须在目标列表中具有相同数目的表达式。那么好,我就依个加1,当我试到'union select 1,1,1,1--的时候,密码我还是任意写,竟然直接进后台了,如图7所示。
为什么会是这样,我们回到e.asp和f.asp来做测试,我在图8所示内的文本框中添入了和前表名相等的1的个数(' union select 1,1,1--)后,可以看到图9所示的界面。图9中我们可以看到f.asp中语句中的●response.write rs2.recordcount●值是1,查循语句是●select * from bbsuser where password='' union select 1,1,1--'●,执行后得到的结果是●id=1、username=1、password=1●,是把union select 1,1,1中的1,1,1直接当作了数据库的一条记录了,所以我们通过了,进入后台了。当然这也要看源程序的具体写法了,像eof、end eof等的判断。