flagChallenge Webhooks Easy

URL Download challenge = EN PROCESO...

Contexto del challenge

Trayectoria del Challenge

Descripción general

El challenge Webhooks es un challenge de seguridad web desplegado mediante Docker, cuyo objetivo principal es la explotación de una aplicación web desarrollada en Node.js con Express. La aplicación simula un formulario de registro para un evento temático de Halloween y cuenta con un panel de administración interno visitado automáticamente por un bot administrador.

El reto está diseñado para evaluar conocimientos en:

  • Análisis de código fuente

  • Cross-Site Scripting (XSS) almacenado

  • Políticas de seguridad web (Content Security Policy – CSP)

  • Exfiltración de cookies y tokens JWT

  • Abuso de bots automatizados (Admin Bot)

  • Manipulación y decodificación de JWT

El objetivo final del challenge es obtener la flag, la cual se encuentra protegida dentro de una cookie de sesión JWT perteneciente al usuario administrador y únicamente accesible mediante la explotación encadenada de varias debilidades de seguridad.

Arquitectura y funcionamiento de la máquina

La máquina se ejecuta localmente mediante Docker y expone un único servicio web:

  • Aplicación web: Node.js + Express

  • Puerto: 1337

  • Interfaz: Formulario de registro web

  • Panel interno: /admin (no accesible directamente por el usuario)

Cuando un usuario envía un formulario, la información es almacenada y posteriormente visualizada en un panel de administración. Dicho panel es visitado de forma automática por un bot basado en Puppeteer, el cual:

  • Inicia sesión como admin

  • Carga una cookie de sesión JWT válida

  • Accede al panel /admin

  • Procesa las solicitudes pendientes

Esta arquitectura introduce un escenario realista de Stored XSS + Admin Bot, muy común en entornos reales y competiciones CTF.

Vulnerabilidades identificadas

A continuación se enumeran las vulnerabilidades presentes en la máquina, incluyendo su identificación, CVE/CWE asociado y criticidad según CVSS v3.1.

Instalación

Primero tendremos que descomprimir el archivo challenge_webhook.zip y, posteriormente, descomprimir el archivo challenge.zip, que es del cual vamos a obtener la información de cómo está compuesto internamente el reto.

Una vez realizado este paso, vamos a iniciar el servidor de la página vulnerable utilizando la herramienta incluida llamada run.sh.

Resultado:

Con esto veremos que ya podremos acceder a la aplicación web vulnerable desde http://127.0.0.1:1337. A partir de aquí, el entorno estará listo para comenzar el reto.


Info extra.

Cuando terminemos el reto y queramos detener el servidor, tendremos que pulsar Ctrl+C varias veces en la pestaña de la terminal donde esté ejecutándose el script run.sh. Una vez detenido, deberemos ejecutar el archivo delete.sh para que elimine los contenedores creados.


Web

Si accedemos a la siguiente URL:

Veremos lo siguiente:

Se trata de una página web aparentemente normal, que contiene un formulario para participar en una fiesta de Halloween o algo similar.

Para obtener más información sobre la tecnología utilizada en la página, ejecutamos la herramienta whatweb.

Resultado:

Como resultado observamos varios detalles interesantes:

  • La aplicación está desarrollada sobre Express.

  • Existen políticas de seguridad configuradas a nivel de headers.

Express

Express se refiere a Express.js, un framework web rápido y minimalista para Node.js, diseñado para simplificar la creación de aplicaciones y APIs web, gestionando rutas y solicitudes de manera eficiente.

Políticas de headers

Si inspeccionamos la página desde el navegador, accedemos a la pestaña Network, seleccionamos la petición GET a la raíz (/) y revisamos los headers de la respuesta, veremos lo siguiente:

Content-Security-Policy (CSP) es una capa de seguridad web que ayuda a prevenir ataques como XSS (Cross-Site Scripting) y ataques de inyección, permitiendo definir qué fuentes de contenido (scripts, imágenes, estilos, etc.) están permitidas.

Dentro de este header, nos llama especialmente la atención la siguiente directiva:

Esto indica que la aplicación confía en scripts cargados desde su propio dominio y desde https://cdn.jsdelivr.net.

Si accedemos a la documentación de dicha plataforma:

URL = Pagina jsdeliver (Seccion GitHub)arrow-up-right

