Writeup CTFR Input Berhadiah

Khairu Aqsara Sudirman

Khairu Aqsara Sudirman

Apr 04, 2021 — 6 mins read

Diberikan sebuah service dengan alamat 103.157.96.13 pada port 7790, dimana setiap kita menginputkan sesuatu response dari server dalam bentuk ter-enkripsi. disini kita harus mencari tau maksud dari respon tersebut. Untuk dapat menyelesaikan challenge ini, dibutuhkkan beberapa informasi dasar, seperti bentuk respons nya, panjang respon dan jenis enkripsi yang digunakan.

Sejauh ini informasi yang bisa didapatkan

1. Respon dalam hexadecimal
2. panjang respon tergantung panjang inputan terkadang 120 terkadang 160 terkadang > 160

jika input yang diberikan sepanjang 1 karakter (karakter terserah) respon sepanjang 128 karakter, misalnya inputan berupa huruf A, respon akan sepanjang 160 karakter, bila inputan yang diberikan huruf B respon akan tetap sepanjang 160 karakter, tetapi 32 Digit pertama sama dengan 32 Digit respon dengan inputan A, 32 Digit berikutnya akan berbeda, sisnya sampai Digit terakhir sama dengan respon bila inputan sama dengan A, hal ini berlaku jika panjang inputan sama dengan 1 karakter, Hal ini berlaku jika inputan dengan panjang yang sama diinputkan lagi.

Yang tidak bergaris merah merupakan hasil yang berbeda

Yang tidak bergaris merah merupakan hasil yang berbeda

Dari hasil analisis tersebut bisa diambil kesimpulan jika respon merupakan enkripsi dengan blok-blok tertentu, karena ada beberapa blok yang sama(identik) dengan inputan yang berbeda-beda, model enkripsi yang menggunakan blok-blok umumnya dikenal dengan nama Block Cipher, karena pattern pada bloknya terdapat blok yang identik dengan inputan yang berbeda-beda bisa dipastikan ini merupakan ECB atau Electronic Code Book

Pendekatan yang paling sederhana adalah dengan dengan meng-enkrip/dekrip setiap blok tersebut sendiri-sendiri, secara independen. Blok satu dan blok yang lain tidak ada hubungannya dan diproses sendiri-sendiri. Mode operasi yang seperti ini disebut sebagai mode ECB (electronic code book).

Apa yang terjadi bila Plaintext 1 dan Plaintext 2 isinya sama ? Karena dalam algoritma block cipher semua blok menggunakan kunci yang sama, tentu saja bila plaintext blok 1 dan plaintext blok 2 identik akan menghasilkan ciphertext blok 1 dan ciphertext blok 2 yang juga identik. Ini adalah kelemahan mode ECB, bila ada blok-blok plaintext yang identik, maka ciphertextnya akan identik juga sehingga akan memperlihatkan pola yang mudah dilihat dalam ciphertext

Kelemahan mode EBC ini akan terlihat jelas ketika meng-enkrip dokumen/data yang memiliki banyak data yang sama seperti gambar yang biasanya memiliki banyak deretan pixel yang warnanya sama. Pada gambar di atas (gambar wikipedia), karena banyak area yang warnanya sama seperti latar putih, warna hitam dan kuning yang luas, membuat file gambar tersebut ketika dipotong-potong akan mempunyai banyak blok yang identik. Mode ECB bahkan tidak bisa menjamin confidentiality karena gambar pinguinnya masih terlihat jelas setelah dienkripsi.

Kelemahan ini adalah kelemahan mode operasi, bukan algoritma enkripsinya. Jadi sekuat apapun algoritma enkripsinya, bila dioperasikan dalam mode ECB, hasilnya juga akan mengandung kelemahan yang sama (blok plaintext identik menghasilkan blok ciphertext identik).

Sejauh ini informasi sudah cukup lengkap, langkah akhir adalah mengexploitasi kelemahan dari ECB itu sendiri, untuk itu harus mencari tau dulu ukuran bloknya, mencari offset padding dan melakukan padding attack pada service tersebut.

saya membuat sebuah program dengan python untuk melakukan padding attack pada service tersebut, script ini tidak sempurna, karena perlu dijalankan berkali-kali dan mengganti blok yang akan dicari secara manual, yang ada pada bagian num_padding=15 serta pada bagian if hasil[4] == padding[4]: untuk membandingkan hasil setiap bloknya, cara ini memang tidak efisien dan jauh dari kata bagus, tapi who care as long as the challenge can be solved right ?

from pwn import *
from string import printable
blok_size = 32
def split_len(seq):
    return [seq[i:i+blok_size] for i in range(0, len(seq), blok_size)]

def find_diff(response, first_response):
    if response[2] == first_response[2]:
        return True
    else:
        return False

def cari_blok(response):
    new = []
    for i in range(0, len(response), blok_size):
        new.append(response[i:i+blok_size])
    return new

