[SUCTF 2019]EasySQL

发布时间 2023-07-19 19:53:23作者: y0Zero

[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