SQL注入-UNION攻击
翻译
原文:https://portswigger.net/web-security/sql-injection/union-attacks
- name: 翻译
desc: 原文:https://portswigger.net/web-security/sql-injection/union-attacks
bgColor: '#F0DFB1'
textColor: 'green'
2
3
4
# SQL注入UNION攻击
当应用程序容易受到 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确定SQL注入UNION攻击所需的列数
在执行 SQL 注入 UNION 攻击时,有两种有效的方法可以确定从原始查询返回多少列。
第一种方法注入一系列ORDER BY
子句并增加指定的列索引,直到出现错误。
例如,假设注入点是原始查询的WHERE
子句中的一个带引号的字符串,你将提交:
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
...等
2
3
4
这一系列有效负载将修改原始查询,以根据结果集中的不同列对结果进行排序。
ORDER BY
子句中的列可以由它的索引指定,因此不需要知道任何列的名称。当指定的列索引超过结果集中实际列的数量时,数据库将返回一个错误,例如:
The ORDER BY position number 3 is out of range of the number of items in the select list.
(ORDER BY的编号 3 超出了所选列表中的项目数量范围。)
2
应用程序实际上可能在其 HTTP 响应中返回数据库错误,也可能返回一般错误,或者干脆不返回结果。如果可以检测到应用程序响应中的一些差异,就可以推断查询返回了多少列。
第二种方法提交一系列UNION SELECT
有效载荷,指定不同数量的空值:
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
...等
2
3
4
如果 null 的数量与列的数量不匹配,数据库将返回一个错误,例如:
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
(使用 UNION、INTERSECT 或 EXCEPT 运算符组合的所有查询,在其目标列表中必须具有相同数量的表达式。)
2
3
同样,应用程序可能实时返回此错误消息,也可能只返回一般错误或不返回结果。
当 null 数与列数匹配时,数据库将在结果集中返回另一行,其中每一列包含空值。
对 HTTP 响应结果的影响,取决于应用程序的代码。如果幸运的话,你将在响应中看到一些额外的内容,例如 HTML 表上的额外行。否则,空值可能会触发不同的错误,例如NullPointerException
。
在最坏的情况下,响应可能与由错误的 null 数引起的响应难以区分,从而使这种确定列计数的方法无效。
- name: 实验室-从业者
desc: SQL注入UNION攻击,确定查询返回的列数 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/sql-injection/union-attacks/lab-determine-number-of-columns
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
笔记
使用
NULL
作为注入的SELECT
查询返回值的原因是,每列中的数据类型必须在原始查询和注入的查询之间兼容。由于NULL
可以转换为每一种常用的数据类型,因此使用NULL
可以最大程度地提高有效负载在列计数正确时成功的机会。在 Oracle 数据库中,每个
SELECT
查询必须使用FROM
关键字指定一个有效的表。Oracle 上有一个内置的表叫做dual
,可以用于这个目的。因此在 Oracle 上注入的查询需要看起来像这样:
' UNION SELECT NULL FROM DUAL--
- 所描述的有效负载使用双破折号注释序列
--
在注入点之后注释掉原始查询的其余部分。在 MySQL 中,双破折号序列后面必须跟着一个空格。或者,可以用字符#
来标识注释。
有关于特定数据库的语法和详细信息,请参阅SQL注入备忘单 (opens new window)。
# 2在SQL注入UNION攻击中 查找具有有效数据类型的列
执行 SQL 注入 UNION 攻击的原因是,能够从注入的查询中检索结果。
通常,要检索的有趣数据将采用字符串形式,因此需要在原始查询结果中 找到数据类型为字符串数据 或 与字符串数据兼容的一个或多个列。
确定所需列数后,可以通过提交一系列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'--
2
3
4
如果列的数据类型与字符串数据不兼容,则注入的查询将导致数据库错误,例如:
Conversion failed when converting the varchar value 'a' to data type int.
(将 varchar 值 a 转换为数据类型 int 时转换失败。)
2
3
如果未发生错误,并且应用程序的响应包含一些其他内容(包括注入的字符串值),则相关列可以用于检索字符串数据。
- name: 实验室-从业者
desc: SQL注入UNION攻击,查找包含文本的列 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/sql-injection/union-attacks/lab-find-column-containing-text
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 3使用SQL注入UNION攻击 检索相关数据
确定原始查询返回的列数 并找到哪些列可以保存字符串数据后,就可以检索感兴趣的数据。
假设:
- 原始查询返回两列,这两列都可以保存字符串数据。
- 注入点是
WHERE
子句中的带引号的字符串。 - 数据库包含一个名为
users
的表,列名为username
和password
。
在这种情况下,你可以通过提交输入 来检索users
表的内容:
' UNION SELECT username, password FROM users--
当然,执行此攻击所需的关键信息是有一个名为 users
的表,其中包含两列,称为username
和password
。
如果没有此信息,你将只能尝试猜测表和列的名称。事实上,所有现代数据库都提供了检查数据库结构的方法,以确定它包含哪些表和列。
- name: 实验室-从业者
desc: SQL注入UNION攻击,从其他表中检索数据 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/sql-injection/union-attacks/lab-retrieve-data-from-other-tables
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 4在单个列中检索多个值
在前面的示例中,假设查询仅返回单个列。
通过将值连接在一起,你可以轻松地在单个列中检索多个值,最好包括合适的分隔符,以便区分组合的值。例如,在 Oracle 上,你可以提交输入:
' UNION SELECT username || '~' || password FROM users--
这里使用了双管道序列||
,它是 Oracle 上的字符串连接运算符。注入的查询将username
和password
字段的值连接在一起,用~
字符分隔。
查询的结果将允许你读取所有的用户名和密码,例如:
...
administrator~s3cure
wiener~peter
carlos~montoya
...
2
3
4
5
注意,不同的数据库使用不同的语法来执行字符串连接。有关更多详细信息,请参阅SQL注入备忘单 (opens new window)。
- name: 实验室-从业者
desc: SQL注入UNION攻击,在单个列中检索多个值 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/sql-injection/union-attacks/lab-retrieve-multiple-values-in-single-column
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6