Python Web 框架 Django 修复SQL注入漏洞

7月4日,OSCS 监测到 Django 官方修复了一个SQL注入漏洞。如果 Trunc()方法的kind参数和Extract()的lookup_name参数没有进行安全过滤,可能会造成SQL注入的风险。

OSCS
OSCS   Follow

OSCS(开源软件供应链安全社区)推出免费的漏洞、投毒情报订阅服务,社区用户可通过机器人订阅情报信息,具体订阅方式详见:https://www.oscs1024.com/?src=wx

# 漏洞概述

Django是一个由 Python 语言编写的开源Web应用框架,Github 上 star 为 64.9K。

Python的开发者使用Django快速开发、设计和部署网站。

7月4日,OSCS 监测到 Django 官方修复了一个SQL注入漏洞。如果 Trunc() 方法kind 参数和 **Extract()**的 lookup_name 参数没有进行安全过滤,可能会造成SQL注入的风险。

  • 漏洞影响等级:高危

  • 利用条件:

    • 代码中使用了**Trunc()和Extract()**方法
    • 其中kind参数和lookup_name参数可控
  • 利用成本:低

  • 影响版本:(∞, 3.2.14),[4.0, 4.0.6),官方已经在4.0.6、3.2.14版本修复此问题

  • CVE编号:CVE-2022-34265

更多漏洞详细信息可进入OSCS社区查看:https://www.oscs1024.com/hd/MPS-2022-19581

# 漏洞分析

以Django 4.0版本为例,可以通过官方提供的测试用例进行验证。

img

Extract() 方法将数据处理后返回一个 Extract 类型的对象,lookup_name 参数是传入的恶意数据。

img

DTModel.objects.filter 方法通过下图链路拼接出有恶意数据的SQL语句

(test_extract_trunc.py)test_extract_lookup_name_sql_injection
                                |
                    (manager.py)manager_method
                                |
                    (models/query.py)filter
                                |
                (models/query.py)_filter_or_exclude
                                |
              (models/query.py)_filter_or_exclude_inplace
                                |
                   (models/sql/query.py)add_q

img

add_q 方法中 self.where.add()则会将 lookup_name 拼接到 SQL 语句的 WHERE 部分

img

官方通告中数据库函数 Trunc,利用条件与 Extract 相同,测试用例如下:

def test_trunc_lookup_name_sql_injection(self):
        start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
        end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
        if settings.USE_TZ:
            start_datetime = timezone.make_aware(start_datetime)
            end_datetime = timezone.make_aware(end_datetime)
        self.create_model(start_datetime, end_datetime)
        self.create_model(end_datetime, start_datetime)
        msg = "Invalid kind: "
        with self.assertRaisesMessage(ValueError, msg):
            DTModel.objects.filter(
                start_datetime__date=Trunc(
                    "start_datetime",
                    "year', start_datetime)) OR 1=1;--",
                )
            ).exists()

# 风险场景

Extract() 方法的作用是提取日期的某部分为一个数字,内置的 lookup_name 参数指定返回数字是指定时间的对应部分,如当 lookup_name = 'year',返回年份。

Trunc() 方法也是将一个日期截断为一个部分,其中的 kind 参数与 lookup_name 参数功能类似。

因此,如果业务逻辑中有类似时间截取的逻辑,对应的year、day等参数由前端传入(用户可控,如选择时间等逻辑)的话,攻击者可以加入payload,从而对数据库进行操作。

# 修复方案

将组件 Django 升级至 3.2.14 及以上版本

将组件 Django 升级至 4.0.6 及以上版本

# 参考链接

https://www.oscs1024.com/hd/MPS-2022-19581

https://www.openwall.com/lists/oss-security/2022/07/04/2

https://nvd.nist.gov/vuln/detail/CVE-2022-34265

https://github.com/django/django/commit/54eb8a374d5d98594b264e8ec22337819b37443c

https://docs.djangoproject.com/zh-hans/4.0/ref/models/database-functions/

https://www.djangoproject.com/weblog/2022/jul/04/security-releases/