[Cyber Apocalypse CTF 2021] – emoji voting

Diberikan sebuah web dan source code.

Web berisikan fungsi untuk melakukan vote terhadap emoji-emoji. Tidak ada yang menarik sejauh ini. Mari kita lihat apa yang dikirim saat melakukan vote.

Saat melakukan vote, main.js akan dipanggil dan mengirim data tertentu. Berikut isi dari main.js.:

Ada potongan code yang menarik. Yakni pada bagian saat memanggil API /api/list.

Dapat dilihat bahwa saat mengirimkan data ke API, data yang dikirim berupa static string count DESC. String ini terlihat seperti bagian dari sebuah query. Mari kita lihat apa saja isi source code soal bagian backend.

Pada bagian database.js, terdapat celah SQL Injection pada bagian fungsi getEmojis.

Input user yang diterima oleh program, akan diproses ke dalam query tanpa prepared statement. Lalu dari fungsi migrate, kita bisa mengetahui struktur database yang ada.

Flag berada di table flag_ yang diikuti oleh 5 random bytes yang di ubah menjadi hex yang berarti akan ada 10 karakter tambahan di belakang tulisan flag. Dari sini, langkah eksploitasi kita sudah jelas:
– Lakukan SQLite Injection untuk mendapatkan nama lengkap dari table flag.
– Lakukan SQLite Injection untuk mendapatkan flag dari table flag.

Dari hasil pencarian di google, pada link disebutkan kalau akan melakukan SQL Injection pada ORDER BY, akan berbeda dari melakukan SQL Injection pada umumnya. Proses dapat dilakukan dengan menggunakan sebuah kondisi dimana jika query yang kita masukkan menghasilkan TRUE maka akan di ORDER BY oleh suatu kolom, dan jika salah juga akan di ORDER BY oleh suatu kolom. Jadi pada soal ini, kita berhadapan dengan Blind SQLite Injection untuk mengambil data dari database.

Berikutnya, kita construct payload untuk injection. Ini payload yang digunakan:

(CASE WHEN(SELECT UNICODE(SUBSTR(tbl_name,5,1))FROM sqlite_master WHERE type=’table’ AND tbl_name LIKE ‘flag%’)=60 THEN name ELSE count END) ASC -> Mendapatkan nama table

(CASE WHEN(SELECT UNICODE(SUBSTR(flag,1,1)) FROM flag_<random_string>)={} THEN name ELSE count END) -> Mendapatkan flag

Payload yang digunakan untuk mendapatkan nama table dan flag mirip. Berikut penjelasan tiap syntax yang digunakan:
– CASE = Fungsi untuk membuat sebuah cek kondisi terhadap query didalamnya. Kondisi sama seperti IF-THEN-ELSE.
– WHEN = Tempat memberikan query sebagai kondisi.
– SELECT = Mengambil bagian apa dari database.
– UNICODE = Mengubah string menjadi ASCII value.
– SUBSTR = Memecah string SUBSTR(‘string yang mau dipecah’, index mulai, berapa karakter yang ingin diambil).
– FROM = Mengambil dari table apa.
– WHERE = Kondisi pada query.
– LIKE = Mengambil data dengan pattern yang ditentukan.
– ASC = Mengurutkan hasil secara ascending.

Mengapa pada query untuk mengambil nama table pada statement LIKE tidak menggunakan flag_ padahal di source code sudah ada informasinya? Karena _ pada SQLite di LIKE statement akan dianggap sebagai wildcard untuk 1 karakter. Penjelasan dapat dilihat pada link.

Mari kita uji coba payload ini pada server soal. Percobaan pertama adalah query salah yang menyebabkan hasil request di sort berdasarkan count.

Lalu percobaan kedua adalah query dengan hasil benar yang menyebabkan hasil request di sort berdasarkan name.

Injection berhasil. Kita mendapatkan working payload. Berikutnya, jika kita melakukan injection sebanyak ini untuk mendapatkan nama table flag dan flag, maka akan memakan waktu lama. Oleh karena itu, kita membuat sebuah script Python untuk automate proses SQLi. Berikut script yang digunakan:

Berikut hasil yang didapat dari dijalankannya script:

Flag: CHTB{order_me_this_juicy_info}

Leave a Reply

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