MYSQL注入一些偏门技巧

刷leetcode的时候数据库部分有些题用到了join,想起前段时间PH师傅在小密圈出的题目,几位大佬给出的解答也是用了join,以及无聊看实验吧题目的时候重新看到的with rollup 的bypass方法,于是想重新梳理一下这一类稍微有点偏门的技巧,虽然实战不一定有用,但是最近槽心事太多了还是静下心做点事把,也有很久没有更新博客了,这篇文章可能会持续更新。

GROUP BY WITH ROLLUP

这个方法最早是在13年的一个CTF题目上看到的,现在已经变成了一个比较基础的用法。要真正理解这个方法,需要理解with rollup的原理

常规的用法是

让查询出的增加一条a为NULL的行。

主要被用来bypass类似下面这个验证:

先验证查询结果行数是否唯一,再验证查询所得密码是否相同。

可以知道

会产生一个password为NULL的行,用limit把它取出来就行,然后传入一个空的password会使得NULL == NULL绕过验证。

上面那条语句需要知道一个username的名字,如果不知道的话怎么办,可以用 username=” or 1=1 绕过,如果 or 被过滤了怎么办,可以用 username=”=0 来绕过。

<=>

还是上面那道题,如果逗号被过滤无法用 limit n,1 可以用 limit 1 offset 1绕过,那更严格的,limit被过滤应该怎么办?要知道的是,要想通过with rollup返回一个含有Null的行,必须要查询成功,也就是说查询出的结果至少含有两行,而我们需要把password=null的那一行挑出来。为了知道我们能干什么,需要理解SELECT的语法:

我们当前的语句处于GROUP BY位置,而他的下一条可以使用的语句是HAVING,能不能通过构造HAVING语句找到我们password=null的那一行,当然是可以的。HAVING语句生效的原因是where_condition为true,如果直接使用HAVING password=null的话不会生效因为mysql中 null = null 会返回 null,万幸的是mysql还有一个比较操作符 <=>,当 null <=> null 的时候会返回1,于是可以构造类似下面的语句:

这样就可以只查询出password = null的那一行从而bypass验证。

 JOIN

mysql中JOIN有三种语法,分别是LEFT JOIN, RIGHT JOIN以及INNER JOIN(JOIN),在SQL注入中的作用主要是构造查询,比如以前ph师傅的那道题:

在直接打印出错误的情况下,报错注入是最优先的方法,各位表哥都是用了join的方法来构造查询,类似于:

这个方法主要是使用了UPDATE的跨表更新,官方手册下的评论有一个例子:

其中TABLE_2处可以引入一个子查询从而达到报错注入的目的。

如果没有错误回显的话,时间盲注也是可以的,例如:

GROUP_CONCAT

其实这不能算是一个偏门技巧,因为其实使用的还是挺多的,GROUP_CONCAT主要用来代替注入中LIMIT被过滤的情况,LIMIT 0,1特征明显,一个关键字一个空格一个逗号都是容易被过滤掉的东西。相比而言GROUP_CONCAT则不那么容易被误伤,并且操作简单比较适合懒人。