Monday, March 23, 2015
BCTF 2015: torrent_lover
BCTF 2015: Experiment
Pertama kali membaca soal ini dan mencoba konek, sepertinya cukup mudah:
Sunday, March 1, 2015
Boston Key Party 2015: Riverside
Kita diberi file PCAP. Biasanya PCAP yang diberikan adalah dalam kategori jaringan, tapi kali ini dalam kategori USB. Dengan membuka file PCAPnya menggunakan wireshark, didapatkan bahwa benda yang dimaksud adalah sebuah USB Mouse.
Proses berikutnya adalah mencari tahu mengenai protol USB Mouse ini. Saya mendapatkan informasi dari dua URL ini:
http://wiki.osdev.org/Mouse_Input
http://www.usbmadesimple.co.uk/ums_5.htm
Setelah memahami protokolnya, saya mulai membuat decodernya dalam Python. Protokol mouse USB sangat mudah, byte pertama berhubungan dengan status tombol mana yang diklik, byte kedua dan ketiga menyatakan perpindahan koordinat relatif (x, y), dan byte terakhir menyatakan status scroll wheel (untungnya tidak dipakai di soal ini).
Untuk mengekstrak data dari PCAP saya menggunakan command line tshark:
tshark -r challenge.pcapng -Y "usb.transfer_type==0x01 && usb.endpoint_number.direction == 1 && usb.device_address==12 && usb.urb_type==URB_COMPLETE" -T fields -e usb.capdata > mousedata.txt
Saya memfilter hanya paket yang arahnya ke komputer, yang URB typenya URB_COMPLETE dan saya ambil datanya saja (4 byte untuk tiap transaksi).
Persoalannya adalah: apa yang dilakukan dengan USB mouse ini? apakah menggambar sesuatu? Ketika saya plot dengan program python saya, hasilnya seperti ini:
Saya menggambar gerakan mouse, dengan alternasi warna setiap kali setelah klik. Saya juga menggambar di mana posisi klik, ternyata dari gambar di atas bisa dilihat bahwa USB mouse tersebut digunakan untuk mengetik keyboard virtual.
Lebih jelasnya seperti ini (saya remove gerakan mousenya karena tidak penting):
Perhatikan bahwa itu berbentuk seperti keyboard. Dengan memperkirakan posisi keynya, didapatkan pesan:
the quick brown fox jumps ovver the lazy dog thekeyisiheardyoulikedsketchyetchingglastyear
Perhatikan bahwa ovver salah ketik (v terketik dua kali), ternyata bagian flagnya juga ada yang terketik dua kali (huruf g). Jadi flagnya adalah
iheardyoulikedsketchyetchinglastyear
(I heard you liked sketchy etching last year).
Source code solusinya:
Untuk Anda yang penasaran darimana saya tahu protokol USB, saya pernah mengimplementasikan remote control receiver USB berdasarkan library http://www.obdev.at/products/vusb/index.html
Boston Key Party 2015: Northeastern Univ
Soal berikutnya juga masih dalam kategori web
Source code bisa dilihat dengan mengklik pada Level3
Perhatikan bahwa perbandingan memakai strcmp. Salah satu sifat strcmp adalah: jika dibery array, maka akan mengembalikan kosong, yang jika dibandingkan dengan == (dua tanda sama dengan) akan memaksa PHP melakukan type juggling, dan hasilnya sama dengan 0. Bypass ini cukup mudah, cara standar: dengan menggunakan variabel array password[]=abc.
Boston Key Party 2015: Orient Heights
Soal ini sama-sama menerima sebuah message dan signaturenya, dan jika benar, maka kita akan diberi flagnya. Message dan signature tidak boleh sudah ada di daftar signature.
Perbedaan soal ini dengan soal sebelumnya adalah: data yang diterima oleh daemon adalah dalam bentuk ASN1 (soal Wood Island dalam bentuk JSON). ASN1 ini tidak memiliki coding yang unik, salah satu cara yang gampang adalah dengan mengencode ulang salah satu message yang sudah diterima dengan chunk size yang berbeda (saya memakai maxChunkSize=8).
Ada hal yang sedikit mengecoh: ada 3 message yang isinya sama (There is no need to be upset), tapi hanya sigs/sig343.txt yang bisa dipakai (ini dari hasil coba-coba).
Flagnya adalah: arent_you_glad_we_have_unique_encodings_now
Source code solusi;
Boston Key Party 2015: Haymarket
Contoh punched card seperti ini:
Untungnya sudah pernah ada soal semacam ini di CTF Lain:
http://meta.security.stackexchange.com/questions/1332/sigint-ctf-2013-starts-friday-5-july-1600-gmt-ended-including-write-ups
Solusi python bisa dipakai, hal yang perlu diganti hanya posisi koordinat dan warna, menjadi:
color = img.getpixel((15 + 7 * j, 20 + 20 * i))
if color == (20,20,20, 255):
Di tabel EBCDIC, entry pertama diganti supaya terlihat spasinya:
EBCDIC = {
'' : ' ',
Hasilnya beberapar baris terakhir seperti ini:
SET CHANGEDOOR TO FIRSTCHOICE. IF CHANGEDOOR = GOODDOOR DISPLAY 'MH: CONGRA
SETULATIONS! YOU FOUND A KEY.' DISPLAY 'MH: THE KEY IS:' DISPLAY 'KEY (
SETALEXTREBEKISASOCIALENGINEER)' ELSE DISPLAY 'MONTY HALL OPENS THE DOOR. A
Saya cuma pernah baca-baca soal COBOL waktu SMU dulu (dari buku Pengenalan Komputer oleh Jogiyanto), tidak pernah memprogram beneran, tapi saya ingat bahwa kolom di awal COBOL bisa diignore, dan sepertinya semua SET di depan perlu diignore (karena kalau tidak, tulisannya adalah CONGRASETULATION, bukan CONGRATULATION), dan ternyata flagnya adalah:
ALEXTREBEKISASOCIALENGINEER
Boston Key Party 2015: Sullivan Square
Soal ini termasuk soal sulit dlam kategori reversing dengan nilai 350. Soalnya:
ternyata kita diberi file dengan ekstensi rbc dan satu file dengan ekstensi dump. Setelah membaca-baca, ternyata rbc adalah file hasil kompilasi ruby dengan rubinius. Di soal disebutkan versinya adalah 2.5.2. Langkah pertama adalah menginstall dulu rubinius dengan mengcompile dari source codenya.
Pengetahuan Ruby saya sangat terbatas, jadi sebagian besar adalah dengan coba-coba saja plus logika sederhana.
Tapi sayangnya ketika dijalankan, hasilnya:
./run.sh
An exception occurred evaluating command line code:
/home/yohanes/trie/trie_harder.rbc (Rubinius::InvalidRBC)
Backtrace:
Rubinius::CodeLoader#load_compiled_file at kernel/delta/code_loader.rb:227
Rubinius::CodeLoader#load_file at kernel/delta/code_loader.rb:175
Saya tidak berhasil mencari tahu kenapa itu terjadi. Jadi terpaksa membaca sourcenya rubinius, ternyata masalahnya adalah kode versi dalam file RBC.
Di file yang didownload, headernya seperti ini:
!RBIX
10184465365783055646
Setelah saya compile program hello world, ternyata headernya:
!RBIX
17720602882280116705
Dengan mengganti 10184465365783055646 menjadi 17720602882280116705, hasilnya program bisa dijalankan:
Tampaknya tanpa source codenya, akan sulit menyelesaikan ini. Setelah mencoba-coba debuggernya rbx ( rbx -Xdebug -I.), ternyata ini pun sulit. Tapi saya mendapatkan beberapa info berharga. Saya tidak tahu di mana titik main eksekusi untuk breakpoint, jadi saya break saja di Object#puts
Ketika sampai main, saya lakukan “dis all”, dan hasilnya:
Seperti yang saya nyatakan sebelumnya: saya tidak terlalu mengerti Ruby, apalagi bytecodenya. Tapi karena sudah mengerti bytecode berbagai bahasa lain, saya bisa menebak bahwa kodenya kira-kira:
a = Marshal.load(File.read('trie.dump'))
Saya mencoba-coba mendump kelas trie, seperti ini:
Rubinius::CodeLoader.require_compiled 'trie'
a = Marshal.load(File.read('trie.dump'))
puts a.methods - Object.methods
puts "--"
puts a.private_methods - Module.private_methods
puts a.instance_variables
Ternyata kelas Trie ini cuma punya instance variable @root yang tipenya Trie.Node, kelas Trie.Node ini memiliki 6 instance variable:
[:@end, :@left, :@value, :@right, :@char, :@mid]
Karena jarang memakai struktur data Trie, saya baca lagi di wikipedia:
https://en.wikipedia.org/wiki/Trie
Berdasarkan deskripsinya, left, right, mid,end sudah jelas. Lalu value dan char bisa kita print saja. Setelah saya dump Trie-nya, hasilnya adalah teks yang tidak terbaca di bagian char, dan teks yang terbaca di bagian value, misalnya:
- “not the flag but a true statement ;)”
- “wow not this either”
- “nope lots of fake flags”
- “stop being such a n00b and get the flag”
- “1 c4n r34d th15 ju57 l1k3 x86 0r 3n6L15h!”
Tapi itu semua bukan flag. Saya lihat ada kelas cipher, tapi bagaimana cara kerjanya? membaca bytecodenya bisa pusing, jadi saya akali, pertama saya coba instansiasi langsung:
Cipher.new
Tapi:
method 'initialize': given 0, expected 1 (ArgumentError)
Berarti kelas ini perlu sebuah parameter, tapi saya tidak tahu apa. Jadi saya buatkan sebuah kelas pengganti Cipher:
rbx compile cipher.rb –o cipher.rbc
./run.sh
Hasilnya:
So, you can tell me now... what's the flag? 1
["K", "D", "w", "X", "H", "3", "e", "1", "S", "B", "g", "a", "y", "v", "I", "6", "u", "W", "C", "0", "9", "b", "z", "T", "A", "q", "U", "4", "O", "o", "E", "N", "r", "n", "m", "d", "k", "x", "P", "t", "R", "s", "J", "L", "f", "h", "Z", "j", "Y", "5", "7", "l", "p", "c", "2", "8", "M", "V", "G", "i", " ", "Q", "F"]An exception occurred evaluating command line code:
undefined method `encrypt' on an instance of Cipher. (NoMethodError)
Ternyata Cipher perlu dipanggil menggunakan tabel sebagai inputnya. Setelah dicoba, ada method decrypt, jadi ini saya pakai untuk mendump isi Trie.
Hasil dump yang menarik adalah:
N = WyXcXAFAp9F0Wc8FDHcveFypMWF288i
rmd1dy y0u tr13 be1ng m04r 2337
Saya tidak sempat mempelajari kenapa ada huruf “rm” dan “y” (stelah d1d), sepertinya itu adalah marker (mungkin “right”,”middle”) dan indikator (“yes”). Tapi dari tebakan saya, flagnya adalah: d1d y0u tr13 be1ng m04r 2337
Dan ternyata setelah dicoba di command line benar.
Source solusi (sorry jelek banget kodenya, ga pernah coding ruby in real life):
Boston Key Party 2015: Symphony
Ini adalah salah satu soal mudah yang berhubungan dengan PHP (25 poin):
Kali ini tidak ada pertanyaan user, hanya password:
Source codenya adalah:
Mudah sekali untuk membuat bilangan yang lebih besar dari 999 yang kurang dari 4 karakter, misalnya 9e6. Informasi ini bisa didapat dari membaca informasi tentang konversi string ke bilangan di PHP:
Boston Key Party 2015: Longwood Medical
Boston Key Party 2015: Wellington
Ini adalah soal reversing binary prolog dengan nilai 250 point.
Saya mengetahui bahwa binary ini adalah binary prolog dari:
- Soalnya yang menyatakan flagnya berakhiran dengan dot
- Binary mengandung string /usr/lib/gprolog-iso/bin
- Hasil disassembly ribet
Dulu saya adalah yang menyarankan dan melaksanakan supaya kelas prolog tidak memakai Turbo Prolog tapi lebih baik memakai GNU Prolog, dan sebagai admin, saya sempat mengeksplorasi GNU Prolog.
Soal ini mudah sekali diselesaikan dengan pemahaman prolog plus menggunakan ltrace. Dalam prolog, rule dan atom dibandingkan menggunakan strcmp (dan strlen untuk mengecek panjangnya).
ltrace –s 35 ./troll_log.4643d195d55746aa180abf7144909677 2>y
Kita memasukkan password “_.” yang akan match dengan rules/fact manapun (kita akan mendapat pesan WiN). Setelah itu kita bisa lihat di file lognya, misalnya baris-baris seperti ini:
strcmp("LOSE", "i_should_have_used_askhell_instead") = -29
Dan itulah flagnya: i_should_have_used_askhell_instead. (seperti petunjuk, flag berakhiran dengan titik).
Boston Key Party 2015: Wood Island
Soal ini nilainya 150 dalam kategori Crypto, soalnya seperti ini:
Kita diberikan source code dalam Python. Intinya adalan: program ini menerima signature dan message, dan akan membalas dengan flag jika signature dan message sudah benar. Kita juga diberi contoh signature dan message yang sudah pernah dikirimkan ke server ini. Server ini tidak akan menerima jika message/signature adalah duplikat dari yang di file sigs.txt.
Bagian terpenting adalah baris-baris berikut:
sig = json.loads(sig)
Kemudian berikut ini pengecekan yang dilakukan:
if "r" not in sig or "s" not in sig or "m" not in sig:
self.request.close()
return
r = sig["r"]
s = sig["s"]
m = sig["m"]
if not elgamal_verify(r, s, m):
self.request.close()
elif is_duplicate(sig):
self.request.close()
elif m != "There is no need to be upset":
self.request.close()
else:
self.request.sendall(FLAG)
self.request.close()
Dan caranya mengecek duplikat adalah dengan:
def is_duplicate(s):
return s in DUPLICATES
Perhatikan bahwa karena formatnya JSON kita bisa menambahkan field lain, dan dengan menambahkan field lain maka apa yang kita kirimkan tidak akan dianggap duplikat. Untuk mencegah orang melakukan brute force, maka server meminta "proof of work" yang meminta kita mencari string 20 karakter (X) dengan prefix 12 karakter yang diberikan, sedemikian sehingga sha1(X) berakhiran dengan 3 heksadesimal ff. Saya memakai cara sederhana brute force dengan menambahkan angka (kadang ini tidak berhasil, jadi perlu diulangi, kadang berhasil dalam sedetik, karena hanya butuh masuk sekali, maka tidak saya optimasi). Berikut ini solusinya.
Ketika dijalankan:
Boston Key Party 2015: Prudential
Ini masuk dalam kategori soal sederhana:
Dengan Login/Password standar:
Source code yang diberikan:
Solusinya menggunakan variabel array lagi. Ketika dibandingkan secara string name[]=a dan password[]=b akan dianggap tidak sama. Jika dilakukan SHA, hasilnya sama-sama kosong.
Boston Key Party 2015: Park Street
Soal ini nilainya hanya 10 point, jadi sangat mudah:
Dengan search google:
Jadi flagnya adalah: OFPFC_ADD
Boston Key Party 2015: Museum Of Fine Arts
Berikut ini soalnya:
Kali ini formnya bukan login/password, tapi angka dengan input:
$ php cracker.php 9377306 8039203 8723770
2251254
Seed yang dipakai oleh kode tersebut kemungkinannya sangat kecil (kurang dari 20 rb kemungkinan), jadi mudah dibrute force.
Dari mana saya tahu ini? Di bagian seed ada mod (operator %) rand(1, 10000) plus rand(1,10000). Andaikan rand pertama dan kedua hasilnya sama-sama 10000, maka nilainya max adalah 20000, andaikan keduanya hasilnya 1 dan hasil XOR-nya 0, maka minimum seednya adalah 1.
Cara memakainya:
$ php cracker.php 9377306 8039203 8723770
2251254
Jika kita bisa menebak angka berikutnya maka hasilnya adalah flagnya:
Boston Key Party 2015: Brigham Circle
Deskripsi soalnya:
Setelah diklik:
Ketika level 6 diklik, muncul source codenya:
Cara bypass ereg cukup mudah, tambahkan saja “% 00”, jadi querynya ?password=a% 00--
(harusnya tanpa spasi, entah kenapa kalau tanpa spasi, terremove oleh blogger, padahal %01 %02 gpp ) Dan hasilnya
Masalah ereg dengan ini adalah bug yang dianggap bukan bug.