目录
一、漏洞成因
二、复现
1.环境搭建
2,django搭建
3,过程调试:
一、漏洞成因
Extract和Trunk源码:
class Extract(TimezoneMixin, Transform):
lookup_name = None
output_field = IntegerField()
def __init__(self, expression, lookup_name=None, tzinfo=None, **extra):
if self.lookup_name is None:
self.lookup_name = lookup_name
if self.lookup_name is None:
raise ValueError('lookup_name must be provided')
self.tzinfo = tzinfo
super().__init__(expression, **extra)
class Trunc(TruncBase):
def __init__(self, expression, kind, output_field=None, tzinfo=None, is_dst=None, **extra):
self.kind = kind
super().__init__(
expression, output_field=output_field, tzinfo=tzinfo,
is_dst=is_dst, **extra
)
Extract用于提取日期,可以提起日期字段中的年,月,日。如2022-7-13 12:12:12可以提取2022。
Trunc用于截取日期,比如日期字段中年,月,日。可以截取2022-7-13。
此次SQL注入漏洞的成因就是将数据赋值给lookup_name或kind时,未经过过滤或转义则直接进行了数据库的查询。
影响版本:3.2.0-3.2.14,4.0.0-4.0.6
二、复现
1.环境搭建
1,数据库的搭建:
2,django搭建
Settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'cve34265',
'USER': 'root',
'PASSWORD': 'root',
'HOST': 'localhost',
'PORT': '3306',
}
}
models.py:
from datetime import datetime
from django.db import models
class Experiment(models.Model):
start_datetime = models.DateTimeField()
start_date = models.DateField(null=True, blank=True)
start_time = models.TimeField(null=True, blank=True)
class Meta:
db_table = 'experiment'
urls.py:
from cve.views import test
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('extract_test/',test.extract_test),
path('trunc_test/',test.trunc_test),
path('admin/', admin.site.urls),
]
test.py:
from django.shortcuts import render
from django.http import HttpResponse
from django.db.models.functions import Extract, Trunc
from cve.models import Experiment
def extract_test(request):
lookup_name = request.GET.get('lookup_name')
test = Experiment.objects.filter(start_datetime__year=Extract('start_datetime', lookup_name)).exists()
print(test)
return HttpResponse('extract_test')
def trunc_test(request):
kind = request.GET.get('kind')
test = Experiment.objects.filter(start_datetime__day=Trunc('start_datetime', kind)).exists()
print(test)
return HttpResponse('trunc_test')
# Create your views here.
3,过程调试:
(1)?进入API函数接口后,首先进入Django的models/query.py的对应方法进行操作处理,如test.py的查询首先调用exists函数:
(2)经过has_results函数等一系列传递,进入compile函数:
?
(3)compile函数将?得到的结果传入as_sql中:
?(4)as_sql函数执行datetime.extract_sql函数:
?(5)date_extract_sql函数进入else,生成EXTRACT(YEAR FROM Experiment '.' start datetime)返回到_query()函数中
返回的语句在数据库中被执行。
?总结:对于传入的参数,仅仅只完成了大写的转换,没有检查就拼接到Where的SQL语句中查询,存在SQL注入漏洞,可以使用updatexml或extractvalue报错注入进行查询。
|