Veremos que existe una sección dedicada a GitHub:

En ella se explica que es posible cargar archivos directamente desde un repositorio de GitHub, indicando el usuario, el repositorio y el archivo a cargar.

Esto resulta muy interesante, ya que podemos aprovechar esta confianza para cargar un script externo en forma de XSS, siempre que encontremos un punto de inyección válido dentro de la aplicación.

La estructura de la URL sería la siguiente:

Aún así, todavía necesitamos identificar el punto exacto de inyección para poder explotar este comportamiento.

Fuzzing de archivos

Si revisamos el contenido del directorio challenge descomprimido y analizamos el código fuente de la aplicación, encontraremos varias líneas interesantes.

En el archivo templates/admin.html observamos el siguiente contenido:

Línea especialmente interesante:

Aquí podemos observar que el único parámetro de texto que no escapa caracteres especiales es Halloween Name. El filtro | safe indica que el contenido recibido del usuario es considerado seguro y se renderiza sin ningún tipo de sanitización.

El resto de campos no utilizan este filtro, por lo que sus caracteres especiales sí serán escapados automáticamente.


Info sobre safe

Cuando introducimos un payload como el siguiente en un campo que no utiliza | safe:

El motor de plantillas lo escapará y lo mostrará así:

Esto evita la ejecución del código.

Sin embargo, si el campo utiliza | safe, el contenido no se escapará y el payload se ejecutará directamente como código JavaScript, permitiendo un ataque XSS.


Llegados a este punto, ya podemos planear la explotación. Para saber exactamente qué debemos obtener mediante el XSS, investigamos el archivo bot/bot.js:

Aquí vemos que existe un bot que visita la página admin.html, justo donde se encuentra el punto vulnerable a XSS. Este bot establece previamente una Cookie de sesión que contiene, entre otros datos, la flag leída directamente del servidor.

Por lo tanto, el objetivo de la explotación será:

  • Inyectar código JavaScript en el campo Halloween Name.

  • Hacer que el bot ejecute ese código.

  • Robar la Cookie de sesión del admin.

  • Decodificar el token y extraer la flag.

Explotación

El payload que vamos a utilizar para el campo vulnerable es el siguiente:

Ejemplo:

Con esto estamos cargando un script externo desde una URL que está permitida por la política CSP, utilizando la funcionalidad de jsDelivr para repositorios de GitHub.

En mi caso, utilizaré una cuenta de pruebas de GitHub donde crearé un repositorio llamado test_XSS y dentro de él un archivo exploit.js. Este archivo se encargará de exfiltrar la Cookie del bot cuando sea ejecutado.

Para ello:

  1. Creamos una cuenta en GitHub.

  2. Creamos un nuevo repositorio llamado test_XSS.

  3. Seleccionamos la opción creating a new file.

  4. Creamos el archivo exploit.js con el siguiente contenido:

exploit.js

En lugar de abrir un puerto en nuestra máquina y configurar port forwarding, utilizamos el servicio webhook.site, que nos proporciona una URL pública temporal capaz de recibir peticiones HTTP.

URL = Pagina Webhookarrow-up-right

Este servicio nos permitirá recibir la Cookie como parámetro (jwt_data), codificada en Base64 para evitar problemas de formato.

El valor <ID_WEBHOOK> deberá ser reemplazado por el identificador generado por la página de Webhook.

Para mas información sobre webhooks leer mi articulo del mismo:

webhookWebhooks para recepción de datos sin exponer tu redchevron-right

Una vez guardado el archivo, volvemos a la página del puerto 1337 y, en el campo HALLOWEEN NAME, introducimos el payload:

Al enviar el formulario, el bot visitará la página de administración y ejecutará el script. En la página de webhook deberíamos ver una petición entrante similar a esta:

Observamos que el parámetro contiene información codificada en Base64. La decodificamos de la siguiente manera:

Resultado:

Esto confirma que hemos obtenido correctamente la sesión del bot.

Ahora procedemos a decodificar el token utilizando la herramienta jwt.io.

URL = Pagina jwt.io (Decodificar Tokens JWTs)arrow-up-right

Al pegar el contenido del token (después del =) en la página, veremos lo siguiente:

La información decodificada es:

Con esto ya hemos conseguido la flag, que era el objetivo final del reto.

flag.txt

Last updated