Gemastik 2019 Final - Crypto

BerAESnang-senang

Diberikan file s34cret.py dan servis ke min4tozaki.me 31000.

Challenge

Kami memodifikasi kode program s34cret.py agar mempermudah memahami implementasi enkripsi AES. Berikut hasil modifikasinya.

from Crypto.Cipher import AES
import sys
import os

key = os.urandom(16)
iv = os.urandom(16)
msg = "-isi pesan member TWICE-deomkicer"
msg = "A"*32
i = 0

class Unbuffered(object):
    def __init__(self, stream):
        self.stream = stream

    def write(self, data):
        self.stream.write(data)
        self.stream.flush()

    def writelines(self, datas):
        self.stream.writelines(datas)
        self.stream.flush()

    def __getattr__(self, attr):
        return getattr(self.stream, attr)

sys.stdout = Unbuffered(sys.stdout)

def pad(msg, v):
    if len(msg) % 16 != 0:
        msg = msg + str(v + 5) * ((16 - len(msg) % 16) - 1)
    else:
        msg = pad(msg + str(v + 5), v)
    return msg

def cpadding():
    padding = os.urandom(16)
    return padding

def encryptSenang_senang(iv, key, plain, v):
    cipher = AES.new(key, AES.MODE_CBC, iv)
    print plain + str(v)
    return (iv + cipher.encrypt(plain + str(v))).encode('hex')

print """
    Selamat datang di Gemastik 12
    Selamat bersenang-senang!
    (https://min4tozaki.me)
    Jangan aneh-aneh ya
"""

print "Senang-senang v" + str(i), ":"
print encryptSenang_senang(iv, key, pad(msg, i), i)
i += 1

while 1:
    print """
        Menu:
        1. Tebak Senang-senang v0
        2. Senang-senang v""" + str(i) + """
        3. Keluar
    """
    p = raw_input('Pilih : ')
    if p == '1':
        flag_f = raw_input("Input Senang-senang v0 : ")
        try:
            if flag_f == msg:
                print '\nSelamat!!!'
                print 'flag : gemastik12{' + msg +'}'
                exit(1)
            else:
                print 'S4d :('
        except:
            exit(1)
    elif p == '2':
        new_msg = raw_input("Enkrip Senang-senang v"+ str(i) +" : ")
        try:
            print "\nSenang-senang v" + str(i), ":"
            print encryptSenang_senang(iv, key, pad(new_msg, i), i)
            i += 1
        except:
            exit(1)
    elif p == '3':
        exit(1)
    else:
        exit(1)

Solution

Setelah dianalisis, pilihan kedua yang disediakan oleh servis memungkinkan kita untuk mengenkripsi string bebas dengan key dan IV yang sama, sehingga kita bisa mengimplementasikan known-plaintext attack pada kriptosistem ini.

Langkah pertama, recover intermediate blocks dengan cara gunakan operasi XOR antara ciphertext dan plaintext (kami gunakan huruf A sebanyak 44 karakter sebagai plaintext dummy), berikut kode programnya.

blocks = []
while c:
    blocks.append(c[:32])
    c = c[32:]
print blocks

inter = []
for i in blocks:
    inter.append(xors('A'*16, i.decode('hex')))
print inter

Langkah kedua, recover plaintext asli pada servis. Hal ini dapat dilakukan bila intermediate blocks sudah didapat secara menyeluruh. Kita dapat melakukan recover dengan menggunakan operasi XOR antara ciphertext asli dan intermediate blocks.

Implementation

def xors(a, b):
    res = ''
    for i in range(len(a)):
        res += chr(ord(a[i]) ^ ord(b[i % len(b)]))
    return res

def getiv(enc):
    iv = enc[32:64]
    enc = enc[96:]
    pesan = enc[:-32]
    return iv, pesan

enc = '8c6cde6fec14f9672d1d7bfa19be5055dbdbe6291d392102c7ef4ff595963e61345de9a61128cdbc4d6af5cfb707e4ea175d8985cc0eaa7ba6580182d8fd016bed45c0842c36f947b657239b1c4028ee323f4e87754f0eb077f2677afa46951f815c07f9857c89ee7d093a8ff58c00b5'
iv, pesan = getiv(enc)
c = iv+pesan

blocks = []
while c:
    blocks.append(c[:32])
    c = c[32:]
print blocks

inter = []
for i in blocks:
    inter.append(xors('A'*16, i.decode('hex')))
print inter

enc = '1d70da1eadb566202f9e6cc4cc30cab4dbdbe6291d392102c7ef4ff595963e6116e40aad380ed4ad62ac2cdad15fd3fc6259fd9bbd298965d37517f7e0891f47986fc49a0032e760b2252e8568715acc424a43f3013b7ac40386130ef945961ee07c825a525ffb06259bfd3dca768ba5'
iv, pesan = getiv(enc)
c = iv+pesan

blocks = []
while c:
    blocks.append(c[:32])
    c = c[32:]
print blocks

flag = []
for i in range(len(inter)):
    flag.append(xors(blocks[i].decode('hex'), inter[i]))
print flag
$ python rsa-sad.py
['dbdbe6291d392102c7ef4ff595963e61', '175d8985cc0eaa7ba6580182d8fd016b', 'ed45c0842c36f947b657239b1c4028ee', '323f4e87754f0eb077f2677afa46951f']
['\x9a\x9a\xa7h\\x`C\x86\xae\x0e\xb4\xd4\xd7\x7f ', 'V\x1c\xc8\xc4\x8dO\xeb:\xe7\x19@\xc3\x99\xbc@*', '\xac\x04\x81\xc5mw\xb8\x06\xf7\x16b\xda]\x01i\xaf', 's~\x0f\xc64\x0eO\xf16\xb3&;\xbb\x07\xd4^']
['dbdbe6291d392102c7ef4ff595963e61', '6259fd9bbd298965d37517f7e0891f47', '986fc49a0032e760b2252e8568715acc', '424a43f3013b7ac40386130ef945961e']
['AAAAAAAAAAAAAAAA', '4E5_0fb_4lW4y5_m', '4kE_mE_fE3L_5p3c', '14L555555555BBB@']

Flag berada pada block ke-2 dan seterusnya.

Flag

gemastik12{4E5_0fb_4lW4y5_m4kE_mE_fE3L_5p3c14L}