不知道各位有没有遇到过这样的功能,一个请求发送了好几个参数,但是不管你如何修改参数的值,他返回的都是一样的结果,而不会返回你构造的比如union的查询结果,这种时候该怎么办呢?
我们可以想办法让它的SQL语句报错,看看响应会不会有差异,但是只是这样似乎不能证明这里执行了你的 payload 啊,比如一个要求是整形的参数,你改了一个字符串 ‘x’,这它报错不是应该的吗。
所以我们需要让它是在语法正确的情况下报错,比如满足 1=1
的时候报错,不满足的时候不报错,这就需要用到我们下面的这个函数了
case when (1=1) then 1/0 else 'q' end
它的意思是:当 1=1 的时候计算 1/0 是多少,否则输出 ‘q’,由于 1/0 会导致数据库报错 ‘divide-by-zero’
对于 MySQL 5.7.8 之后的版本,可能不会报错,而是返回一个 NULL,具体取决于数据库的配置情况
那么当1=1的时候服务器响应报错,1=2的时候他又不报错了,是不是就说明服务器执行了我们的SQL语句,这个漏洞也就被发现啦!
开始
此靶场包含一个SQL盲注入漏洞。该应用程序使用跟踪cookie进行分析,并执行包含提交cookie值的SQL查询。
SQL查询的结果不会返回,应用程序也不会根据查询是否返回任何行而做出任何不同的响应。如果SQL查询导致错误,则应用程序将返回自定义错误消息。
该数据库包含一个名为users的不同表,其中的列名为username和password。您需要利用盲SQL注入漏洞来查找 administrator 用户的密码。
以 administrator 用户身份登录则通关。
注入点还是在 cookie 上,我们发现一个单引号报错 Internal Server Error 两个单引号正常返回信息,那说明这里是存在注入点的
联合注入失败
那我们先来测试一下联合注入的效果怎么样,这里由于已经给出了存放用户名密码的表明和列名,我们直接使用下面的 payload ' order by 1 --+
测出只有一列返回值,但是在使用 ' union select null --+
时系统报错了,虽然不太清楚后台是把 union select 加了黑名单还是怎么回事,但是联合查询肯定是没戏了
布尔盲注失败
那联合查询不行,布尔盲注呢,我们来试一下,可以看到 1=1 和 1=2 返回的数据长度都是一样的(5264),那么就无法根据响应的差异来判断条件是否成立,来盲注出账号密码了
报错型注入
我们在第一步已经通过单引号造成了它的语法报错从而导致服务器响应500,那么我们下一步就是要构造出一个正确的语法,来让我们可以有条件的重现报错,来遍历出它的 administrator 密码
首先我们来给它原有的查询语句的 where 条件拼接一个空字符,这样理论上讲是不会造成语法错误的,而且查询的结果也不会改变,返回的应该是和未修改时一样的数据,这里我们使用'||(select '')||'
进行测试
拼接后的语句可能是
select … from … where trackingId=‘glF5yaHU2Lm8ftmV’||(SELECT ‘’)||‘’
这个语句相当于 select … from … where trackingId=‘glF5yaHU2Lm8ftmV’
我们可以看到,它还是报错了,这是因为有的数据库在使用 select 的时候必须指明要查询的表,比如 Oracle 数据库,所以我们来修改一下payload '||(select '' from dual)||'
从上面可以确认这是一个 Oracle 数据库,那接下来我们就输入一个不存在的表,看看会不会报错
从上一步我们可以发现,在语法正确的时候,也是可以让服务报错的,那下面就看看有没有 users 这个表,这里有一个需要注意的点,在使用 子查询 时,其返回的结果必须只有一行,也就是说需要限定条件,payload '||(select '' from users where rownum = 1)||'
【补充】对于 Oracle 数据库,我们可以使用它的 ROWNUM 伪列来实现,你可以把他理解成一个 mysql 的id,但是它和id还不一样,Mysql的id是固定对应一条数据的,而 ROWNUM 是针对当前查询结果动态生成的,也就是说同一个 RUWNUM=1 是每次查询结果排序后的第1行数据,但这个数据并不一定处于数据库的第1行
所以可以肯定是存在 users 这个表的,那下一步就是试一下我们的 case when 语句能不能用,然后就爆破密码了,payload '||(select case when (1=1) then to_char(1/0) else '' end from dual)||'
然后就是判断 administrator 这个用户是否存在, payload '||(select case when (1=2) then to_char(1/0) else '' end from users where username = 'administrator')||'
存在 administrator 那么我们看看他是多少位的,这里我们直接用 Intruder 去跑,payload '||(select case when (length(password) = 1) then to_char(1/0) else '' end from users where username = 'administrator')||'
,这样的话哪个报错,就是几位
上一步既然爆破出了位数,那么下一步就是爆破密码了,让我们丰富一下 payload '||(select case when substr(password,1,1)='1' then to_char(1/0) else '' end from users where username = 'administrator')||'
等待爆破结束,密码也就出来了 (4c3ahujk9laxc1sknpi0),登录过关