Diberikan source code seperti dibawah :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
#!/usr/bin/env python3 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import json, signal, sys 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) 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) def user_input(s): inp = input(s).strip() assert len(inp) < 1024 return inp def tulis(): 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) def redeem(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') return def banner(): 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') def main(): banner() ink = 100 used = [] while True: print('-' * 60) opt = user_input('> ') if opt == '1': if ink >= 30: tulis() ink -= 30 else: 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: break if __name__ == '__main__': signal.alarm(60) main() |
Untuk mendapatkan flag, kita perlu set sekte menjadi diblender. Akan tetapi, kita tidak dapat langsung mengsetnya di input, karena terdapat validasi assert. Disitu kita bisa mengirim pesan sesuai kebutuhan, dan potong ciphertext sesuai kebutuhan. Berikut adalah step by step cara pengerjaannya :
- Masukkin aaaaaaa di inputan nama, diaduk di inputan sekte, dan berikan rating 5. Ambil ciphertext sebanyak ciphertext[0:64] (dalam hex), kita akan dapat bagian JSON berupa {“nama”: “aaaaaaa”, “sekte”: “di
- Masukkin aaaaaablender di inputan nama, diaduk di inputan sekte, dan berikan rating 5. Ambil ciphertext sebanyak ciphertext[32:64] (dalam hex), kita akan dapat bagian JSON berupa blender”, “sekte
- Masukkin aaaaaaaaaaaaaaaaaaaaaa di inputan nama, diaduk di inputan sekte, dan berikan rating 5. Ambil ciphertext sebanyak ciphertext[32:64] (dalam hex), kita akan dapat bagian JSON berupa aaaaaaaaaaaaaaaa
- Masukkin aaaaaablender di inputan nama, diaduk di inputan sekte, dan berikan rating 5. Ambil ciphertext sebanyak ciphertext[64:] (dalam hex), kita akan dapat bagian JSON berupa “: “diaduk”, “alasan”: “semua rasa tercampur dengan sempurna”, “rating”: 5} beserta padding yang tidak saya ketahui nilainya
Kalau kita menggambungkan ciphertext a + b + c +d, maka kita akan dapat plaintext {“nama”: “aaaaaaa”, “sekte”: “diblender”, “sekteaaaaaaaaaaaaaaaa”: “diaduk”, “alasan”: “semua rasa tercampur dengan sempurna”, “rating”: 5}. Disitu karena nanti alasan akan diset ulang berdasarkan nilai dari sekte, maka kita bisa mendapatkan flag. Berikut solver scriptnya :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
from pwn import * #get first cipher con = remote('103.152.242.222', 30001) con.recvuntil(b'> ') con.sendline(b'1') con.recvuntil(b'Nama: ') con.sendline(b'aaaaaaa') con.recvuntil(b'Sekte (diaduk/tidak diaduk): ') con.sendline(b'diaduk') con.recvuntil(b'Rating (1-5): ') con.sendline(b'5') con.recvline() c1 = con.recvline().decode().strip().split(': ')[1] print("cipher 1=", c1) #get second cipher con.recvuntil(b'> ') con.sendline(b'1') con.recvuntil(b'Nama: ') con.sendline(b'aaaaaablender') con.recvuntil(b'Sekte (diaduk/tidak diaduk): ') con.sendline(b'diaduk') con.recvuntil(b'Rating (1-5): ') con.sendline(b'5') con.recvline() c2 = con.recvline().decode().strip().split(': ')[1] print("cipher 2=", c2) #get third cipher con.recvuntil(b'> ') con.sendline(b'1') con.recvuntil(b'Nama: ') con.sendline(b'aaaaaaaaaaaaaaaaaaaaaa') con.recvuntil(b'Sekte (diaduk/tidak diaduk): ') con.sendline(b'diaduk') con.recvuntil(b'Rating (1-5): ') con.sendline(b'5') con.recvline() c3 = con.recvline().decode().strip().split(': ')[1] flag = c1[0:32] + c1[32:64] + c2[32:64] + c3[32:64] + c2[64:] #get flag con.recvuntil(b'> ') con.sendline(b'2') con.recvuntil(b'Kupon: ') con.sendline(flag.encode()) print(con.recvline()) |
Jalanin script diatas dan dapat flagnya :