🦙🦙🦙🦙🦙 < ブロック暗号の基本問題パカ
import os
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
flag = os.environ.get("FLAG", "ALPACA{*** REDACTED ***}")
ALPACA = chr(129433) # "🦙"
print(f"Welcome to my login service {ALPACA}")
key = os.urandom(16)
print(f"[DEBUG] key: {key.hex()}") # Oops!
try:
ciphertext = bytes.fromhex(input("Enter your ciphertext (hex): "))
iv = bytes.fromhex(input("Enter your IV (hex): "))
cipher = AES.new(key, AES.MODE_CBC, iv)
padded_plaintext = cipher.decrypt(ciphertext)
plaintext = unpad(padded_plaintext, AES.block_size)
username = plaintext.decode()
print(f"Welcome, {username}")
if username == ALPACA * 5: # username == "🦙🦙🦙🦙🦙"
print(f"Congratulations! Here is your flag: {flag}")
else:
print("Invalid username.")
except Exception as e:
print(f"something went wrong: {e}")
exit(1)
サーバは「ログインサービス」として AES-CBC で復号した平文を username として扱い、
username == "🦙" * 5のときに FLAG を出します。
一方で、クライアント側は ciphertext と IV を自由に入力できます。
keyが出力されるので IV を適当に決めて
ciphertext = AES-CBC-Encrypt(key, iv, pad(target_plaintext))
を送ればよいです。
from pwn import remote
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import os
io = remote("34.170.146.252", 58209)
io.recvuntil(b"[DEBUG] key: ")
key = bytes.fromhex(io.recvline().strip().decode())
username = ("🦙" * 5).encode()
padded = pad(username, AES.block_size)
iv = os.urandom(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
ct = cipher.encrypt(padded)
io.sendline(ct.hex().encode())
io.sendline(iv.hex().encode())
print(io.recvall().decode(), end="")