[SUCTF 2019]EasySQL
[SUCTF 2019]EasySQL
题目来源:buuctf
题目类型:web
涉及考点:SQL注入、堆叠注入
1. 题目给了一个输入框,先随便传点东西进去
- 传入数字回显如下:
- 传入flag回显如下:
- 传入字符无回显
没什么其他线索了,还是爆破一下看看过滤了哪些字符:
返回长度为507的字符都是被过滤了的,包括union、sleep、extractvalue
,那么union注入、时间盲注、报错注入都用不了了,这时候想到可以试试堆叠注入
2. 尝试堆叠注入
- 爆库名:
1;show databases;
- 爆表名:
1;show tables;
感觉就在Flag表里了,但是 flag 又被过滤了
我们明确一下目标,现在我们需要查询 Flag 表中的 flag 字段
即:select flag from Flag
尝试了几个绕过方法无果,只能看看其他师傅的wp,发现这题需要猜测后端的查询语句
3. 猜测后端语句
后端查询语句如下:
select $_POST['query'] || flag from flag
下面说一下这样猜测的原因:(有点马后炮的意思)
首先在第一步我们知道,传入数字有回显,传入字符无回显,那么可以推测查询语句中有 或结构(||)
在或结构中,如果左右两边都是字符串,则会报错(当表中无相应列时),对应到本题就是传入字符无回显
例如,我们构造语句
select abc||flag from flag
,当表中没有abc列时,在数据库中会有报错如下:
Unknown column 'abc' in 'field list'
,这里只是举例说明了为什么可以猜测具有或结构其次是在做堆叠注入时我们已经知道具有表Flag,因此后续肯定是from Flag
4. 在知道后端语句的情况下,我们构造payload
法一:
比较简单的做法是,payload直接构造:
*,1
这样传入之后,后端语句就变成了:
select *,1 from flag
因为1||flag
相当于把flag
截断了
传入后得到flag:
法二:
第一次见到这种做法,涨知识了,利用了sql_mode,这里简单介绍一下:
sql_mode是一组语法校验规则,个人理解是它可以设定一些sql的语法规则,常见的几个sql_mode如下:
sql_mode的值 | 作用 |
---|---|
ONLY_FULL_GROUP_BY | 对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中 |
NO_ZERO_DATE | mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告 |
ERROR_FOR_DIVISION_BY_ZERO | 在insert或update过程中,如果数据被零除,则产生错误而非警告。如果未给出该模式,那么数据被零除时Mysql返回NULL |
PIPES_AS_CONCAT | 将 || 视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样是,也和字符串的拼接函数concat相类似 |
ANSI_QUOTES | 不能用双引号来引用字符串,因为它被解释为识别符 |
那么我们将sql_mode的值设为PIPES_AS_CONCAT时,后端查询语句就相当于:
select concat($_POST['query'],flag) from flag
那么构造payload如下:
1;set sql_mode=PIPES_AS_CONCAT;select 1
其中1可以换成任意数字
这个构造会使得后端语句变成这样:
select 1;
set sql_mode=PIPES_AS_CONCAT;
select concat(1,flag) from flag;
为了方便查看我将这段分为三行,实际上他们处在同一行,因为第一行的分号将语句分隔了,所以我们在第三行要补上一个select
同时需要注意,这里写concat只是方便理解,实际上它还是 1||flag,只是 || 这是并不是 或,而是用作字符串连接
最终得到flag:(将1去掉即可)
flag{adff8126-a76e-4af2-b59c-b48f1c728329}
日期:2023.7.19
作者:y0Zero