
Demonstra uma vulnerabilidade de path traversal em um script de exemplo oficial do eml-parser, permitindo escrita arbitrária de arquivos por meio de nomes de anexos manipulados, com PoC e correção.
O script de exemplo oficial examples/recursively_extract_attachments.py contém uma vulnerabilidade de travessia de caminho que permite a gravação arbitrária de arquivos fora do diretório de saída pretendido. Os nomes de arquivos de anexos extraídos de e-mails analisados são usados diretamente para construir caminhos de arquivos de saída sem qualquer sanitização, permitindo que um nome de arquivo controlado pelo atacante escape do diretório de destino.
Arquivo: examples/recursively_extract_attachments.py
Linhas: 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']))
O valor a['filename'] é controlado pelo atacante por meio de cabeçalhos de anexos de e-mail manipulados:
Content-Disposition: attachment; filename="../outside/pwned.txt"
Nenhuma normalização de caminho ou validação de limites é realizada antes da gravação.
.eml malicioso:Content-Disposition: attachment; filename="../outside/pwned.txt"
python recursively_extract_attachments.py -p ./emails -o ./safe
./safe/pwned.txt./outside/pwned.txt ← gravado fora do diretório pretendidoVerificado no Kali Linux com eml-parser instalado via pip em um ambiente virtual.
Esta vulnerabilidade está limitada apenas ao script de exemplo e não afeta a biblioteca principal eml-parser. No entanto, como o script faz parte do repositório oficial e provavelmente será adaptado para uso em produção, um atacante que forneça um e-mail manipulado poderia obter gravação arbitrária de arquivos dentro do contexto de execução.
Cenários de ataque potenciais incluem:
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']))