flagBrowsed HackTheBox (Intermediate)

Contexto de la maquina

Trayectoria de Browsed

Descripción general

La máquina Browsed es un laboratorio de seguridad ofensiva enfocado en aplicaciones web modernas, extensiones de navegador y escaladas de privilegios avanzadas en sistemas Linux. El entorno simula un escenario realista en el que una aplicación web permite la carga de extensiones de Google Chrome, las cuales son posteriormente procesadas y ejecutadas por un navegador interno del sistema.

El reto combina múltiples vectores de ataque encadenados, incluyendo:

  • Abuso de extensiones de navegador

  • Ejecución de código remoto indirecta (RCE)

  • Command Injection desde servicios internos

  • Movimiento lateral mediante ejecución en localhost

  • Escalada de privilegios a nivel de usuario

  • Privilege Escalation a root mediante Python Bytecode Poisoning

El objetivo final es comprometer completamente el sistema y obtener acceso como root, demostrando el impacto de una mala validación de entradas, configuraciones inseguras y permisos excesivos en entornos reales.

Arquitectura de la máquina

La máquina expone los siguientes componentes principales:

  • Sistema operativo: Ubuntu Linux

  • Servicios expuestos:

    • SSH (22)

    • HTTP (80)

  • Servidor web: Nginx

  • Aplicación web: Plataforma de subida de extensiones Chrome (.zip)

  • Servicios internos no expuestos externamente:

    • Aplicación Python en localhost:5000

    • Instancia de Gitea accesible únicamente desde el sistema

  • Herramienta privilegiada: Script Python ejecutable como root vía sudo

La aplicación web procesa extensiones subidas por el usuario, las ejecuta en un entorno controlado y permite interacción con dominios internos, lo que abre la puerta a ataques de Server-Side Extension Abuse.

Vulnerabilidades identificadas

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

Escaneo de puertos

Comenzamos realizando un escaneo completo de puertos TCP para identificar los servicios expuestos en la máquina objetivo.

Una vez identificados los puertos abiertos, lanzamos un escaneo más detallado sobre ellos para obtener versiones y scripts por defecto.

Resultado:

Detectamos un servicio HTTP en el puerto 80. Al acceder desde el navegador observamos lo siguiente:

Se muestra de forma destacada un dominio llamado browsed.htb. Lo añadimos a nuestro archivo /etc/hosts para poder trabajar cómodamente con él.

Guardamos los cambios y comenzamos a realizar fuzzing web en busca de subdominios, directorios o archivos interesantes.

Tras un fuzzing intensivo no encontramos nada relevante. Sin embargo, en la página principal se observa una opción llamada Upload Extension, lo que sugiere que podemos subir extensiones de Google Chrome en formato ZIP.

Al acceder a esta opción vemos lo siguiente:

Además, en la página principal existe una sección llamada Examples, donde se proporcionan ejemplos de extensiones ZIP válidas para tener una referencia del formato esperado.

Si inspeccionamos uno de estos ZIP de ejemplo, observamos una estructura típica de una extensión de navegador en JavaScript.

Resultado:

Con esta estructura clara, el objetivo es crear una extensión propia que realice conexiones hacia nuestra máquina atacante para comprobar si el código se ejecuta sin restricciones y si existe conectividad desde el servidor interno.

Para ello, creamos un pequeño servidor HTTP en Python que nos permitirá registrar cualquier petición recibida.

server.py

Ejecutamos el servidor:

Resultado:

Ahora creamos los archivos necesarios para nuestra extensión de prueba.

manifest.json

beacon.js

Comprimimos ambos archivos para generar la extensión.

Subimos el ZIP a la web y, tras unos segundos, observamos actividad en nuestro servidor:

Aquí se revela un nuevo dominio interno: browsedinternals.htb. Lo añadimos al archivo hosts.

Al acceder al dominio observamos la siguiente página:

Resultado:

Se trata de un Gitea. Al explorar los repositorios públicos encontramos uno interesante.

Escalate user larry

Arithmetic injection (RCE)

Revisando los archivos del repositorio observamos código en app.py y routines.sh. En concreto, se detecta una vulnerabilidad de Command Injection (Arithmetic injection) en el siguiente fragmento:

Problema:

  1. El parámetro rid se pasa directamente al script routines.sh

  2. En routines.sh se usa [[ "$1" -eq 0 ]] que espera un número

  3. Pero si pasas algo como $(comando) o ; comando, podría ejecutarse

