Stack Smash Attack
Stack Smash
Stack Smash是一种利用Canary机制本身的缺陷达到信息泄露效果的一种栈溢出利用方式。该方法不需要绕过Canary保护就可以泄露内存或栈中保存的信息。大概原理是:当Canary机制检测到栈溢出时(也就是自身的值被改写的时候),会触发__stack_chk_fail
函数,这个函数又会调用__fortify_fail
函数向屏幕上输出一段信息来提示用户检测到栈溢出,随后程序被终止运行。提示的内容如下所示:
这时我们会发现,这个提示还会输出当前文件的路径,那么我们是否可以利用这个路径带出一些其他东西呢。先来看下__stack_chk_fail
的源码:
|
|
__stack_chk_fail
函数只是调用了__fortify_fail ("stack smashing detected")
而已,我们继续看__fortify_fail
的源码:
|
|
__fortify_fail
函数则是负责调用__libc_message
输出栈溢出信息。由于每个程序的argv[0]
变量都存放着程序的名称,那么这个函数就会同时将程序名称打印出来。
值得一提的是,__libc_argv[0]
也存在于栈上,因此我们借助栈溢出的机会可以同时修改它的值,让它指向我们想要的内存区域。那么最后它就会帮我们泄露内存信息。
此漏洞仅限Glibc 2.30及之前的版本,较新的Glibc不再输出argv[0]。
Exploit
以经典的Stack Smashing题目演示利用手段。题目为2021鹤城杯 easyecho。
实际上在Stack Smashing的利用过程中只需要考虑一件事情,就是找到__libc_argv[0]
在栈上的位置(相对溢出点的位置),这样我们才能覆盖。其他的一切libc会帮我们完成。
一种方法是直接在栈上找,观察栈上有没有存放着有关程序路径的地方,下面就是一个可疑点:
此处存放着0x7fffffffde18,而0x7fffffffde18又指向0x7fffffffe0c9,我们发现0x7fffffffe0c9处刚好存放着程序路径。也就是说,0x7fffffffde18就是argv[0]。
第二种方法直接在gdb上打印__libc_argv[0]
变量的地址即可。
最终确定argv[0]在0x7fffffffde18的地址处。
为什么一定要获得指向path的地址而不是直接修改path?当然是都可以,但是哪种方便呢?
继续观察溢出点,发现argv[0]在栈上的位置相对于溢出点相差0x7fffffffde18-0x7fffffffdcb0=0x168字节的位置。那么我们填满0x168字节后既可以覆盖到argv[0]。
根据题目,flag存放在base + 0x202040的地方(base是程序基址)。于是payload就为:
|
|
由于0x168个字节早就覆盖掉rbp了,因此直接结束程序就可以看到结果:
完整的exp:
|
|