Environ
Linux C中environ 变量是一个char** 类型 存储着系统的环境变量
编译下面的程序 进行一个实验 进入pwndbg我们来看一下environ指向的地址是哪里
|
可以看到其指向的其实是栈帧高地址处的环境变量 我们s进入test1函数
可以看到此时environ存储的值距离rbp非常接近 如果我们计算一下偏移 就可以得到栈帧的ret addr地址
再加上任意写 就可以做到控制程序执行流
实际利用
覆盖retaddr
这个办法的利用主要是在堆中 对于开启了沙盒的堆 我们只能构造orw 从而获取flag 但是如何执行rop链是一个难点 如果我们得到了ret addr地址 搭配上任意写 就可以劫持程序执行流 从而执行rop链
演示环境: ubuntu22 libc依赖2.27 1.0小版本
演示附件: 自己编译的 涵盖所有漏洞
首先我们利用tcachebin attack 申请到指向environ的chunk (实际做题当然不局限于tcachebin attack)
libc_addr = gift() |
老生常谈的操作了 不过获取libc基址的那个操作是我编写程序的时候直接给的漏洞 毕竟方便演示嘛
那么 获取了栈上的一个地址 要做的当然是计算和ret addr的偏移了
这时候会存在两种情况 一种rbp的值指向栈上 下一个字长就是ret addr了 直接看就好了 和泄露出来的偏移大概在0x100-0x200左右 上面的小程序就是这种情况
还有一种情况是我的演示程序 其rbp并不指向栈上
这种情况也别怕 断点直接打在栈帧结束前的ret指令 看一下现在的rsp是指向哪里 计算那个地址的偏移就行了
如图所示 我计算出来的偏移是0x110 那就依法炮制 利用tcachebin attack任意写
delete(0) |
直接同样也是图方便 直接填了个onegadget 一般是开沙盒的 或者是libc2.34以上的版本没有hook了
可以看到覆盖成功了 接下来就劫持了程序执行流
覆盖函数的retaddr
这个我感觉比上面那个效果更牛逼一点 上面那种覆盖办法 直接就把程序执行流控死了 执行完你的rop链以后 如果你rop链不返回的话 就直接终止了程序
这个办法是覆盖你调用的函数的retaddr 这样也就把调用函数的执行流控制了 main函数的不会
当然 还是没逼用 毕竟最后都控执行流了 我们肯定就获取shell或者flag了 还要这程序执行下去什么
哎呀 虽然没用 但还是看一看嘛 了解了解
比如 这个时候执行一个puts函数 我们s进入
单步执行到这里 继续s进去
待这个子函数执行完了 他肯定要返回父函数的嘛
这个时候你看rsp指针 是吧 和environ存的地址很接近的
算一算偏移照样能覆盖 和上题一样的环境 来演示一下
既然我们最后执行的是edit函数 所以攻击的应该是read函数的retaddr
不过这里先不演示 就比如menu函数的puts函数吧 打这里
断点调一下 算一下偏移 直接打
delete(0) |
欸 怎么不是onegadget呢 犯蠢了吧 那你这都到main函数的执行了 你onegadget是edit函数写进去的 那这栈结构肯定又被系统写了一次 所以我们还是乖乖写read函数吧
s进去 单步执行到ret
是吧 照样打 算一下偏移 覆盖一下
控制程序执行流成功