Stacked Queries(堆叠注入)


[toc]

Stacked injection 汉语翻译过来后,国内有的称为堆查询注入,也有称之为堆叠注入。个人认为称之为堆叠注入更为准确。堆叠注入为攻击者提供了很多的攻击手段,通过添加一个新的查询或者终止查询( ; ),可以达到 修改数据 和 调用存储过程 的目的。这种技术在SQL注入中还是比较频繁的。

基本知识

原理介绍:

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下,我们在结束一个sql语句后继续构造下一条语句,会不会一起执行? 因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于 union 或者union all执行的语句类型是有限的,可以用来执行的是查询语句,而堆叠注入可以执行的是任意的语句。 例如以下这个例子。用户输入:1; DELETE FROM products;服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products;当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。

堆叠注入的局限性

堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到API或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。

img

PS:此图是从原文中截取过来的,因为我个人的测试环境是php+mysql,是可以执行的,此处对于mysql/php存在质疑。但个人估计原文作者可能与我的版本的不同的原因。虽然我们前面提到了堆叠查询可以执行任意的sql语句,但是这种注入方式并不是十分的完美的。在我们的Web系统中,因为代码通常只返回一个查询结果,因此,堆叠注入第二个语句产生的错误或者结果只能被忽略,我们在前端界面是无法看到返回结果的。因此,在读取数据时,我们建议使用union(联合)注入。同时在使用堆叠注入之前,我们也是需要知道一些数据库相关信息的,例如表名,列名等信息。

Mysql数据库实例介绍

Mysql数据库

(1)新建一个表 select * from users where id=1;create table test like users;

img

执行成功,我们再去看一下是否成功新建表。

img

(2)删除上面新建的test表select * from users where id=1;drop table test;

img

img

(3)查询数据select * from users where id=1;select 1,2,3;

img

(4)加载文件 select * from users where id=1;select load_file('c:/tmpupbbn.php'); //读文件

img

(5)修改数据 select * from users where id=1;insert into users(id,username,password) values('100','new','new');

img

img

CTF 实战与各种姿势

修改表名

使用条件:rename、alter没有被过滤

我们用[强网杯 2019]随便注这道题来进行演示。

1

可以看到查询页面返回了一些数据
输入1’ 发现报错,

在这里插入图片描述

可知后台为单引号过滤。然后1’ #显示正常,应该是存在sql注入了,且为单引号字符型

2

3

正常流程走起,order by

4

可以看到order by 2的时候是正常回显了,但order by 3就出错了,只有2个字段

这时候用union select进行联合查询试试

5

返回一个正则过滤规则,可以看到几乎所有常用的都被过滤了,这时候想到堆叠注入,试一下 show databases;

6

尝试一下堆叠注入,果然可以,把全部库名都给查出来了,可以看到成功了,存在堆叠注入。我们再直接 show tables; 来查询下,试下能不能查询出表:

7

可以看到当前连接的库下有两张表(1919810931114514和words),下面分别来看下两张表有什么字段:0'; show columns from words;#

8

发现words表中一共有id和data两列,那么可以猜测我们提交查询的窗口就是在这个表里查询数据的,那么查询语句很有可能是:select id,data from words where id =,如下:(2为输入的id,miaomiaomiao为回显的data字段)

在这里插入图片描述

再输入:

0'; show columns from `1919810931114514`;#

9

可以看到1919810931114514中有我们想要的flag字段,且只有这一列

现在常规方法基本就结束了,要想获得flag就必须来点骚姿势了(让表1919810931114514冒充表words)

因为这里有两张表,回显内容肯定是从word这张表中回显的,那我们怎么才能让它回显flag所在的表呢?

该题目的查询语句很有可能是:selsect id,data from words where id =,因为我们输入1,回显得是两个字段,这与words表符合,而1919810931114514表中只有一列。

这时候虽然有强大的正则过滤,但没有过滤alter和rename关键字,这时候我们就可以以下面的骚姿势进行注入:

因为可以堆叠查询,这时候就想到了一个改名的方法,把words随便改成words1,然后把1919810931114514改成words,再把列名flag改成id(或data),结合上面的1’ or 1=1#爆出表所有内容就可以查flag啦。

payload

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

rename命令用于修改表名。
rename命令格式:rename table 原表名 to 新表名;

上述命令不能分开执行,否则报错找不到某表名:

在这里插入图片描述

最后,再用一下一开始的操作 id=1' or 1=1#

img

如上图,得到flag。

利用HANDLER语句

使用条件:rename、alter也被过滤了。

我们用[GYCTF2020]Blacklist这道题来进行演示。

与强网杯2019随便注前面部分一样,只不过这道题rename、alter也被过滤了。

在这里插入图片描述

在这里插入图片描述

当前连接的库下有两个表——FlagHere、words,flag在FlagHere中,而此时后台数据库查询语句应为:

select id,data from words where id =

在这里插入图片描述

在不改名字的情况下怎么才能读取到FlagHere表中的内容呢?

这里还有一种新姿势,参考官方文档

HANDLER ... OPEN 语句打开一个表,使其可以使用后续 HANDLER ... READ 语句访问,该表对象未被其他会话共享,并且在会话调用 HANDLER ... CLOSE 或会话终止之前不会关闭,详情请见:https://www.cnblogs.com/taoyaostudy/p/13479367.html

所以我们的payload如下:

1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;#1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;#

如下图,得到flag:

在这里插入图片描述

利用MySql预处理语句

使用条件:HANDLER也被过滤了。

在遇到堆叠注入时,如果select、rename、alter和handler等语句都被过滤的话,我们可以用MySql预处理语句配合concat拼接来执行sql语句拿flag。

  1. PREPARE:准备一条SQL语句,并分配给这条SQL语句一个名字供之后调用
  2. EXECUTE:执行命令
  3. DEALLOCATE PREPARE:释放命令
  4. SET:用于设置变量

用法:

PREPARE stmt_name FROM preparable_stmt

EXECUTE stmt_name [USING @var_name [, @var_name] ...] 

{DEALLOCATE | DROP} PREPARE stmt_name

我们还是用[强网杯 2019]随便注这道题来进行演示,假设此题过滤了select、rename、alter和handler等sql语句,如果我们想要执行sql语句的话,我们还可以利用一下payload:

1';set @a=concat("sel","ect flag from `1919810931114514`");prepare hello from @a;execute hello;#

image-20201115195954234

好吧,我忘了“set”和“prepare”也被检测了,但没关系,这里只使用的strstr函数,该函数是区分大小写的,所以我们用大写即可绕过,如下:

1';sEt @a=concat("sel","ect flag from `1919810931114514`");PRepare hello from @a;execute hello;#

image-20201115200601407

如上图,sql语句执行成功,并得到flag。


Author: WHOAMI
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source WHOAMI !
评论
  TOC