谈谈Django的RCE
字数 1991 2025-08-18 17:33:25

Django RCE漏洞分析与防御指南

0x00 前言

Django作为一款高安全性框架,历史上很少出现无条件直接利用的RCE漏洞。本文详细分析两种因配置不当导致的Django RCE漏洞:CVE-2014-0472历史漏洞和FileBasedCache新型RCE利用方法。

0x01 CVE-2014-0472漏洞分析

漏洞描述

2014年发现的漏洞,位于django/core/urlresolvers.py(现为django/url/resolvers.py)中的reverse函数过滤不当,导致可以任意获取内部函数,当攻击者知道代码内部存在恶意模块时,可导致任意代码执行。

漏洞原理

  1. reverse函数用于URL反向解析,根据视图名称查找对应URL
  2. 漏洞点在于get_callable函数中未对传入的函数名进行充分过滤
  3. 关键危险代码:lookup_view = getattr(import_module(mod_name), func_name)
  4. 当传入不可调用函数名时,会直接通过getattr调用该函数

漏洞利用条件

  1. 存在使用redirectreverse函数且参数可控的视图
  2. 攻击者知道项目内部存在的恶意引用

典型漏洞代码示例

def redirect_test(request):
    page = request.GET.get('page', None)
    if page is not None:
        redirect(page)  # 危险:直接使用用户输入作为redirect参数
    return HttpResponse("OK")

漏洞复现步骤

  1. 构造恶意请求:http://example.com/example?page=os.system
  2. Django会尝试调用os.system函数
  3. 如果知道项目内部使用的恶意模块,可进一步利用

官方修复

  1. 增加了对传入reverse函数内部功能的检查
  2. 检查方法是否存在于URL路由表中
  3. 补丁地址:https://github.com/django/django/commit/8b93b31487d6d3b0fcbbd0498991ea0db9088054

0x02 FileBasedCache RCE漏洞

漏洞描述

Django的缓存配置错误可能引发RCE,特别是使用FileBasedCache时,由于直接使用pickle反序列化缓存文件,攻击者可构造恶意序列化数据实现代码执行。

漏洞原理

  1. FileBasedCache使用pickle进行序列化/反序列化
  2. 关键危险代码:
    • pickle.loads(zlib.decompress(f.read())) (get方法)
    • pickle.load(f) (_is_expired方法)
  3. 无任何过滤直接反序列化用户可控的缓存文件

漏洞利用条件

  1. 知道缓存文件存储位置(通常为/var/tmp/django_cachec:/foo/bar)
  2. 知道缓存文件命名规则
  3. 有权限写入缓存目录(通过其他服务或文件上传)

缓存文件命名规则

  1. GET方式:
    md5("<prefix>:version:views.decorators.cache.cache_page.<prefix>.GET.<全局url的md5>.d41d8cd98f00b204e9800998ecf8427e.<时间区域>") + ".djcache"
    
  2. HEAD方式:
    md5("<prefix>:version:views.decorators.cache.cache_page.<prefix>.HEAD.<全局url的md5>.d41d8cd98f00b204e9800998ecf8427e.<时间区域>") + ".djcache"
    

利用场景

  1. 多服务共享临时目录

    • Django默认缓存权限700
    • 但若nginx/apache运行多个服务,其他服务可能有权写入
  2. 错误配置缓存位置

    • 将CACHE_LOCATION配置在MEDIA_ROOT子目录
    • 通过文件上传覆盖缓存文件
    • 注意:FileField不会覆盖已有文件,但可上传HEAD类型缓存
  3. 敏感信息泄露

    • 过期缓存未被删除
    • 可能泄露之前视图的响应内容

漏洞复现步骤

  1. 确定缓存位置(检查settings.py中的CACHE_LOCATION)
  2. 根据URL计算缓存文件名
  3. 构造恶意pickle序列化数据写入缓存文件
  4. 访问对应URL触发反序列化

缓存内容读取示例代码

import pickle
import zlib
import sys

def readcachecontent(filename):
    f = open(filename, "rb")
    pickle.load(f)
    previous_value = pickle.loads(zlib.decompress(f.read()))
    f.close()
    print("Content:")
    print(previous_value.content)

if __name__ == '__main__':
    filename = sys.argv[1]
    readcachecontent(filename)

0x03 防御措施

针对CVE-2014-0472

  1. 升级到已修复版本
  2. 避免直接使用用户输入作为redirectreverse参数
  3. 对传入参数进行严格过滤

针对FileBasedCache RCE

  1. 官方修复

    • 在manage.py的check方法中增加对MEDIA_ROOT、STATIC_ROOT和STATICFILES_DIRS的检查
    • 警告CACHE_LOCATION不应位于这三个路径下
    • 补丁地址:https://github.com/django/django/commit/c36075ac1dddfa986340b1a5e15fe48833322372
  2. 配置建议

    • 使用key_prefix参数混淆缓存文件名:
      @cache_page(60 * 60, key_prefix="obfuscating_cache")
      
    • 设置严格的缓存目录权限
    • 避免使用默认缓存位置
  3. 替代方案

    • 考虑使用其他缓存后端如Memcached或Redis
    • 定期清理过期缓存文件

