You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/network-services-pentesting/pentesting-web/django.md
+54-8Lines changed: 54 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,32 @@ This HackerOne report provides a great, reproducible example of exploiting Djang
23
23
24
24
---
25
25
26
+
## Host Header / Password Reset Poisoning
27
+
Django uses the request host to build absolute URLs in several common patterns: password reset emails, canonical links, redirects, `request.build_absolute_uri()`, sitemap generation, and multitenant logic. The framework validates the host only when code goes through `request.get_host()`. Therefore, **applications that read `request.META['HTTP_HOST']` or trust `HTTP_X_FORWARDED_HOST` in custom middleware can reintroduce classic Host header poisoning bugs even when `ALLOWED_HOSTS` is configured**.
28
+
29
+
### High-value targets
30
+
* Password reset and email verification links generated from `request.build_absolute_uri()`
31
+
* Cache keys or reverse-proxy cache variations that include the host
32
+
* Tenancy / white-label logic that picks branding, callback URLs, or storage buckets from the host
33
+
* CSRF logic in deployments with attacker-controlled subdomains or overly broad cookie domains
34
+
35
+
### Practical checks
36
+
```http
37
+
POST /accounts/password/reset/ HTTP/1.1
38
+
Host: attacker.tld
39
+
X-Forwarded-Host: attacker.tld
40
+
X-Forwarded-Proto: https
41
+
```
42
+
43
+
Watch for:
44
+
* Reset links, absolute redirects, or preview URLs containing the injected host
45
+
*`SuspiciousOperation` only for `Host`, while `X-Forwarded-Host` still reaches application code
46
+
* Absolute URLs built from `request.META['HTTP_HOST']` instead of `request.get_host()`
47
+
48
+
Django's own security docs explicitly note that fake Host values can be used for CSRF, cache poisoning, and poisoning links in emails, and that reading the host directly from `request.META` bypasses `ALLOWED_HOSTS` protection. Also remember the CSRF limitation: if an attacker controls a subdomain and can set cookies for the parent domain, they may be able to satisfy the CSRF cookie/token check for the main app.
49
+
50
+
---
51
+
26
52
## Server-Side Template Injection (SSTI)
27
53
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.
28
54
@@ -72,13 +98,27 @@ Applications built on Django commonly integrate xhtml2pdf/ReportLab to export vi
72
98
73
99
---
74
100
75
-
## Pickle-Backed Session Cookie RCE
76
-
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.
101
+
## Pickle-Backed Signed Session Cookie RCE
102
+
If the application uses `SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'` together with `SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'` (or a custom serializer that deserialises pickle), Django will **unsign and unpickle attacker-controlled session data beforeview code runs**. In this configuration, a leaked `SECRET_KEY`immediately becomes an RCE primitive.
77
103
78
104
### Exploit Requirements
105
+
* The server uses the signed-cookie session backend (`django.contrib.sessions.backends.signed_cookies`).
79
106
* The server uses `PickleSerializer`.
80
107
* The attacker knows / can guess `settings.SECRET_KEY` (leaks via GitHub, `.env`, error pages, etc.).
81
108
109
+
### Recon and tooling
110
+
If the whole session is stored client-side, the `sessionid` cookie is usually a long signed blob rather than a short opaque session key from a server-side session store. That is the situation where `SECRET_KEY` guessing, reuse, or disclosure matters the most.
111
+
112
+
[`badsecrets`](https://github.com/blacklanternsecurity/badsecrets) can test Django signed cookies against known or weak secrets:
113
+
114
+
```bash
115
+
pip install badsecrets
116
+
badsecrets --url https://target.tld/
117
+
badsecrets '<sessionid_cookie_value>'
118
+
```
119
+
120
+
This is especially useful during wide scans for appliances or products that shipped with a hardcoded / tutorial `SECRET_KEY`, or after recovering a settings file from an LFI, debug page, or public repository.
121
+
82
122
### Proof-of-Concept
83
123
```python
84
124
#!/usr/bin/env python3
@@ -95,23 +135,29 @@ print(f"sessionid={mal}")
95
135
```
96
136
Send the resulting cookie, and the payload runs with the permissions of the WSGI worker.
97
137
98
-
**Mitigations**: Keep the default `JSONSerializer`, rotate `SECRET_KEY`, and configure`SESSION_COOKIE_HTTPONLY`.
138
+
**Mitigations**: keep the default `JSONSerializer`, rotate `SECRET_KEY`/`SECRET_KEY_FALLBACKS`, and leave`SESSION_COOKIE_HTTPONLY` enabled. Django's own signing/session docs explicitly recommend JSON here because JSON serialization prevents pickle-based code execution even if the signing key is exposed.
99
139
100
140
---
101
141
102
142
## Recent (2023-2025) High-Impact Django CVEs Pentesters Should Check
103
-
***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.
104
-
***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.
143
+
These are useful as **version-gated testing hints**, but the important lesson is broader: recent Django SQLi fixes keep landing in places where developers assume "ORM == safe" while still passing attacker-controlled field names, JSON keys, or alias names into `*args` / `**kwargs`.
144
+
145
+
***CVE-2025-48432** – *Log injection via unescaped `request.path`* (fixed June 4 2025). Allows attackers to smuggle newlines/ANSI escape sequences into application logs and poison downstream log ingestion or analyst terminals. Patch level ≥ 4.2.22 / 5.1.10 / 5.2.2.
146
+
***CVE-2025-57833** – *SQL injection in `FilteredRelation` column aliases* (fixed September 3 2025). Dangerous pattern: attacker-controlled dictionary expansion into `QuerySet.annotate()` / `QuerySet.alias()` keyword arguments.
147
+
***CVE-2024-42005** – *SQL injection in `QuerySet.values()` / `values_list()` on `JSONField`* (fixed August 6 2024). Dangerous pattern: attacker-controlled JSON keys reaching `values(*user_keys)` or `values_list(*user_keys)`.
148
+
***CVE-2024-53908** – *SQL injection in direct `HasKey(lhs, rhs)` usage on Oracle* (fixed December 4 2024). The common `field__has_key='x'` syntax is unaffected; the risky case is hand-built lookup objects with untrusted `lhs`.
105
149
106
-
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.
150
+
Always fingerprint the exact framework version via the `X-Frame-Options` error page, `/static/admin/css/base.css`hashes, package metadata leaks, or debug stack traces, then test the affected call sites where user input influences lookup names or alias names rather than raw values.
* 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)
0 commit comments