很多新手在栈溢出的时候会手动输入/bin/sh地址和system等函数的地址,这样不仅麻烦而且很容易出错。其实libc中带有很多gadget,控制程序跳转到这些位置执行并满足一定的条件就可以拿到shell。
最常见的用法是one_gadget后面跟libc文件,就可以拿到one_gadget的地址了,上图我以libc 2.27为例,这里有一个小技巧,就是可以看到one_gadget是需要满足一定条件的,这里我认为最好满足的是 rsp+0x40==NULL 这个条件,要求栈上的这个位置为null,这里随便拿一个程序来看一下。我在返回地址处填充了0x4f3c2这个gadget。
然后跟进去运行, ,发现程序将rsp+0x40赋值给了rsi,那么显然这个值是需要是null的,这也跟刚才one_gadget给我们提示的满足条件相符合。看一下这个值,
这个值并不是null,这样的话运行下去显然是会出错的,修改这个值显然也很麻烦,但是我们可以观察到0x7fffb5b9e0d0 + 0x60是null,符合我们的要求,而且刚才溢出的时候我们是可以控制rsp的,我们可以在输入one_gadget之前多个ret指令的addr,这样就可以增加rsp的值了。修改后的payload如下
payload = 0x78 * 'a' + p64(ret_addr) + p64(ret_addr) + p64(ret_addr) + p64(ret_addr) + p64(one_addr)
此时
这样就可以满足我们的要求了
后面加-l2参数可以找到更多的gadget。
另外还有一个near功能也很管用,可以找最靠近某个函数的gadget,这里我以libc 2.23为例。
one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near read
可以看到这两个地址只相差了两个字节。利用这一点我们可以在泄露不了libc的情况下采用尾字节覆盖的方式来强行修改read函数地址成为我们的one_gadget地址。我们看到libc函数在随机时最后倒数两个字节中只有前半个字节随机。
第一次
第二次
因此在这里我们只要覆盖尾部的两个字节,我们就有1/16的概率命中。
one_gadget的介绍到这里就结束了,如果有不足的地方,欢迎大家指正。
【预售】看雪夏日限定 · 清爽速干T恤 开卖啦!运动速干T恤,让运动更干爽!
最后于 1天前 被Mr.Bean编辑 ,原因: 刚才图片挂了