Django SQL注入漏洞 CVE-2022-28346
漏洞簡介
Django 在2022年發(fā)布的安全更新,修復(fù)了在 QuerySet 的 annotate(), aggregate(), extra() 等函數(shù)中存在的 SQL 注入漏洞。
影響版本
2.2<= Django Django <2.2.28
3.2<= Django Django <3.2.13
4.0<= Django Django <4.0.4
需要使用了 annotate 或者 aggregate 或 extra 方法
環(huán)境搭建
搭建特定版本的 django 項(xiàng)目
利用 pycharm 創(chuàng)建一個(gè) python 項(xiàng)目

創(chuàng)建完成項(xiàng)目后在 Settings 中找到 Project: CVE202228346 對(duì)應(yīng)的 Python Interpreter

添加存在問題的 Django 版本

在 Terminal 中執(zhí)行命令,創(chuàng)建 django 項(xiàng)目
django-admin startproject CVE202228346

配置啟動(dòng)設(shè)置


運(yùn)行后就啟動(dòng)了最簡單的 django 項(xiàng)目


?
編寫配置漏洞代碼
折騰來折騰去,出現(xiàn)了很多問題,一度想要放棄說直接采用 docker ,但是在不斷的試錯(cuò)下,最終還是編寫成功
因?yàn)閷?duì) python 的 django 不太熟悉,所以其中可能更多的是比較偏向于基礎(chǔ)的操作
?
進(jìn)入到項(xiàng)目目錄下創(chuàng)建命令 創(chuàng)建第一個(gè)應(yīng)用

在 settings.py 中添加配置

在 urls.py 中添加 對(duì)應(yīng)的 url,urls.py 相當(dāng)于路由解析器,將路由解析到對(duì)應(yīng)的 views.py 中對(duì)應(yīng)的函數(shù)上

urlpatterns?=?[
????path('admin/',?admin.site.urls),
????path('index/',views.index),
????path('demo/',views.users),
????path('initialize/',views.loadexampledata)
]
?
models.py 是創(chuàng)建表結(jié)構(gòu)的時(shí)候使用,通過類的定義,可以創(chuàng)建一個(gè)表

from?django.db?import?models
#?Create?your?models?here.
class?User(models.Model):
????name?=?models.CharField(max_length=200)
????def?__str__(self):
????????return?self.name
?
views.py 主要定義了對(duì)應(yīng)路由所響應(yīng)的函數(shù)

from?django.db.models?import?Count
from?django.http?import?HttpResponse
from?django.shortcuts?import?render
from?.models?import?User
#?Create?your?views?here.
def?index(request):
????return?HttpResponse('hello?world')
def?users(request):
????field?=?request.GET.get('field',?'name')
????user_amount?=?User.objects.annotate(**{field:?Count("name")})
????html?=?""
????for?u?in?user_amount:
????????html?+=?"<h3>Amoount?of?users:?{0}</h3>".format(u)
????return?HttpResponse(html)
def?loadexampledata(request):
????u?=?User(name="Admin")
????u.save()
????u?=?User(name="Staff1")
????u.save()
????u?=?User(name="Staff12")
????u.save()
????return?HttpResponse("ok")
三個(gè)函數(shù)分別是 helloword 函數(shù),往數(shù)據(jù)庫中加參數(shù),以及查詢數(shù)據(jù)庫中的字段
?
編寫好代碼后,需要對(duì)數(shù)據(jù)庫執(zhí)行初始化操作
python?manage.py?makemigrations
python?manage.py?migrate
?
漏洞復(fù)現(xiàn)
先訪問 initialize 為數(shù)據(jù)庫中添加信息
構(gòu)造 payload
http://127.0.0.1:8000/demo/?field=demo.name"?FROM?"demo_user"?union?SELECT?"1",sqlite_version(),"3"?--

漏洞分析
發(fā)現(xiàn)一個(gè)問題,在加上斷點(diǎn)調(diào)試以后,每次運(yùn)行輸出的結(jié)果跟不加斷點(diǎn)運(yùn)行的結(jié)果存在很大的差異,結(jié)果完全不同。不斷嘗試之后發(fā)現(xiàn)是因?yàn)樵谀承┑胤郊由蠑帱c(diǎn)之后,在調(diào)試器中查看變量和狀態(tài)可能會(huì)影響程序的執(zhí)行速度和內(nèi)存使用情況,為了方便的輸出某些位置的變量,采用 print 的方法結(jié)合斷點(diǎn)調(diào)試。

通過 get 傳入的參數(shù) field
CVE202228346.demo.views.users

此處的**{field: Count("name")}?用來表示拆分字典
跟進(jìn)?annotate?對(duì)傳入?yún)?shù)的處理
django.db.models.query.QuerySet.annotate

繼續(xù)將參數(shù)傳入到?_annotate?進(jìn)行處理
django.db.models.query.QuerySet._annotate

在將?kwargs?的值?update?到?annotations?后,調(diào)用?add_annotation?進(jìn)行處理
django.db.models.sql.query.Query.add_annotation

add_annotation
?也是漏洞存在的關(guān)鍵位置,因?yàn)樾迯?fù)漏洞的關(guān)鍵位置也在此處
調(diào)用?resolve_expression?解析表達(dá)式
django.db.models.aggregates.Aggregate.resolve_expression

django.db.models.expressions.Func.resolve_expression

django.db.models.expressions.F.resolve_expression

django.db.models.sql.query.Query.resolve_ref

最后我們可以看到 clone 對(duì)應(yīng)的值 以及執(zhí)行的 SQL 語句

整個(gè)漏洞分析下來,仍然有很多不太清楚的地方,可能再分析幾個(gè)關(guān)于 Django 的漏洞會(huì)好一些
漏洞修復(fù)

在?
add_annotation
?添加了?
check_alias
?來對(duì)傳入的參數(shù)進(jìn)行校驗(yàn)
2023年網(wǎng)絡(luò)安全學(xué)習(xí)筆記(完整版)

獲取方式↓↓↓
添加VX備注【XQ】 即可免費(fèi)獲取
