暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SQL注入之UNION攻击

WEB漏洞挖掘 2021-07-22
1665

当应用程序存在SQL注入漏洞并且在应用程序的响应中返回查询结果时,可以使用UNION关键字从数据库中的其他表中检索数据。这将导致SQL注入UNION攻击。

UNION关键字允许您执行一个或多个额外的SELECT查询,并将结果附加到原始查询。例如:

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

这个SQL查询将返回一个带有两个列的结果集,其中包含table1中的列a和b以及table2中的列c和d的值。

要成功执行UNION查询,必须满足两个关键需求:

  • 多表查询返回列的数量必须相同。

  • 多表查询对应的每个列的数据类型必须一致。

要执行SQL注入UNION攻击,需要确保满足这两个要求。这通常需要考虑:

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

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

1. 确定UNION攻击中所需的列数

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

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

' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--

等等

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

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

应用程序可能在其HTTP响应中实际返回数据库错误,或者可能返回一个通用错误,或者只是不返回任何结果。如果您可以检测到应用程序响应中的一些差异,您就可以推断出从查询中返回了多少列。

第二种方法是提交一系列的UNION SELECT payload,指定不同数量的null值:

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

等等

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

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

同样,应用程序可能实际返回此错误消息,或者可能只返回一个通用错误或没有结果。当空值的数量与列的数量匹配时,数据库将在结果集中返回一个额外的行,每个列中包含空值。对HTTP响应的影响取决于应用程序的代码。如果幸运的话,您将在响应中看到一些额外的内容,比如HTML表上的额外一行。否则,空值可能会触发不同的错误,例如NullPointerException。最坏的情况是,正常响应可能与不正确的空值数量导致的响应难以区分,这使得这种确定列数的方法无效。

  • 使用NULL作为注入SELECT查询返回值的原因是,每个列中的数据类型必须在原始查询和注入查询之间兼容。由于NULL可以转换为每一种常用的数据类型,所以当列的数量正确时,使用NULL最大程度地提高了payload成功的机会。

  • 在Oracle上,每个SELECT查询都必须使用FROM关键字并指定一个有效的表。Oracle上有一个内置的表dual,可以用于此目的。所以在Oracle上注入的查询应该是这样的:

    ' UNION SELECT NULL FROM DUAL--

  • payload使用双破折号 -- 注释掉原始查询注入点之后的其余部分。在MySQL中,双破折号后面必须有一个空格。或者,可以使用字符#来注释。     

2. 在UNION攻击中查找具有有用数据类型的列

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

在确定了所需列的数量之后,可以通过提交一系列UNION SELECT payload 依次将字符串值放入每个列来探测每个列,以测试它是否支持字符串数据。例如,如果查询返回4列,您将提交:

' 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.

如果没有发生错误,并且应用程序的响应包含一些附加内容,包括注入的字符串值,那么相关列适合于检索字符串数据。     

3. 使用UNION攻击检索感兴趣的数据

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

假如:

  • 原始查询返回两个列,这两个列都支持字符串数据。

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

  • 数据库包含一个名为users的表,列是用户名和密码。

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

 ' UNION SELECT username, password FROM users--

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

4. 在单个列中检索多个值

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

通过将多个值连接在一起,可以很容易地在单个列中检索多个值,理想情况下可以包含适当的分隔符来区分组合的值。例如,在Oracle上你可以提交输入:

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

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

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

...            
administrator~s3cure            
wiener~peter            
carlos~montoya            
...        

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


文章转载自WEB漏洞挖掘,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论