0ctf2018 babystack、babyheap、blackhole解析

0ctf2018 babystack writeup

赛题链接

https://github.com/eternalsakura/ctf_pwn/tree/master/0ctf2018/babystack

前置技能

ret2dl in x86

没有能用来leak的漏洞。 如下面的代码,除了明显的栈溢出,没有可以用来leak内存布局,bypass aslr的函数。

本来想写一下原理的,不过其他资料已经讲得非常好了,实在没什么可补充的(其实是我还不怎么懂)。

https://www.slideshare.net/AngelBoy1/re2dlresolve

http://www.inforsec.org/wp/wp-content/uploads/2016/01/sec15-paper-di-frederico.pdf

http://skysider.com/?p=416

学习过程中最好找个程序,然后对着_dl_runtime_resolve源码服用,效果更佳,然后再看图就思路清晰了。

分析

alarm用keypatch先nop掉

可以看出有很明显的栈溢出漏洞,但是只有一个read,没有可以用来leak的函数,所以用ret2dl的解法

利用

利用思路

通过栈溢出来调用read函数在bss段写我们需要的结构和/bin/sh

然后使用dlresolvecall去调用system,得到shell。

getshell

https://github.com/eternalsakura/ctf_pwn/blob/master/0ctf2018/babystack/exp.py

其他

ret2dl方法是hook师傅教我的,我也没全看懂,只是理解了基本思路后,整个过程用roputils工具来实现的,工具我放在了我的github(https://github.com/eternalsakura/ctf_pwn/blob/master/roputils.py)上。 依然不懂怎么手工构造,而且程序再换成64位也就不会,还要学习一下。

0ctf2018 babyheap writeup

赛题链接

https://github.com/eternalsakura/ctf_pwn/blob/master/0ctf2018/babyheap.tar.gz

前置知识

fastbin attack

off-by-one

overlap

熟悉mallocstate即mainarena,即知道main_arena是存储在libc.so的一个数据段。

分析

checksec

程序分析

典型的菜单程序

比较特别的是存放堆指针的全局变量不再放在bss段,而是随机mmap了一段空间出来存放。

添加

修改

删除

查看

漏洞分析

在修改函数里存在一个off-by-one漏洞,可以用来溢出修改相邻chunk的prev_size或者size. 测试:

如图:

这里要注意一点就是我把分配的chunk修改一下

可以看出这样就修改到了下一个chunk的prev_size,之所以分配0x28和分配0x20都得到大小为0x30的chunk,是因为chunk的空间复用,如果当前chunk正在使用中,没有被free掉,那么相邻chunk的prev_size域是无效的,可以被前一个chunk使用。

利用

利用思路

leak heap

申请多个chunk,通过off-by-one改变其中一个chunk的size,使其包含两个chunk,即overlap。

然后在这个大chunk里伪造fastbin chunk B.

然后申请一个和其大小一致的fastbin chunk A,依次释放A和B。

则fastbin:B->A, B的fd就存放着A的堆地址,通过打印大chunk的内容,将其中存放着的小chunk打印出来,从而得到堆地址。

leak libc

修改3的大小为超出fastbin范围的small bin的大小,将其free,则其fd和bk都指向main_arena,而main_arena在libc上,减去偏移就得到libc基地址。

修改topchunk,覆盖mallochook为one_gadaget

通过改fastbin的fd,从而使得下一次分配的chunk到我们指定的地址(这里是top_chunk上方)。

然后修改top_chunk到malloc_hook上方,使得chunk的分配从malloc_chunk的上方附近开始进行。

于是下一次分配就分配到malloc_hook上方,从而可以覆盖malloc_hook为one_gadaget

需要注意的是main_arena + 32 + 5是什么?

还记得我们之前分配并free的xx = alloc(0x58)么?它在fastbin占位,于是它的地址的第一个字节,如图,0x55,正好可以帮我们绕过对于分配fastbin时,对size的验证。

这里顺便提一下这个验证:

在malloc时会进行一个校验,当size是fastbin的情况下,如果从fastbin取出的第一块chunk的(unsigned long)size不属于该fastbin中的时候就会发生memory corruption(fast)错误。

主要检查方式是根据malloc的bytes大小取得index后,到对应的fastbin去找,取出第一块后检查该chunk的size是否属于该fastbin。

于是我们的chunk就被分配到了这里!

注意到我们开始就说过的malloc_state,也就是main_arena它的结构体,可以看到top就在fastbin数组的下面,所以我们malloc出了fastbin数组附近之后,就可以覆盖修改top_chunk了。

将top_chunk修改为main_arena-0x33,如图,就在malloc_hook上方。

接着就可以分配出这块空间,并且对其修改,覆盖__malloc_hook到one_gadget

顺便提一句,寻找one_gadaget可以参考这篇文章(http://bestwing.me/2016/12/30/one-gadget-rce/)

exp

https://github.com/eternalsakura/ctf_pwn/blob/master/0ctf2018/babyheap/exp.py

0ctf2018 blackhole writeup

题目链接

https://github.com/eternalsakura/ctf_pwn/blob/master/0ctf2018/blackhole.tar.gz

前置技能

ret2csu 这是blackhat2018的新议题,slide如下:https://www.blackhat.com/docs/asia-18/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR.pdf

分析

这题和babystack是一样的,除了变成了64位,也是完全没有可以用来输出的函数。

而且,这题还设置了沙箱,限制了能够执行的系统调用为mprotect/read/write/exit。

所以说没办法getshell,只能一点一点的把flag给“注入”出来。

思路是先弄出一个syscall gadget,调一下mprotect,读进来shellcode就可以随便操作了。

sc逻辑的话,就把flag读进来,然后一个bit一个bit去爆破..

相当于sql盲注那样..可以构造个if flag[x]=='a' sleep else exit..这样

另外,要想要调用系统调用,可以通过在got表地址里面写掉一个低Byte,从而可以跳转到附近的函数去,这里就是系统调用,如图。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180411G079QV00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券