0x04 总结

  1. Django虽然安全性高,但配置不当仍可能导致严重漏洞
  2. 历史漏洞CVE-2014-0472展示了URL反向解析的风险
  3. FileBasedCache的pickle反序列化是新型RCE利用点
  4. 防御关键在于严格过滤输入和合理配置缓存
  5. 遵循最小权限原则和安全配置指南可有效降低风险
Django RCE漏洞分析与防御指南 0x00 前言 Django作为一款高安全性框架,历史上很少出现无条件直接利用的RCE漏洞。本文详细分析两种因配置不当导致的Django RCE漏洞:CVE-2014-0472历史漏洞和FileBasedCache新型RCE利用方法。 0x01 CVE-2014-0472漏洞分析 漏洞描述 2014年发现的漏洞,位于 django/core/urlresolvers.py (现为 django/url/resolvers.py )中的 reverse 函数过滤不当,导致可以任意获取内部函数,当攻击者知道代码内部存在恶意模块时,可导致任意代码执行。 漏洞原理 reverse 函数用于URL反向解析,根据视图名称查找对应URL 漏洞点在于 get_callable 函数中未对传入的函数名进行充分过滤 关键危险代码: lookup_view = getattr(import_module(mod_name), func_name) 当传入不可调用函数名时,会直接通过 getattr 调用该函数 漏洞利用条件 存在使用 redirect 或 reverse 函数且参数可控的视图 攻击者知道项目内部存在的恶意引用 典型漏洞代码示例 漏洞复现步骤 构造恶意请求: http://example.com/example?page=os.system Django会尝试调用 os.system 函数 如果知道项目内部使用的恶意模块,可进一步利用 官方修复 增加了对传入 reverse 函数内部功能的检查 检查方法是否存在于URL路由表中 补丁地址:https://github.com/django/django/commit/8b93b31487d6d3b0fcbbd0498991ea0db9088054 0x02 FileBasedCache RCE漏洞 漏洞描述 Django的缓存配置错误可能引发RCE,特别是使用FileBasedCache时,由于直接使用pickle反序列化缓存文件,攻击者可构造恶意序列化数据实现代码执行。 漏洞原理 FileBasedCache使用pickle进行序列化/反序列化 关键危险代码: pickle.loads(zlib.decompress(f.read())) (get方法) pickle.load(f) (_ is_ expired方法) 无任何过滤直接反序列化用户可控的缓存文件 漏洞利用条件 知道缓存文件存储位置(通常为 /var/tmp/django_cache 或 c:/foo/bar ) 知道缓存文件命名规则 有权限写入缓存目录(通过其他服务或文件上传) 缓存文件命名规则 GET方式: HEAD方式: 利用场景 多服务共享临时目录 : Django默认缓存权限700 但若nginx/apache运行多个服务,其他服务可能有权写入 错误配置缓存位置 : 将CACHE_ LOCATION配置在MEDIA_ ROOT子目录 通过文件上传覆盖缓存文件 注意:FileField不会覆盖已有文件,但可上传HEAD类型缓存 敏感信息泄露 : 过期缓存未被删除 可能泄露之前视图的响应内容 漏洞复现步骤 确定缓存位置(检查settings.py中的CACHE_ LOCATION) 根据URL计算缓存文件名 构造恶意pickle序列化数据写入缓存文件 访问对应URL触发反序列化 缓存内容读取示例代码 0x03 防御措施 针对CVE-2014-0472 升级到已修复版本 避免直接使用用户输入作为 redirect 或 reverse 参数 对传入参数进行严格过滤 针对FileBasedCache RCE 官方修复 : 在manage.py的check方法中增加对MEDIA_ ROOT、STATIC_ ROOT和STATICFILES_ DIRS的检查 警告CACHE_ LOCATION不应位于这三个路径下 补丁地址:https://github.com/django/django/commit/c36075ac1dddfa986340b1a5e15fe48833322372 配置建议 : 使用 key_prefix 参数混淆缓存文件名: 设置严格的缓存目录权限 避免使用默认缓存位置 替代方案 : 考虑使用其他缓存后端如Memcached或Redis 定期清理过期缓存文件 0x04 总结 Django虽然安全性高,但配置不当仍可能导致严重漏洞 历史漏洞CVE-2014-0472展示了URL反向解析的风险 FileBasedCache的pickle反序列化是新型RCE利用点 防御关键在于严格过滤输入和合理配置缓存 遵循最小权限原则和安全配置指南可有效降低风险