[HackToday 2018] – nullflag

nullflag (1 solve)

Deskripsi:

Maybe it’s funny if shorter

Soal ini solved atas dasar asumsi bahwa program dijalankan pada Ubuntu 16.04 dengan libc-2.23-x.so (x merupakan sub-versi dari libc-2.23; note: setiap versi memiliki offset library yang berbeda).

Diberikan sebuah binary:

Ini terlihat seperti skenario buffer overflow biasa.

Berikut adalah disassembly  dari program.

Init hanya digunakan untuk mematikan buffering.

Jika kita lihat, pada fungsi vuln ini memiliki kelemahan buffer overflow. Namun kita hanya dapat menggunakannya untuk menulis return address (dan tidak lebih dari itu).

Langkah pertama adalah memastikan control atas payload; dengan kata lain, menulis payload kita ke tempat yang kita ketahui. Berikut adalah snippet intro:

Dengan ini kita dapat menuliskan payload di alamat (0x601900-0x70), karena jika kita lihat, alamat di bawah rbp hanya melakukan read berdasarkan address relatif ke rbp (variable lokal). Dengan ini kita dapat menuliskan payload kita (langsung tanpa overflow).

 

Pertanyaannya adalah, “tanpa libc, bagaimana caranya kita dapat memanggil system(“/bin/sh”) ?” Jawabannya adalah ret-to-dl-resolve.

Pada setup “Partial RELRO“, jika kita memanggil fungsi libc untuk pertama kali, fungsi akan memasukkan relocation offset ke stack dan linker akan melakukan perhitungan alamat berdasarkan relocation offset.

Singkatnya, kita perlu memanggil _dl_runtime_resolve dengan beberapa hal dibawah kendali kita:

  1. versi libc yang tidak spesifik atau NULL
  2. relocation offset
  3. PLT relocation slot
  4. string table (dan offset ke string table)

Jika ketiga hal di atas dipenuhi, dan string table berisi pointer ke “system”, maka linker akan menghitung dan membawa kita ke system dengan parameter yang sudah kita simpan sebelum _dl_runtime_resolve.

Kita perlu alamat dari link map supaya kita dapat mengosongkan libc version. Binary ini punya fungsi puts, yang dapat digunakan untuk menulis alamat link map ke stdout.

Dengan ini kita dapat memanjangkan payload kita (dari yang maximum hanya 0x70 bytes). link map tidak dapat keluar dalam sekali puts, sehingga puts dipanggil dua kali. Kemudian kita pivot stacknya ke tempat dimana payload kita mulai (dari pop rsi).

Kita harus kembali ke main karena kita butuh waktu untuk menerima alamat link map, Kita cukup masukkan payload kita lagi ke dalam buffer, perpanjang payload, dan kita pivot stack ke tempat di mana payload kita berada.

Ini adalah bagian terakhir dari payload. Kita mengosongkan versi libc (ini terletak pada alamat link map+0x1c8) terlebih dulu, untuk menghindari validasi tambahan. Kita memasukkan pointer ke “/bin/sh” ke rdi, setelah itu memanggil _dl_runtime_resolve dengan relocation offset yang sudah terhitung (melalui “roputils.rop”). Dibawah string “/bin/sh”, saya menambahkan payload sendiri berdasarkan data yang terbentuk melalui “rop.dl_resolve_data”. Kita butuh sebuah pointer karena jika tidak, fungsi lookup akan crash karena null pointer dereference. Selanjutnya adalah relocation_info. Kita perlu memasukkan offset relocation (offset << 20) beserta tipe relocation (PLT = 7). Setelah itu terdapat offset ke string table kita (yang ada “system”). Yang terakhir adalah string “system” itu sendiri.

Sebelum fungsi lookup, dengan string table berisi “system”:

Pada saat _dl_runtime_resolve melakukan return ke system:

Pada saat pengetesan ke remote / service:

Saya beruntung dan mendapat flagnya (yang artinya asumsi awal itu benar).

Exploit script:

 

Leave a Reply

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