Sabemos que este endpoint se ejecuta en localhost. Además, anteriormente observamos que la extensión realiza peticiones tanto al dominio como a localhost. Aprovechamos esto para cargar una extensión maliciosa que invoque el endpoint vulnerable y ejecute una reverse shell desde localhost.

Creamos los archivos necesarios para la extensión de ataque.

manifest.json

attack.js

Comprimimos la extensión:

Nos ponemos a la escucha:

Tras subir la extensión a la web y esperar unos segundos, recibimos la conexión:

Confirmamos acceso como el usuario larry.

Sanitización de shell (TTY)

Una vez estabilizada la shell, leemos la flag de usuario.

user.txt

Escalate Privileges

Si hacemos sudo -l veremos lo siguiente:

Podemos ejecutar extension_tool.py como root. Antes de explotarlo, analizamos su contenido.

Resultado:

SSH (Clave privada)

Antes de continuar, revisamos el directorio .ssh del usuario larry.

Encontramos una clave privada id_ed25519.

id_ed25519

La guardamos en nuestra máquina atacante como id_rsa, ajustamos permisos y nos conectamos por SSH.

Resultado:

Acceso SSH confirmado con una shell mucho más estable.

Python .pyc Poisoning

Siguiendo con el análisis anterior, al inspeccionar el código podemos identificar una vulnerabilidad conocida como Python .pyc Poisoning, presente en la siguiente línea:

Si es posible escribir en el directorio donde Python busca módulos, podemos inyectar nuestro propio código malicioso para que sea ejecutado en lugar del legítimo.

Al inspeccionar el directorio /opt/extensiontool/, observamos lo siguiente:

  • El directorio __pycache__ tiene permisos drwxrwxrwx (world-writable)

  • El archivo extension_utils.py es importado por el script principal y se ejecuta con privilegios de root

Python almacena bytecode compilado (.pyc) en el directorio __pycache__. Cuando un módulo es importado, Python verifica si existe un archivo .pyc con metadatos coincidentes (timestamp y tamaño). Si estos coinciden, Python ejecuta directamente el bytecode en lugar de recompilar el archivo .py.

Obtención de Metadatos del Archivo Original

El primer paso consiste en obtener el tamaño exacto y el timestamp del módulo legítimo, ya que necesitaremos replicarlos para que Python acepte nuestro archivo malicioso como válido:

Resultado:

Creación del Código Malicioso

A continuación, creamos una versión compacta del módulo original que incluye nuestro payload malicioso, manteniendo exactamente la misma interfaz de funciones (validate_manifest y clean_temp_files) para evitar errores en tiempo de ejecución:

Resultado:

Ajuste de Tamaño con Padding

Para engañar a Python, el archivo malicioso debe tener exactamente el mismo tamaño que el archivo original. Para ello, añadimos padding en forma de comentarios hasta alcanzar el tamaño objetivo:

Resultado:

Sincronización de Timestamps

Aplicamos el mismo timestamp del archivo original (1742727379) para que Python acepte el .pyc como válido durante el proceso de importación:

Resultado:

Compilación e Inyección

Una vez ajustado el archivo, lo compilamos a bytecode (.pyc) y lo inyectamos directamente en el directorio __pycache__, sobrescribiendo el bytecode legítimo:

Resultado:

Limpieza de Caches de Python

Para asegurarnos de que Python cargue el nuevo bytecode malicioso, limpiamos completamente los caches de importación:

Resultado:

Ejecución y Obtención de Root

Finalmente, al ejecutar el script con privilegios de root, nuestro código malicioso se ejecuta automáticamente:

Resultado:

Veremos que el archivo malicioso se ha creado correctamente.

Mecanismo del Ataque

  1. World-writable __pycache__: Los permisos excesivos permiten escribir archivos .pyc arbitrarios

  2. Python cache validation: Python confía en .pyc si coinciden tamaño y timestamp

  3. Module hijacking: Se sobrescribe el bytecode legítimo con código malicioso

  4. Privilege execution: El script se ejecuta como root, otorgando privilegios elevados al payload

Comprobamos la existencia del binario SUID:

Resultado:

Como se observa, el binario ha sido creado correctamente. Ahora lo ejecutamos con el parámetro -p para mantener los privilegios efectivos:

Resultado:

Con esto ya somos el usuario root, por lo que podemos leer la flag correspondiente.

root.txt

Last updated