def cari_panjang_blok():
    known_byte = list()
    blok_awal = 8
    while True:
        con = remote('103.157.96.13',7790)
        con.recvuntil("Input: ")
        patokan = ''
        log.info("Mencari Blok Awal....")
        data = 'a' * (blok_awal -len(known_byte))
        data_length = len(data)
        con.sendline(data)
        res = con.recvuntil('\n')
        res = res.decode()
        res = res.replace('Input: ','')
        res = res.replace('\r\n','')
        res_length = len(res)
        blok = split_len(res)
        if res_length == 128:
            patokan = blok[1]
        elif res_length == 160:
            patokan = blok[2]
        log.info(str(blok))
        log.info("Panjang : {}".format(str(res_length)))
        log.success("Patokan : {}".format(patokan))
        printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&()*+,-./:;<=>?@[]^_`{|}~'
        for c in printable:
            pading_data = 'a' * (blok_awal - len(known_byte)) + ''.join(known_byte) + c
            print("Mencoba Karaketer {}".format(pading_data))
            con.sendline(pading_data)
            res = con.recvuntil('\n')
            res = res.decode()
            res = res.replace('Input: ','')
            res = res.replace('\r\n','')
            respon_blok = split_len(res)
            log.info(str(respon_blok))
            if patokan in respon_blok:
                log.success("Karakater ditemukan")
                log.success("Bloknya : {}".format(valid_check))
                print("Karakater : {}".format(hex(ord(c))))
                known_byte.append(c)
                break
        print(known_byte)
        if len(known_byte) > 8 :
            break
        con.close()
    print(known_byte)

def testing():
    printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&()*+,-./:;<=>?@[]^_`{|}~'
    dapet=''
    con = remote('103.157.96.13',7790)
    con.recvuntil("Input: ")
    data = 'B' * 44 + 'A' * 16 * 2
    con.sendline(data)
    res = con.recvuntil('\n')
    res = res.decode()
    res = res.replace('Input: ','')
    res = res.replace('\r\n','')
    blok_awal = split_len(res)
    print(len(res))
    print(str(blok_awal) + '\t' + data)
    num_padding = 15 # 15 # 3163
    know_char = 'C' 
    if blok_awal[2:-3][-2:][0] == blok_awal[2:-3][-2:][1]:
        while 1:
            if len(know_char) >= 39:
                break
            padding = sendData(con, 'B' * 44 + 'A' * (num_padding - len(know_char)))
            for i in printable:
                hasil = sendData(con, 'B' * 44 + 'A' * (num_padding - len(know_char)) + know_char + i)
                if hasil[4] == padding[4]: # 4 5 7
                    know_char+=i
                    print(i)
                    break
                else:
                    print("----{}".format(i))
    else:
        print('NOPE')
    print(know_char)
def sendData(con, data):
    con.sendline(data)
    res = con.recvuntil('\n')
    res = res.decode()
    res = res.replace('Input: ','')
    res = res.replace('\r\n','')
    blok = split_len(res)
    log.info(''.join(blok))
    log.success(res)
    return blok
testing()

Saat dijalankan pertama kali hasilnya seperti berikut

num_padding = 15 dan padding[4]

num_padding = 15 dan padding[4]

dengan mengganti variable num_padding=31, know_char = 'CTFR{n4m4ny4_0' dan padding[5] kemudian dijalankan kembali, saya mendapatkan hasil

num_padding=31 dan padding[5] serta know_char = 'CTFR{n4m4ny4_0'

num_padding=31 dan padding[5] serta know_char = 'CTFR{n4m4ny4_0'

terakhir dengan mengganti num_padding=63 , know_char = 'CTFR{n4m4ny4_0r4cl3_p4dd1n9_4tt4' serta if hasil[7] == padding[7] hasilnya adalah

untuk lebih jelasnya bisa dilihat pada video amburadul dibawah

Untuk lebih memahami cara kerja Padding Oracle Attack dan ECB teman-teman bisa membaca tulisan mas Rizki Wicaksono dari Ilmu Hacking serta Tulisan Zach Grace tentang Exploitasi ECB, pasti teman-teman punya cara yang lebih simple untuk menyelesaikan challenge ini.

cryptography programming ctf Reverse
Read More

Writeup CTFR Kalkulasi PHP 1 Dan 2

Diberikan sebuah service pada alamat 103.157.96.13 pada port 7791 yang dibangun menggunakan php dengan fungsi melakukan perhitungan aritmatika dasar seperti tambah, kurang, bagi, perkalian dan lain-lain, sesuai petunjuk yang diberikan, kita diharuskan mengganti value variable $admin agar menjadi CTFR, pada tahap ini kita bisa menginputkan nilai-nilai aritmatika seperti 5+3 hasilnya akan 8, (4+4)*2=16 dan lainya, jika diberikan input berupa huruf akan mendapatkan respon berupa Tidak diizinkan huruf!, tetapi mengijinkan inputan berupa ()[^?], artinya kita harus merubah value dari variable $admin menjadi CTFR dengan memanfaatkan simbol-simbol aritmatika yang di-izinkan. beberapa contoh inputan yang dicoba

Read More

Writeup CTFR Warna Warni

Dari deskripsi challenge nya terdapat informasi "maksimal 127" dan kita diberikan satu gambar yang isinya warna acak (noise) yang tidak beraturan, jadi bisa dipastikan jika flagnya ada dalam pixel warna gambar, karena ada hint maksimal 127 jadi kita mengambil semua warna RGB, saya mencoba mengambil semua pixel pada masing-masing warna seperti RG dan B yang nilainya lebih kecil dari 127 dan merubahnya menjadi karakter, asumsinya angka pada pixel adalah ordinal dari sebuah karakter, setelah mencoba-coba karakter yang bisa terbaca ada pada pixel R (Red)