#!/usr/bin/env python3from Crypto.Cipher import AESfrom Crypto.Util.Padding import pad, unpadimport json, signal, sysclassUnbuffered(object):def__init__(self,stream): self.stream = streamdefwrite(self,data): self.stream.write(data) self.stream.flush()defwritelines(self,datas): self.stream.writelines(datas) self.stream.flush()def__getattr__(self,attr):returngetattr(self.stream, attr)sys.stdout =Unbuffered(sys.stdout)FLAG =open('flag.txt', 'rb').read()BUBUR ={"diaduk":"semua rasa tercampur dengan sempurna","tidak diaduk":"terlihat dan terjaga tetap estetik","diblender": FLAG.decode()}key = AES.get_random_bytes(AES.block_size)defuser_input(s): inp =input(s).strip()assertlen(inp)<1024return inpdeftulis():try: nama =user_input('Nama: ') sekte =user_input('Sekte (diaduk/tidak diaduk): ')assert sekte in ['diaduk','tidak diaduk'] alasan = BUBUR[sekte] rating =int(user_input('Rating (1-5): '))assert rating in [1,2,3,4,5]except:print('Review kamu aneh, silakan coba lagi')return form = json.dumps({"nama": nama,"sekte": sekte,"alasan": alasan,"rating": rating }).encode() enc = AES.new(key, AES.MODE_ECB).encrypt(pad(form, 16)) kupon = enc.hex()print('Kamu bisa gunakan kupon di bawah ini untuk mendapatkan bubur gratis!')print('Kupon: '+ kupon)defredeem(kupon):try: dec = AES.new(key, AES.MODE_ECB).decrypt(bytes.fromhex(kupon)) form = json.loads(unpad(dec, 16))assert"sekte"in form.keys()and"alasan"in form.keys()and"rating"in form.keys() form["alasan"]= BUBUR[form["sekte"]]if form["sekte"]=="diblender"and form["rating"]==5:print(f'Mencengangkan! Kamu suka makan bubur {form["sekte"]} karena {form["alasan"]}?')else:print(f'Kupon berhasil digunakan! Bubur gratis untuk kamu: {chr(0x1f372)}')except:print('Kupon yang kamu miliki tidak berasal dari Warung Bubur MDT')returndefbanner():print('-'*60)print('Selamat datang di Warung Bubur MDT')print('Warung Bubur MDT sedang mengadakan event tulis review bubur')print('Setiap review yang kamu tulis dapat ditukarkan dengan 1 porsi bubur gratis')print('Review terbaik akan mendapatkan hadiah spesial dari Warung Bubur MDT')print('-'*60)print('Kamu bisa:')print('1. Tulis review')print('2. Redeem kupon')defmain():banner() ink =100 used = []whileTrue:print('-'*60) opt =user_input('> ')if opt =='1':if ink >=30:tulis() ink -=30else:print('Tinta pulpenmu tidak cukup untuk menulis review lagi')elif opt =='2': coupon =user_input('Kupon: ')if coupon in used:print('Kupon telah digunakan')else:redeem(coupon) used.append(coupon)else:breakif__name__=='__main__': signal.alarm(60)main()
Dari source code tersebut dapat diketahui bahwa tujuan kita adalah menampilkan flag dengan cara mengisi nilai sekte dengan diblender. Karena enkripsi yang digunakan adalah AES ECB , jadi antar blocknya tidak saling terikat , jadi kita bisa meracik ciphertext dengan mengkombinasikan nilai per blocknya untuk menghasilkan plaintext dengan nilai sekte diblender. Berikut proses pembuatan ciphertext yang kami lakukan
Hasil
{"nama": "AAAAAA -> f[0]
A", "sekte": "di -> f[1]
blender", "sekte -> s[1]
asan": "semua ra -> s[3]
aduk", "alasan": -> f[2]
"semua rasa ter -> f[3]
campur dengan se -> f[4]
mpurna", "rating -> f[5]
": 5} -> f[6]
f->first
{"nama": "AAAAAA 0
A", "sekte": "di 1
aduk", "alasan": 2
"semua rasa ter 3
campur dengan se 4
mpurna", "rating 5
": 5} 6
s->second
{"nama": "AAAAAA 0
blender", "sekte 1
": "diaduk", "al 2
asan": "semua ra 3
sa tercampur den 4
gan sempurna", " 5
rating": 5} 6
Dapat dilihat pada section hasil kita berhasil membuat suatu ciphertext yang nantinya akan membuat nilai sekte menjadi diblender. Berikut penerapannya pada python
from pwn import*defsplit(target): result = []for i inrange(0,len(target),32): result.append(target[i:i+32])return resultpayload = ["AAAAAAA","AAAAAAblender"]r =remote("103.152.242.222",30001)r.recvuntil("> ")r.sendline("1")r.recvuntil("Nama: ")r.sendline(payload[0])r.recvuntil(": ")r.sendline("diaduk")r.recvuntil(": ")r.sendline("5")r.recvuntil("Kupon: ")f =split(r.recvline().strip())r.recvuntil("> ")r.sendline("1")r.recvuntil("Nama: ")r.sendline(payload[1])r.recvuntil(": ")r.sendline("diaduk")r.recvuntil(": ")r.sendline("5")r.recvuntil("Kupon: ")s =split(r.recvline().strip())payload = f[0]+f[1]+s[1]+s[3]+f[2]+f[3]+f[4]+f[5]+f[6]r.recvuntil("> ")r.sendline("2")r.recvuntil("Kupon: ")r.sendline(payload)r.interactive()
Flag : MDT4.0{dapat_meningkatkan_iq_sebanyak_100_poin}
Intinya disini kita harus melakukan leak terhadap nilai seed ( F1 ) , dan juga nilai dari nsr.next() untuk mendapatkan nilai F2. Disini kami melakukan pengamatan terhadap 3 nilai next yang dihasilkan dan didapatkan persamaan seperti berikut
a = b
1st next
a^5*a^2 = a^7
(a^7)^19 = a^133
2nd next
(a^5)^2*(a^2)^5 = (a^20)^19 = a^380
3rd next
((a^5)^2)^5*((a^2)^5)^2 = (a^70)^19 = a^1330
4th next
a^3800
Karena nilai dari 3rd next adalah 1330 dan 1st next adalah 133 , jadi kita bisa menebak nilai ke tiga dengan hanya memangkatkan 10 untuk nilai 1st next.
3rd = (1st^10) mod p
Selanjutnya kami sempet stuck untuk mendapatkan nilai seed , karena hanya kurang mod saja :3 . Berikut analisa yang kami lakukan
e*d mod phi = 19
n = p -> prime
Jadi karena nilai e*d mod phi tidak sama dengan 1 kita perlu melakukan pengecekan terhadap seluruh kemungkinan nilai yang ada ( menggunakan nthroot_mod , sebelumnya kami hanya menggunakan nthroot -> stuckk lama ). Karena n prime jadi untuk phi tinggal n-1 saja. Berikut solver yang kami gunakan