安全矩阵

 找回密码
 立即注册
搜索
查看: 2903|回复: 0

Django SQL injection CVE-2022-28346 analysis

[复制链接]

180

主题

231

帖子

1180

积分

金牌会员

Rank: 6Rank: 6

积分
1180
发表于 2022-4-30 00:45:59 | 显示全部楼层 |阅读模式
Django SQL injection CVE-2022-28346 analysis

前言
最近在看CNVD时无意间看到两条关于Django的最新漏洞通告,随即打开看了一下.大概意思是说Django在2.2.28 版本之前的2.2版本、3.2.13版本之前的3.2版本、4.0.4版本之前的4.0版本使用QuerySet.annotate() aggregate() extra()数据聚合函数时会导致SQL注入问题.由于笔者平时开发一些平台多半也是使用Django,所以便尝试进行分析了一下.如有描述不当之处,还望大佬们斧正.

影响版本

  1. Django Django >=2.2,<2.2.28
  2. Django Django >=3.2,<3.2.13
  3. Django Django >=4.0,<4.0.4
复制代码


环境构建

  1. Python: 3.7.9
  2. Django: 3.2.11
复制代码


目录结构




models.py

  1. from django.db import models

  2. # Create your models here.
  3. class User(models.Model):
  4.     name = models.CharField(max_length=200)

  5.     def __str__(self):
  6.         return self.name
复制代码


views.py
  1. import datetime

  2. from django.db.models import Count
  3. from django.http import HttpResponse

  4. # Create your views here.
  5. from demo.models import User


  6. def loadexampledata(request):
  7.     u = User(name="Admin")
  8.     u.save()
  9.     u = User(name="Staff1")
  10.     u.save()
  11.     u = User(name="Staff12")
  12.     u.save()
  13.     return HttpResponse("ok")


  14. def users(request):
  15.     field = request.GET.get('field', 'name')
  16.     user_amount = User.objects.annotate(**{field: Count("name")})
  17.     html = ""
  18.     for u in user_amount:
  19.         html += "<h3>Amoount of users: {0}</h3>".format(u)
  20.     return HttpResponse(html)
复制代码


urls.py



  1. from django.contrib import admin
  2. from django.urls import path

  3. from demo import views

  4. urlpatterns = [
  5.     path('', views.loadexampledata),
  6.     path('demo/', views.users)
  7. ]
复制代码


settings.py



  1. INSTALLED_APPS = [
  2.     'django.contrib.admin',
  3.     'django.contrib.auth',
  4.     'django.contrib.contenttypes',
  5.     'django.contrib.sessions',
  6.     'django.contrib.messages',
  7.     'django.contrib.staticfiles',
  8.     'demo.apps.DemoConfig' # 新增
  9. ]
复制代码


或者使用笔者构建好的环境

https://github.com/DeEpinGh0st/CVE-2022-28346

漏洞复现
初始化项目

  1. 1.python manage.py makemigrations
  2. 2.python manage.py migrate
  3. 3.访问http://x.x.x.x:8000/ 初始化数据
复制代码


触发

  1. 访问
  2. http://x.x.x.x:8000/demo?field=demo.name" FROM "demo_user" union SELECT "1",sqlite_version(),"3" --
复制代码



漏洞分析
老规矩,分析前可以先看看官方在修复的commit中有没有给出测试用例

https://github.com/django/django ... 34c4139bcf48c5c7e48中看到官方在测试组件中给出了基本的测试用例




我们可以根据官方给出的代码编写相应的代码进行调试和分析.

在views.py的annotate打入断点后,来到db.models.query.py:__init__,进行QuerySet的初始化



在初始化QuerySet后,会来到db.models.query.py:annotate开始执行聚合流程,在annotate中首先会调用_annotate并传入kwargs




_annotate在完成对kwargs.values()合法性校验等一系列操作后,将kwargs更新到annotations中,随后遍历annotations中的元素调用add_annotation进行数据聚合




跟进add_annotation(print是笔者为了分析自己加入的)




add_annotation继续调用resolve_expression解析表达式,在此处并没有对传入的聚合参数进行相应的检查.在经过一系列调用后,最终会来到db.models.sql.query.py:resolve_ref

resolve_ref会获取annotations中的元素,并将其转换后带入到查询的条件中,最后其结果通过transform_function聚合到一个Col对象中

可以看到聚合之后的结果



返回到db.models.query.py:_annotate可以看到具体聚合后数据值,以及执行的sql语句




最后将结果返回到QuerySet中进行展示





修复
在漏洞公开后,django官方随即对项目进行了修复



在add_annotation中加入了check_alias对聚合参数进行检查

参考
https://github.com/django/django/commit/2044dac5c6968441be6f534c4139bcf48c5c7e48

https://www.cnvd.org.cn/flaw/show/CNVD-2022-31838



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-30 09:00 , Processed in 0.015253 second(s), 29 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表