什么是SQL注入(SQLi)
SQL注入(SQLi)是一种网络安全漏洞,允许攻击者干扰应用程序对其数据库的查询。这可能让攻击者查看他们通常无法检索的数据。
这可能包括属于其他用户的数据,或应用程序可以访问的其他任何数据。在许多情况下,攻击者可以修改或删除这些数据,导致应用程序内容或行为持续发生变化。
在某些情况下,攻击者可以升级SQL注入攻击,攻破底层服务器或其他后端基础设施。它还能使他们能够实施拒绝服务攻击。
如何检测SQL注入漏洞
可以手动检测SQL注入,方法是对应用中的每个入口点进行系统化测试。为此,通常需要提交:
- 使用单引号字符 ,寻找错误或其他异常。
' - 一些SQL专用语法,可以根据入口点的基础(原始)值和不同的值进行评估,并观察应用响应中的系统差异。
- 布尔条件 如 AND ,并观察应用响应的差异。
OR 1=1``OR 1=2 - 这些有效载荷设计用于在SQL查询中执行时触发时间延迟,并寻找响应时间的差异。
另外,也可以使用Burp Scanner快速且可靠地发现大多数SQL注入漏洞。
在查询的不同部分注入SQL的应用
大多数SQL注入漏洞都发生在查询的从句内。大多数有经验的测试人员都熟悉这种SQL注入方式。WHERE ``SELECT
然而,SQL 注入漏洞可能出现在查询的任何位置,且存在于不同的查询类型中。SQL注入出现的其他常见地点包括:
- 在语句中,在更新后的值或子句中。
UPDATE ``WHERE - 在语句中,插入的值内。
INSERT - 在语句中,在表或列名中。
SELECT - 在声明中,在条款内。
SELECT ``ORDER BY
检索隐藏数据
想象一个购物应用,展示不同类别的产品。当用户点击**"礼物**"类别时,浏览器会请求以下链接:
https://insecure-website.com/products?category=Gifts
这会导致应用程序进行SQL查询,从数据库中检索相关产品的详细信息:
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
该SQL查询要求数据库返回:
- all details (
*) - from the table
products - where the is
category``Gifts - and is .
released``1
这一限制被用来隐藏未发布的产品。我们可以假设对于未发布的产品,。
released = 1 已发布(用户能看到)
released = 0
注入:
该应用没有实现任何针对SQL注入攻击的防御措施。这意味着攻击者可以构造以下攻击,例如:
https://insecure-website.com/products?category=Gifts'--
这会得到以下SQL查询:
SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1
关键是 -- 。这意味着查询的其余部分被解读为注释,实际上是删除了它。
在这个例子中,所有产品都会被展示,包括尚未发布的产品。
--``AND released = 1
可以使用类似的攻击,让应用程序显示任何类别的所有产品,包括他们不知道的类别:
https://insecure-website.com/products?category=Gifts'+OR+1=1--
这会得到以下SQL查询:
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1
修改后的查询返回所有元素,其中是逻辑或 。一如既往,查询返回所有项目
警告
在将条件注入SQL查询时务必小心。即使在注入的上下文中看似无害,应用程序也常会将单个请求的数据用于多个不同查询。例如,若你的条件涉及或逻辑,可能导致意外数据丢失。例如:OR 1=1 UPDATE DELET
颠覆应用逻辑
想象一个应用程序,允许用户用用户名和密码登录。如果用户提交用户名和密码,应用程序通过执行以下SQL查询来检查凭证:wiener ``bluecheese
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
如果查询返回了用户的详细信息,则登录成功。否则,它将被拒绝。
在这种情况下,攻击者可以以任何用户身份登录,无需密码。他们可以通过SQL注释序列来移除查询从句中的密码检查。例如,提交用户名和空密码会得到以下查询:WHERE ``administrator'--
SELECT * FROM users WHERE username = 'administrator'--' AND password = ''
该查询返回了该用户,并成功将攻击者登录为该用户。username ``administrator
SQL 注入 UNION 攻击
当应用对SQL注入存在漏洞,且查询结果通过应用程序响应返回时 ,可以使用该关键词从数据库内的其他表中检索数据。这通常被称为SQL注入UNION攻击。UNION
该关键词允许执行一个或多个额外查询,并将结果附加到原始查询中 。例如:UNION ``SELECT
SELECT a, b FROM table1 UNION SELECT c, d FROM table2
该SQL查询返回一个包含两列的单一结果集,包含来自列和的值,以及列和在。a ``b ``table1 ``c ``d ``table2
查询要正常工作,必须满足两个关键要求 :UNION
- 各个查询必须返回相同的列数。
- 每列的数据类型必须在各个查询之间兼容。
要实施SQL注入UNION攻击,确保攻击满足这两个要求。这通常包括了解:
- 原始查询返回了多少列。
- 原始查询返回的列属于适合存放注入查询结果的数据类型。
确定所需列数
当执行SQL注入UNION攻击时,有两种有效的方法可以确定原始查询返回了多少列。
一种方法是注入一系列子句,并递增指定的列索引直到出现错误 。例如,如果注入点是原始查询子句中的引号字符串,你将提交:ORDER BY``WHERE
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
这一系列有效载荷修改了原始查询,使结果按结果集的不同列排序。子句中的列可以通过其索引指定,因此不需要知道任何列的名称。当指定的列索引超过结果集中的实际列数时,数据库会返回错误, 例如:ORDER BY
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--
如果空值的数量与列数不匹配,数据库会返回错误,例如:
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
我们使用从注入查询返回的值,因为每列中的数据类型必须在原始查询和注入查询之间兼容 。可以转换为每种常见的数据类型,因此当列计数正确时,它最大限度地提高了有效载荷成功的机会。NULL ``SELECT ``NULL
与该技术一样,应用程序可能在 HTTP 响应中返回数据库错误,但也可能返回通用错误,或干脆不返回任何结果。当空值数量与列数相匹配时,数据库会返回结果集中的额外行,每列包含空值。HTTP 响应的影响取决于应用程序的代码。
如果幸运的话,会在回复中看到一些额外内容,比如HTML表格上的一行额外内容。否则,空值可能会触发不同的错误,比如 。在最坏的情况下,响应可能与由于零点数错误引起的反应相同。这会使这种方法无效。ORDER BY ``NullPointerException
在Oracle上,每个查询都必须使用关键字并指定一个有效表。Oracle上有一个名为的内置表可用于此目的。因此,Oracle上注入的查询需要看起来像:SELECT FROM dual
Oracle 的 SELECT 不能没有 FROM,所以它提供了一个叫 dual 的内置表,专门用来"凑数"。
' UNION SELECT NULL FROM DUAL--
在某些情况下,查询可能只返回一列。
可以通过将多个值串接在一起,在这一列内检索多个值。可以添加分隔符来区分合并后的值。例如,在Oracle上你可以提交以下输入:
' UNION SELECT username || '~' || password FROM users--
这使用双管序列,它是Oracle上的字符串连接运算符。注入的查询将和字段的值连接在一起,用字符分隔
在SQL注入攻击中检查数据库
要利用SQL注入漏洞,通常需要查找数据库信息。这包括:
- 数据库软件的类型和版本。
- 数据库中包含的表和列。
|------------------|---------------------------|
| Database type | Query |
| Microsoft, MySQL | SELECT @@version |
| Oracle | SELECT * FROM v$version |
| PostgreSQL | SELECT version() |
盲注
当应用程序易受SQL注入攻击,但其HTTP响应不包含相关SQL查询的结果或任何数据库错误的详细信息时,就会发生盲SQL注入。
许多技术(如攻击)对盲SQL注入漏洞无效。这是因为它们依赖于能够在应用程序的响应中看到注入查询的结果。仍然有可能利用盲SQL注入来访问未经授权的数据,但必须使用不同的技术。
考虑一个使用跟踪Cookie收集使用数据分析的应用。对应用程序的请求包含如下的 cookie 头:
Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4
当处理包含 cookie 的请求时,应用程序会使用 SQL 查询来确定该用户是否为已知用户:TrackingId
SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'
该查询存在SQL注入的漏洞,但查询结果不会返回给用户。然而,应用程序的行为会根据查询是否返回数据而有所不同。如果你提交已识别的 ,查询会返回数据,回复中会显示"欢迎回来"的消息。TrackingId
这种行为足以利用盲目SQL注入漏洞。你可以通过根据注入的条件触发不同响应来获取信息。
假设发送了两个请求,依次包含以下 cookie 值:TrackingId
...xyz' AND '1'='1 ...xyz' AND '1'='2
- 第一个值会导致查询返回结果,因为注入条件为真。因此,会显示"欢迎回来"信息。
AND '1'='1 - 第二个值会导致查询不返回任何结果,因为注入的条件为假。"欢迎回来"的信息并不是 显示。

为假是存在差异,即盲注
