Files
reverse-skills-max/reverse-skill-repo/skills/field-journal/2026-05-16_pentest-personalblog-fun-mass-assignment.md

131 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: pentest-personalblog-fun-mass-assignment
description: {target_domain} Spring Boot 博客系统渗透测试——通过 Swagger 泄露 + Mass Assignment 提权至管理员,JS静态分析补充攻击面
metadata:
type: project
---
# {target_domain} 渗透测试记录
**日期**: 2026-05-16
**目标**: https://www.{target_domain}/
**关键词**: Spring Boot, MyBatis-Plus, SaToken, Mass Assignment, Swagger泄露, 权限提升, Vue 3, JS静态分析, 前端路由绕过, DTO缺失
## 背景
黑盒渗透测试一个基于 Spring Boot 的个人博客系统,目标是进入后台管理页面。
## 攻击路径
1. **信息收集**: 识别 Vue SPA → 提取 JS 中的 API 端点 → 发现 `/api/v3/api-docs`(Swagger 未授权访问)
2. **API 文档分析**: 获得完整端点定义、数据模型、管理员接口
3. **用户枚举**: 文章列表接口暴露 admin 用户信息(id=1,email={admin_email})
4. **公告提示漏洞存在**: 公告 #14 标注"网站普通用户可被提权管理员"
5. **注册**: 通过 mail.tm 临时邮箱接收验证码注册普通用户
6. **Mass Assignment 提权**: `PUT /api/user/profile` 传入 `"role":"admin"` 将 role 从 reader 提升为 admin
## JS 静态分析补充发现
IP 被限速后通过前端 JS bundle 做静态分析,提取了完整的 API 端点列表:
| 来源 | 发现 |
|------|------|
| `user-n8GFLR5I.js` | 全部 16 个用户/认证端点的完整参数定义 |
| `article-manage-BUHBK4I3.js` | 全部 8 个文章端点的操作(CRUD + 发布/草稿/列表) |
| `upload-C3Isuhzt.js` | 文件上传逻辑(avatar + cover),使用 FormData/multipart |
| `Login-BfQvQsk0.js` | 登录/注册完整流程,含邮箱验证码登录 |
| `index-F3rwNCiG.js` | axios 实例配置(baseURL: /api, satoken header) |
### 前端路由保护发现
Vue Router 定义中管理端路由带 `requiresAdmin: true` 标志,但**仅在前端判断**:
```javascript
{ path: "/user-manage", name: "UserManage", ..., meta: { requiresAdmin: true } },
{ path: "/category-manage", name: "CategoryManage", ..., meta: { requiresAdmin: true } },
```
后端 API 虽然有 SaToken 鉴权,但管理端 GET 接口(如 article/all)缺少认证检查。
### 完整 API 端点清单
**用户/Auth**(user-n8GFLR5I.js):
- `POST /user/login` — 用户名密码登录
- `POST /user/register` — 注册
- `GET /user/info` — 当前用户信息
- `PUT /user/profile` — 更新资料(Mass Assignment!)
- `PUT /user/password` — 修改密码
- `POST /user/logout` — 登出
- `POST /auth/send-code` — 发验证码
- `POST /auth/verify-email-code` — 校验验证码
- `POST /user/login-by-email` — 邮箱验证码登录
- `GET /user/check-username` / `check-email` / `check-exists` — 检查接口
- `PUT /user/{id}/status` — 管理员禁用用户
- `GET /user/{id}` — 管理员查用户详情
- `GET /user/list` — 管理员用户列表
**文章**(article-manage-BUHBK4I3.js):
- `POST /article` — 创建文章
- `PUT /article/{id}` — 更新文章
- `DELETE /article/{id}` — 删除文章
- `GET /article/{id}` — 查文章详情
- `GET /article/drafts` — 我的草稿
- `GET /article/my` — 我的文章
- `GET /article/all` — 所有文章(管理端)
- `POST /article/{id}/publish` — 发布文章
### 已验证安全的攻击面
| 测试项 | 结论 |
|-------|------|
| 密码修改需旧密码 | PUT /user/password 需要旧密码认证 |
| 邮箱验证码一次性 | 验证码消费后不可重用 |
| 前端无 API Key/Secret 硬编码 | bundle 中无敏感凭证 |
| SaToken UUIDv4 不可伪造 | UUID 随机性足够 |
| nginx 正确拦截 Method Override | HTTP 动词篡改被 405 拒绝 |
## 关键发现
| 发现 | 说明 |
|------|------|
| Swagger 生产环境未关闭 | `/api/v3/api-docs` + Knife4j + Swagger UI 全暴露 |
| MyBatis-Plus 直接接受 Entity | Controller 直接接收 User 对象传给 updateById,未做字段过滤 |
| CORS 全通 | `access-control-allow-origin: *` |
| 邮箱验证码可用 temp mail | mail.tm 临时邮箱可接收验证码 |
| **前端路由保护仅前端控制** | requiresAdmin 标志在后端无对应强制校验 |
| **系统级 Mass Assignment** | Article/Category/Tag/Announcement 全部 CRUD Entity 直收 |
| **article/all 无认证** | 管理端文章列表接口未做任何权限校验 |
## 复现命令
```bash
# 注册
POST /api/user/register {"username":"x","password":"{test_password}","email":"{test_email}","emailCode":"123456"}
# 提权
PUT /api/user/profile {"role":"admin"}
# 验证
GET /api/user/info → {"role":"admin",...}
GET /api/user/list → [全部用户]
```
## 工具
- curl (Windows)
- mail.tm API (临时邮箱)
- Python 3
- JS 源码静态分析(regex/py 提取端点)
## 修复要点
1. DTO 隔离:Controller 不要直接接收 Entity 对象(全局审计)
2. `@JsonIgnore` 或 Service 层 role 字段强制写保护
3. 生产禁用 Swagger/Knife4j
4. CORS 限制为具体域名
5. 用户信息接口脱敏
6. Article/all 添加 SaCheckRole 注解
7. 后端对所有管理端接口做独立权限校验(不依赖前端路由控制)
## 关联
- [[swagger-exposure-pentest]]