
Demonstriert eine Path-Traversal-Schwachstelle in einem offiziellen Beispielskript des eml-Parsers, die beliebiges Schreiben von Dateien über manipulierte Anhang-Dateinamen ermöglicht, mit PoC und Fix.
Das offizielle Beispielskript examples/recursively_extract_attachments.py enthält eine Pfad-Traversal-Schwachstelle, die beliebiges Datei-Schreiben außerhalb des vorgesehenen Ausgabeverzeichnisses ermöglicht. Anhängernamen, die aus geparsten E-Mails extrahiert werden, werden direkt zur Konstruktion der Ausgabedateipfade verwendet, ohne jegliche Bereinigung, sodass ein vom Angreifer kontrollierter Dateiname das Zielverzeichnis verlassen kann.
Datei: examples/recursively_extract_attachments.py
Zeilen: 61–64
for a in m['attachment']:
out_filepath = out_path / a['filename'] # No sanitization
print(f'\tWriting attachment: {out_filepath}')
with out_filepath.open('wb') as a_out:
a_out.write(base64.b64decode(a['raw']))
Der Wert a['filename'] ist über manipulierte E-Mail-Anhang-Header vom Angreifer kontrollierbar:
Content-Disposition: attachment; filename="../outside/pwned.txt"
Vor dem Schreiben wird keine Pfadnormalisierung oder Grenzwertprüfung durchgeführt.
.eml-Datei:Content-Disposition: attachment; filename="../outside/pwned.txt"
python recursively_extract_attachments.py -p ./emails -o ./safe
./safe/pwned.txt./outside/pwned.txt ← außerhalb des vorgesehenen Verzeichnisses geschriebenVerifiziert auf Kali Linux mit eml-parser, installiert über pip in einer virtuellen Umgebung.
Diese Schwachstelle ist auf das Beispielskript beschränkt und betrifft nicht die Kernbibliothek eml-parser. Da das Skript jedoch Teil des offiziellen Repositorys ist und wahrscheinlich für den Produktionseinsatz angepasst wird, könnte ein Angreifer, der eine manipulierte E-Mail bereitstellt, beliebiges Datei-Schreiben im Ausführungskontext erreichen.
Mögliche Angriffsszenarien umfassen:
filename="../../etc/cron.d/backdoor"filename="../../var/www/html/shell.php"filename="../../home/user/.ssh/authorized_keys"import os.path
for a in m['attachment']:
filename = os.path.basename(a['filename'])
out_filepath = out_path / filename
if not out_filepath.resolve().is_relative_to(out_path.resolve()):
print(f'[!] Skipping suspicious filename: {a["filename"]}')
continue
print(f'\tWriting attachment: {out_filepath}')
with out_filepath.open('wb') as a_out:
a_out.write(base64.b64decode(a['raw']))