[TAMUctf18]: Shells – Buffer Overflow + Return Oriented Programming

Challenge (binary file) dapat didownload dari link berikut.

Hal yang biasanya saya lakukan sebelum mengerjakan atau menjalankan program adalah mengecek detail binary file dengan cara memasukkan command file <file_name> , dan kita juga dapat melihat security dari file tersebut dengan memasukkan command checksec <file_name> pada terminal. untuk challenge ini, ketika saya melakukan pengecekan tersebut maka yang terlihat adalah sebagai berikut :

Terlihat bahwa settingan security yang digunakan adalah RELRO default, tanpa stack canary (stack protector), NX disabled (stack dapat mengeksekusi perintah yang kita berikan dalam inputan), dan no PIE (susunan bagian .text tidak diacak).

Setelah itu, saya menjalankan program.  Program ini menampilkan output berupa tulisan-tulisan dan sebuah nomor yang aneh, dan setelah itu meminta inputan dari user lalu program tersebut akan mengoutput inputan yang telah kita masukkan sebelumnya.

Karena kita masih belum mengetahui jelas apa yang sebenarnya program ini lakukan maka kita akan melihat pseudocode dengan cara mereverse menggunakan IDA.

Dapat kita lihat dari potongan code dari fungsi main(), setelah program mengoutput tulisan, program memanggil function bernama echo(). Dan ketika kita melihat ke dalam function echo ternyata nomor aneh yang tadi merupakan sebuah alamat memori. Hal ini dapat kita ketahui karena program melakukan printf dengan format %p yang dimana %p itu merepresentasikan sebuah format string pointer (memory address). Untuk saat ini, kita belum mengetahui sebenarnya apakah memory yang ditunjuk tersebut.

Setelah itu function echo() akan meminta inputan dan menaruh buffer tersebut ke dalam sebuah array buffer.

Dari potongan code di atas, terlihat ada sebuah bug (kode yang lemah) yang bisa kita manfaatkan yaitu pada gets(s). Ketika gets meminta inputan dengan syntax tersebut, gets tidak mengecek total karakter yang kita input dan langsung menerima semua inputan kita ke dalam memory dan apabila kita menginput lebih dari array yang disediakan, maka kita dapat melakukan overwrite (menimpa) variable-variable, bahkan return point dari sebuah program (teknik stack buffer overflow). Kelemahan ke-2 adalah program masih memiliki stack yang dapat mengeksekusi code (NX Disabled). Ketika dalam inputan kita melakukan overwrite kepada instruction pointer dengan sebuah code, maka pointer tadi akan dengan senang hati melakukan return terhadap kode yang telah kita input tadi.

Jadi konsep dan skenario yang mestinya kita lakukan nanti untuk melakukan exploit adalah

  • Melakukan buffer overflow hingga kita sampai pada instruction pointer,
  • Menginput code yang dapat mengendalikan instruction pointer agar kita dapat melakukan Remote Code Execution (melakukan input command terhadap terminal melalui sebuah program lain).

Kita sudah mendapatkan beberapa clue mengenai hal-hal yang akan kita lakukan untuk mengeksploitasi program ini,tap kita masih menyisakan beberapa misteri yaitu :

  • Bagaimana cara kita mengetahui batasan dari array buffer tersebut?
  • Apakah bagian memory yang ditunjuk oleh nomor random teresbut?

Untuk menjawab hal tersebut, kita akan melakukan debug dengan gdb.

Pertama-tama, kita melakukan disassemble terhadap function echo() karena kita tahu bahwa function itulah yang membuat program kita menjalankan gets untuk meminta input. Lalu kita memberikan breakpoint (semacam tanda ketika program sudah menjalankan breakpoint kita, maka program akan berhenti dan dapat kita debug) pada bagian leave dari function tersebut yang berada tepat sebelum return untuk melihat posisi inputan kita dalam memori.

Saya akan menginput banyak A agar mudah mengetahui letak huruf A tersebut dalam memori.

Setelah program sampai ke breakpoint, Kita dapat melihat isi dari memori dengan cara melakukan command x/64x $esp yang berarti kita akan mengecek isi dari 64 byte memory di bawah register esp(esp menunjuk ke top of stack) dalam bentuk bilangan hex.

 

Terlihat ada 0x41 yang beberapa kali terlihat dan jika kita lihat, 0x41 adalah sebuah angka dalam hex yang merepresentasikan huruf ‘A’. Dapat kita hitung alamat sesungguhnya dari ‘A’ dalam memori. 0xffffd268 + 0x2( muncul pada byte ke 2 )    0xffffd26a. Dan jika kita lihat kembali ke nomor aneh di atas, ternyata nomor tersebut juga menunjukkan angka 0xffffd26a.

Sekarang setelah kita mengetahui bahwa angka tersebut adalah posisi awal inputan kita dalam memori, kita hanya perlu mengetahui offset ( max array ) dari buffer tersebut. untuk mengetesnya, kita dapat menggunakan comamnd pattern agar kita dapat secara otomatis melakukan generate atas inputan yang banyak dengan command pattern create <jumlah byte> <file_name>, dan dapat secara otomatis langsung mengetahui offset dengan command pattern offset $eip (eip adalah instruction pointer yang menjadi goal kita agar kita dapat melakukan execute terhadap code yang akan kita buat).

saya menggunakan pattern create 500 patterns lalu melakukan run < patterns dan program mengalami sigsev ( segmentation fault). ketika dicek menggunakan pattern offset $eip maka yang muncul adalah

Terlihat offset menuju $eip sebesar 242, sehingga kita butuh menginput code+padding sebesar 242 byte. Sekarang kita dapat membuat exploitnya, saya menggunakan bantuan pwntools untuk mengerjakan exploit ini karena pwntool dapat membuat exploit code kita langsung berinteraksi dengan program, selain itu kita juga dapat melakukan unpacking memory address dalam bentuk endian baik little atau big, baik 32 bit atau 64bit, dan juga bisa crafting shellcode dengan pwntool.

dan ketika exploit code dijalankan maka kita akan berhasil melakukan RCE terhadap local machine kita sendiri.

Sebenarnya kita hanya perlu mengganti r=process(“./ctf/shells”) menjadi r=remote(“pwn.ctf.tamu.edu”, 4323) agar dapat mengexploit remote service, namun karena sudah down, maka saya hanya memberikan image dari keberhasilan atas remote exploitnya

gigem{n0w_w3_4r3_g377in6_s74r73d}

Leave a Reply

Your email address will not be published. Required fields are marked *