★且听安全★-点关注,不迷路!
★漏洞空间站★-优质漏洞资源和小伙伴聚集地!
这段时间 Java 卷的太狠,换一下口味。
**漏洞信息
**
Django 数据库函数 `Trunc` 和 `Extract` 主要用于进行日期操作,定义如下:
`Extract` 用于提取日期,比如我们可以提取日期字段中的年、月、日等信息, `Trunc` 则用于截取,比如 `2000-01-01 11:11:11` ,可以根据需求获取到日期 `2000-01-01` 。如果将未过滤的数据传递给 `kind` 或 `lookup_name` 时,将会出现 SQL 注入漏洞。影响版本:
Django 3.2.x prior to 3.2.14
Django 4.0.x prior to 4.0.6
**补丁对比
**
在 Django 新版本 `operations.py` 的 `BaseDatabaseOperations` 类中新增了 `extract_trunc_lookup_pattern` 正则表达式:
然后在 `datetime.py` 的 `Extract` 和 `Trunc` 类中 `as_sql` 函数分别加入了对 `self.lookup_name` 和 `self.kind` 参数的正则表达式检查:
**环境搭建
**
为了深入分析漏洞原理,建议采用源码方式完成环境搭建:
参考 Django 官方提供的 `database-functions` 以及补丁中的测试例子,构造如下数据库实体类:
对应 MySQL 数据库定义:
在 `views.py` 中添加测试 API 接口定义:
在 `urls.py` 中配置路由规则:
**漏洞分析
**
以 `Extract` 为例,构造请求 `/extract_test/?lookup_name=year` ,顺利进入 API 函数入口:
在 Django 框架自带的 ORM 模型中,当进行 SQL 查询操作时,将调用 `\django\db\models\query.py` 的 `QuerySet` 类中对应方法进行处理。比如 `Demo` 中的查询将调用 `QuerySet#exists` 函数:
经过多次传递后,进入 `SQLCompiler#compile` :
最终到达此次存在漏洞的 `Extract` 类中函数 `as_sql` :
因为 `demo` 中选择的字段 `start_datetime` 属于 `DateTimeField` 类型,所以将进入第 `58` 行的 `datetime_extract_sql` 函数:
跟进 `date_extract_sql` :
`date_extract_sql` 函数将根据输入的 `lookup_type` 取值生成不同的 SQL 语句,比如 `demo` 中设置为 `year` ,最终返回如下 :
对来自 GET 请求的 `lookup_name` 参数只是完成大写转换,但没有进行任何检查,直接拼接到 SQL 查询语句中,存在注入漏洞:
报错回显测试:
**修复方式
**
前面补丁对比已经提到,新版本中对传入参数新增了正则表达式检查规则。
由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用本人负责,且听安全及文章作者不为此承担任何责任。
★且听安全★-点关注,不迷路!****
★漏洞空间站★-优质漏洞资源和小伙伴聚集地!