SQL injection : UNION attacks

当应用程序易受SQL注入攻击并且查询结果在应用程序的响应中返回时,可以使用UNION关键字从数据库中的其他表检索数据。这将导致SQL注入联合攻击。
UNION关键字允许您执行一个或多个附加的SELECT查询,并将结果附加到原始查询。例如:

SELECT a, b FROM table1 UNION SELECT c, d FROM table2 

此SQL查询将返回一个包含两列的结果集,其中包含table_1中a列和b列以及table_2中c列和d列的值。

要使联合查询正常工作,必须满足两个关键要求:

  • 各个查询必须返回相同数量的列。

  • 每列中的数据类型必须在各个查询之间兼容。

要执行SQL注入联合攻击,您需要确保您的攻击满足这两个要求。这通常包括计算:

  • 从原始查询返回多少列?

  • 从原始查询返回的哪些列具有合适的数据类型,以保存注入查询的结果?

Determining the number of columns required in an SQL injection UNION attack 确定SQL注入联合攻击中所需的列数

在执行SQL注入联合攻击时,有两种有效的方法可以确定从原始查询返回多少列。

第一种方法涉及注入一系列ORDER BY子句并递增指定的列索引,直到出现错误。例如,假设注入点是原始查询WHERE子句中的带引号的字符串,您将提交;

' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
etc. 

这一系列payloads修改原始查询,以按结果集中的不同列对结果进行排序。ORDERBY子句中的列可以由其索引指定,因此您不需要知道任何列的名称。当指定的列索引超过结果集中的实际列数时,数据库将返回错误,例如:

The ORDER BY position number 3 is out of range of the number of items in the select list. 

应用程序可能在其HTTP响应中实际返回数据库错误,也可能返回一般错误,或者干脆不返回任何结果。如果可以检测到应用程序响应中的某些差异,则可以推断查询返回了多少列。

第二种方法涉及提交一系列UNION SELECT有效负载,指定不同数量的空值:

' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
etc. 

如果空值的数量与列的数量不匹配,数据库将返回一个错误,例如:

All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists. 

同样,应用程序可能实际返回此错误消息,也可能只返回一般错误或无结果。当空值的数量与列的数量匹配时,数据库将在结果集中返回另一行,每列中包含空值。对结果HTTP响应的影响取决于应用程序的代码。如果幸运的话,您将在响应中看到一些额外的内容,例如HTML表上的额外一行。否则,null值可能会触发不同的错误,例如NullPointerException。
在最坏的情况下,响应可能无法与由不正确的null数引起的响应区分开来,这使得此确定列计数的方法无效。

使用NULL作为插入的SELECT查询返回的值的原因是,每列中的数据类型必须在原始查询和插入的查询之间兼容。由于NULL可转换为所有常用的数据类型,因此在列计数正确时,使用NULL可最大限度地提高有效负载成功的可能性。
在Oracle上,每个SELECT查询都必须使用FROM关键字并指定有效的表。Oracle上有一个名为dual的内置表,可用于此目的。因此,Oracle上的注入查询需要如下所示:“UNION SELECT NULL FROM DUAL–”。
所描述的有payloads使用双破折号注释序列–注释掉注入点之后原始查询的其余部分。在MySQL上,双破折号序列后面必须跟一个空格。或者,可以使用散列字符#来标识注释。

Finding columns with a useful data type in an SQL injection UNION attack在SQL注入联合攻击中查找具有有用数据类型的列

执行SQL注入联合攻击的原因是能够从注入的查询中检索结果。通常,您要检索的感兴趣的数据是字符串形式的,因此您需要在原始查询结果中找到一个或多个列,这些列的数据类型是或与字符串数据兼容。

在已经确定了所需列的数量之后,您可以通过提交一系列UNION SELECT有效负载(依次将字符串值放入每列)来探测每一列,以测试它是否可以保存字符串数据。例如,如果查询返回四列,您将提交:

' UNION SELECT 'a',NULL,NULL,NULL--
' UNION SELECT NULL,'a',NULL,NULL--
' UNION SELECT NULL,NULL,'a',NULL--
' UNION SELECT NULL,NULL,NULL,'a'-- 

如果列的数据类型与字符串数据不兼容,则插入的查询将导致数据库错误,例如:

Conversion failed when converting the varchar value 'a' to data type int. 

如果没有发生错误,并且应用程序的响应包含一些附加内容(包括注入的字符串值),则相关列适合检索字符串数据。
比如:
在这里插入图片描述

Using an SQL injection UNION attack to retrieve interesting data 返回特殊值

确定原始查询返回的列数并找到哪些列可以保存字符串数据后,就可以检索感兴趣的数据了。

假设:

  • 原始查询返回两列,这两列都可以保存字符串数据。

  • 注入点是WHERE子句中带引号的字符串。

  • 数据库包含一个名为users的表,其中包含username和password列。

  • 在这种情况下,您可以通过提交输入来检索users表的内容:

  • '从用户中选择用户名、密码–

当然,执行此攻击所需的关键信息是有一个名为users的表,其中有两列名为username和password。如果没有这些信息,您将不得不猜测表和列的名称。事实上,所有现代数据库都提供了检查数据库结构的方法,以确定它包含哪些表和列。
比如:输入

' union select%20 username,password from users --++

或许就能返回出特别的东西
在这里插入图片描述

Retrieving multiple values within a single column 在单个列中检索多个值

在前面的示例中,假设查询只返回单个列

通过将多个值串联在一起,可以轻松地在单个列中检索多个值,理想情况下,可以使用合适的分隔符来区分组合值。例如,在Oracle上,您可以提交输入:

' UNION SELECT username || '~' || password FROM users-- 

这使用了双管道序列| |,它是Oracle上的字符串连接运算符。注入的查询将用户名和密码字段的值连接在一起,用~字符分隔。

查询结果将允许您读取所有用户名和密码,例如:

administrator~s3cure
wiener~peter
carlos~montoya

请注意,不同的数据库使用不同的语法来执行字符串连接。
例如
如果:

'union select null,null --+

前面的null和后面的null数据类型不一样,就不能分别回显username和password。
如此方法:

' union select 1,username||'~'||password from users --+

就可以回显出账号密码:
在这里插入图片描述

posted @ 2021-08-17 11:30  Zeker62  阅读(218)  评论(0编辑  收藏  举报