JSON, XML & Yaml Hacking & Issues
Reading time: 4 minutes
Go JSON 解码器
在 Go JSON 中检测到以下问题,尽管这些问题也可能出现在其他语言中。这些问题已在 这篇博客文章 中发布。
Go 的 JSON、XML 和 YAML 解析器存在许多不一致和不安全的默认设置,这些设置可能被滥用以 绕过身份验证、提升权限 或 外泄敏感数据。
(反)序列化意外数据
目标是利用允许攻击者读取/写入敏感字段(例如,IsAdmin、Password)的结构体。
- 示例结构体:
go
type User struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
IsAdmin bool `json:"-"`
}
- 常见漏洞
- 缺失标签(无标签 = 字段仍然按默认解析):
go
type User struct {
Username string
}
有效载荷:
json
{"Username": "admin"}
- 不正确使用
-:
go
type User struct {
IsAdmin bool `json:"-,omitempty"` // ❌ wrong
}
有效载荷:
json
{"-": true}
✔️ 正确阻止字段被(反)序列化的方法:
go
type User struct {
IsAdmin bool `json:"-"`
}
解析器差异
目标是通过利用不同解析器对相同有效负载的不同解释来绕过授权,例如:
- CVE-2017-12635: 通过重复键绕过 Apache CouchDB
- 2022: 通过 XML 解析器不一致性实现 Zoom 0-click RCE
- GitLab 2025 通过 XML 特性绕过 SAML
1. 重复字段:
Go 的 encoding/json 取 最后 一个字段。
go
json.Unmarshal([]byte(`{"action":"UserAction", "action":"AdminAction"}`), &req)
fmt.Println(req.Action) // AdminAction
其他解析器(例如,Java的Jackson)可能会取第一个。
2. 不区分大小写: Go是不区分大小写的:
go
json.Unmarshal([]byte(`{"AcTiOn":"AdminAction"}`), &req)
// matches `Action` field
即使是Unicode技巧也有效:
go
json.Unmarshal([]byte(`{"aKtionſ": "bypass"}`), &req)
3. 跨服务不匹配:
想象一下:
- 用 Go 编写的代理
- 用 Python 编写的 AuthZ 服务
攻击者发送:
json
{
"action": "UserAction",
"AcTiOn": "AdminAction"
}
- Python 看到
UserAction,允许它 - Go 看到
AdminAction,执行它
数据格式混淆(多语言)
目标是利用混合格式(JSON/XML/YAML)或在解析器错误时失败开放的系统,例如:
- CVE-2020-16250:HashiCorp Vault 在 STS 返回 JSON 而不是 XML 后,用 XML 解析器解析了 JSON。
攻击者控制:
Accept: application/json头- 对 JSON 主体的部分控制
Go 的 XML 解析器 仍然 解析了它并信任注入的身份。
- 精心制作的有效负载:
json
{
"action": "Action_1",
"AcTiOn": "Action_2",
"ignored": "<?xml version=\"1.0\"?><Action>Action_3</Action>"
}
结果:
- Go JSON 解析器:
Action_2(不区分大小写 + 最后一个胜出) - YAML 解析器:
Action_1(区分大小写) - XML 解析器:解析字符串中的
"Action_3"
🔐 缓解措施
| 风险 | 修复 |
|---|---|
| 未知字段 | decoder.DisallowUnknownFields() |
| 重复字段(JSON) | ❌ 标准库中没有修复 |
| 不区分大小写的匹配 | ❌ 标准库中没有修复 |
| XML 垃圾数据 | ❌ 标准库中没有修复 |
| YAML:未知键 | yaml.KnownFields(true) |
HackTricks