漏洞分析: 细数Django框架核心历史SQL注入漏洞(下)
本文首发于奇安信攻防社区:https://forum.butian.net/share/1962
本文仅用于技术讨论与研究,文中的实现方法切勿应用在任何违法场景。如因涉嫌违法造成的一切不良影响,本文作者概不负责。
0x00 前言
最近总结了一下 Django
框架曾经出现的 SQL
注入漏洞,总共有七个 CVE
,分别都简单分析复现并写了文章,总体来说会觉得比较有意思,在这里分享一下。本篇文章是下篇。上篇请查看:细数Django框架核心历史SQL注入漏洞(上)
0x01 目录
本篇文章分享三个 CVE
,其他四个 CVE
在上篇文章展现。
- CVE-2022-28346
- CVE-2022-28347
- CVE-2022-34265
0x02 CVE-2022-28346
漏洞描述
Django
在2022年发布的安全更新,修复了在 QuerySet
的 annotate()
, aggregate()
, extra()
等函数中存在的 SQL
注入漏洞。
漏洞影响
- Django 2.2.x < 2.2.28
- Django 3.2.x < 3.2.13
- Django 4.0.x < 4.0.4
需要使用了 annotate
或者 aggregate
或 extra
方法
漏洞分析
我们可以直接来到 github
修复记录
这里给 add_annotation
和 add_extra
两个函数中的参数添加了正则过滤,接下来我们就是要找到哪里使用到了这两个函数
这里其实可以通过测试用例来进行判断,我们可以看到修复记录中也存在测试用例的修复有点多,这里只选取一个进行分析
这里使用到了如下语句
1 |
|
crafted_alias
是用来测试的 payload
,我们先找到 aggregate
的实现位置
最终可以找到这里 django\db\models\query.py
传进来的 args
与 kwargs
会经过 _validate_values_are_expressions
处理,但没有进行过滤
之后进过 add_annotation
进行赋值,如下
这里就是修复 sql
注入的位置,对 alias
进行了过滤,而目前这里没有进行过滤,直接成为了 self.annotations
的键,之后跟进会发现这个self.annotations
在 resolve_ref
函数中被取出来
这里会将我们之前的 alias
的值最终放到 transform
中,直接被使用
其他的漏洞函数与这个类似,就不分析了。
漏洞复现
复现环境参考之前的 CVE-2020-7471
,只需要更改 views.py
1 |
|
payload
如下
1 |
|
0x03 CVE-2022-28347
漏洞描述
Django
在2022年发布的安全更新,修复了在 QuerySet
的 explain()
函数中存在的 SQL
注入漏洞。
漏洞影响
- Django 2.2.x < 2.2.28
- Django 3.2.x < 3.2.13
- Django 4.0.x < 4.0.4
需要使用了 explain
方法,并且参数可控
漏洞分析
我们可以直接来到 github
修复记录
这里首先做的就是对 options
的内容进行过滤,如果包含敏感的字符,那么就报错,仅仅这些还没够,还做了如下更改
这里做了一个白名单,只有在这个白名单中的字符串才可以被使用,不会直接将所有的都拼接进去
有了修复的记录,我们就很容易定位到出现问题的地方,这里 django\db\models\sql\compiler.py
是将代码变成 sql
语句,在这里有一句关于 explain
的处理
result
是一个数组,里面的字符串最后都会拼接到一起,这里调用 explain_query_prefix
进行处理 self.query.explain_options
的内容,我们这里使用 postgres
数据库,并且 postgres
对这个函数存在重写,因此这里也直接看该数据库相关的处理
django\db\backends\postgresql\operations.py
经过父类的处理后,在下面,会将options
中的每一个取出来,键直接为键,值存在就为 true
,因此值无法被更改,但是键会直接写入,最后拼接到 prefix
上去,因此这里的键存在注入。
漏洞复现
复现环境参考之前的 CVE-2022-28346
,只需要更改 views.py
1 |
|
payload
如下
1 |
|
0x04 CVE-2022-34265
漏洞描述
Django
在2022年发布的安全更新,修复了在 Trunc()
和 Extract()
函数中存在的 SQL
注入漏洞。
漏洞影响
- Django 3.2.x < 3.2.14
- Django 4.0.x < 4.0.6
需要使用了 Trunc()
或 Extract()
方法,并且参数可控
漏洞分析
我们可以直接来到 github
修复记录
在这里是直接给 Extract
类或者 Trunc
类的 as_sql
方法添加了一层正则过滤。
这里我们以 Extract
为例,可以多关注被过滤的那个参数,也就是 self.lookup_name
这里我们可以进入多个分支,但之后得处理实际上都差不多,我们先进入 datetime_extract_sql
这里还是进入了和上面一样的 date_extract_sql
函数,而且没有经历其他的处理
看到 lookup_type
,就是我们之前传入的被过滤的参数,最后在 else
直接拼接了,直接造成 sql
注入。
trunc
也是一样,不过进入的是 datetime_trunc_sql
或者 time_trunc_sql
等函数
漏洞复现
漏洞复现可以参照修复记录中的 test
,这里直接使用 vulhub
的环境,可以直接在下面获取
payload
1 |
|