Tuesday, October 13, 2015
ASIS Finals 2015
Kali ini team Rentjong mendapat peringkat 38 dengan 826 points
Write-up ada di github
https://github.com/rentjongteam/write-ups-2015/tree/master/asis-finals-2015
Monday, May 18, 2015
DEF CON QUALS 2015
https://github.com/rentjongteam/write-ups-2015/tree/master/def-con-quals-2015
ASIS Quals 2015
Sekarang ini untuk kemudahan, sebagian besar writeup akan dituliskan di git team rentjong. Dengan git, semua file pendukung bisa lebih mudah ditaruh di situ, gambar juga lebih mudah diupload.
Rencananya satu repository akan dibuat untuk satu tahun, link repository untuk writeup tahun ini:
https://github.com/rentjongteam/write-ups-2015/
Dan link untuk ASIS Quals:
https://github.com/rentjongteam/write-ups-2015/tree/master/asis-quals-2015
Monday, May 11, 2015
ASIS CTF 2015 - Keylead (Reverse 150)
Sunday, April 19, 2015
PNG Uncorrupt(Forensic150)
Kita diberikan sebuah file PNG dengan petunjuk:
We received this PNG file, but we're a bit concerned the transmission may have not quite been perfect.Dengan menggunakan pngcheck, kita bisa tahu apa salahnya file ini:
yohanes@ubuntu:~$ pngcheck corrupt_735acee15fa4f3be8ecd0c6bcf294fd4.png
corrupt_735acee15fa4f3be8ecd0c6bcf294fd4.png: CORRUPTED by text conversion
ERROR: corrupt_735acee15fa4f3be8ecd0c6bcf294fd4.png
Header PNG dirancang supaya kita bisa mendeteksi jika ada konversi ASCII ketika mentransfer file. Tapi sayangnya tidak membantu dalam hal recoverynya.
http://www.libpng.org/pub/png/pngintro.html
PNG supports three main types of integrity-checking to help avoid problems with file transfers and the like. The first and simplest is the eight-byte magic signature at the beginning of every PNG image. It will detect the most common type of file corruption: that due to the transfer of a binary file in text (or "ASCII") mode.Dalam kasus ini ketika kita lihat header PNG-nya, tidak cukup untuk memperbaiki headernya saja, karena di dalam data PNG (yang terkompresi), masih ada byte yang tadinya CRLF (0x0d 0x0a) berubah menjadi LF (0x0a). Masalahnya adalah: tidak semua 0x0a tadinya adalah (0x0d 0x0a). Contohnya seperti ini. Jika data asli adalah:
PNG's magic signature cleverly includes both a CR/LF pair and a single LF.
0x0a 0x01 0x02 0x0d 0x0a 0x02 0x0a
Maka setelah konversi CRLF:
0x0a 0x01 0x02 0x0a 0x02 0x0a
Kita tidak tahu 0x0a mana yang harus dikembalikan menjadi 0x0d 0x0a (bisa jadi ada beberapa 0x0a yang harus dikembalikan menjadi 0x0d 0x0a).
Bagaimana kita bisa mengembalikan byte-byte yang benar? file PNG disusun dalam bentuk chunk, seperti ini:
- Length (4 byte)
- Chunk Type (4 byte)
- Chunk Data (N byte, sesuai dengan length)
- CRC (4 byte, CRC sesuai algoritma di sini)
Data PNG ada dalam chunk IDAT, dalam file soal ada 10 IDAT yang sebagian besar corrupt. Perhatikan bahwa karena konversi CRLF, maka kita tidak bisa memparsing menggunakan LENGTH, karena datanya akan bergeser ketika CRLF berubah menjadi LF.
Kode yang saya pakai untuk menyelesaikan agak berantakan (Karena ini adalah CTF dan ini satu-satunya soal yang sempat saya selesaikan sebelum perjalanan panjang). Saya punya dua kode, pertama dalam python untuk mensplit PNG menjadi chunk IDAT, dan kode dalam C (supaya cepat) untuk memperbaiki CRC-nya.
Kedua kode ini sebenarnya bisa digabung supaya semuanya otomatis. Skrip python juga mengoutputkan HEADER dan FOOTER supaya bisa digabung lagi hasil akhirnya. Kelebihan menggunakan cara terpisah adalah: saya bisa copy chunk-nya ke komputer lain dan menjalankan perbaikan untuk chunk itu saja.
Bagian parsing IDAT dalam python hanya mencari string IDAT dan ditulis ke file:
Di situ saya juga memprint padding, berapa byte yang berubah dari yang seharusnya. Setelah tahu berapa byte yang berubah tiap blok, saya membuat program dalam C untuk memperbaiki chunk IDAT tersebut.
Cara perbaikannya adalah sebagai berikut: kita tahu berapa jumlah 0x0a (misalnya N) di dalam sebuah chunk IDAT (bisa dihitung dengan melihat bytenya), kita tahu berapa 0x0d0x0a yang berubah menjadi 0x0a (dari jumlah padding di skrip python, misalnya K), kita tahu CRC dari tiap blok IDAT.
Kita bisa mencoba-coba memilih kombinasi K dari N. Untuk IDAT tertentu, hanya 1 byte dari sekitar 400 byte yang perlu diubah (bisa dicoba-coba manual kalau rajin), untuk IDAT-4, ada 459 byte 0x0a, dan paddingnya 3, artinya ada lebih dari 16 juta kombinasi, tidak mungkin diperbaiki manual.
Berikut ini source saya untuk memperbaiki IDAT dengan mencoba semua kombinasi dan mengecek crcnya:
Setelah selesai, saya gabungkan lagi HEADER, IDAT, dan FOOTER-nya.
Hasilnya adalah gambar berikut:
flag{have_a_wonderful_starcrafts}
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.