目录

堆溢出点

利用步骤

  创建第一个house,修改top_chunk的size

  创建第二个house,触发sysmalloc中的_int_free

  创建第三个house,泄露libc和heap的地址

  创建第四个house,触发异常

一点疑惑

参考资料


堆溢出点

图1  堆溢出点

  edit函数中没有对那么长度进行校验。


利用步骤

创建第一个house,修改top_chunk的size

    top_chunk的size也不是随意更改的,因为在sysmalloc中对这个值还要做校验

  assert ((old_top == initial_top (av) && old_size == 0) ||((unsigned long) (old_size) >= MINSIZE &&prev_inuse (old_top) &&((unsigned long) old_end & (pagesize - 1)) == 0));/* Precondition: not enough current space to satisfy nb request */assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE));

    所以要满足:

  1. 大于MINSIZE(0X10)
  2. 小于所需的大小 + MINSIZE
  3. prev inuse位设置为1
  4. old_top + oldsize的值是页对齐的

创建第二个house,触发sysmalloc中的_int_free

    如果要触发sysmalloc中_int_free,那么本次申请的堆大小也不能超过mp_.mmap_threshold,因为代码中也会根据请求值来做出不同的处理。

 if (av == NULL|| ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)&& (mp_.n_mmaps < mp_.n_mmaps_max)))   

    如果请求的堆块大小nb大于等于mp_.mmap_threshold就可能走mmap分支,而不是扩展原来heap的大小了。

    触发_int_free后,top_chunk就被释放到unsortbin中了。以下将它称作old_top。之所以要这样操作,是因为程序本身的限制,让我们不能分配到想要的内存区。

    本身的限制:   

  1. 一次操作的对象只能是最近一次创建的house指针
  2. 没有释放操作

    通过这种方式,在空闲区有了堆块,也就存在了链表指针,通过一定的方式就拿到想要的数据了。

创建第三个house,泄露libc和heap的地址

    本次创建house分配的堆块从unsortbin中分配,指定的大小要小于old_top,系统会将old_top切分成两块。

    在把old_top从unsortbin链中取下后,会将其插入相应的largebin中

/* remove from unsorted list */
unsorted_chunks (av)->bk = bck;//将old_top从unsortbin中取下
bck->fd = unsorted_chunks (av);…
victim_index = largebin_index (size);//计算old_top大小在largebin那个层次
bck = bin_at (av, victim_index);
fwd = bck->fd;
…victim->fd_nextsize = victim->bk_nextsize = victim;//将old_top的fd_nextsize和bk_nextsize都指向old_top本身
…
mark_bin (av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;//将old_top加入largebin链表中
bck->fd = victim;

    在后面分割堆块后,保存有指针信息的堆块会被分配给用户,而且这些信息malloc不会擦除。

图2  old_top加入largebin链表中

    剩下的堆块(下文依然称之为为old_top)又被加入到unsortbin中了。

    然后输入8个字节,调用see函数,那么bk处保存的指针信息就得到了。这个就是unsortbin的地址,这个地址处于libc中,减掉一个偏移就是libc的起始地址了。

    重新输入24个字节,调用see函数,那么bk_nextsize处保存的指针信息就得到了。这个是本次分割前的old_top块起始地址。减掉一个偏移就是heap的起始地址了。

为第四步触发异常布局内存。

      本题的利用思路,是通过修改IO_list_all指针来控制异常处理的流程到我们指定的函数。如何触发异常,第四步会说。

while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
{
bck = victim->bk;
…
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

      IO_list_all的地址需要拿到libc.so后才能确定。通过覆盖此时的old_top的size域和bk指针,来重写IO_list_all。

      将bk指针覆盖为&IO_list_all -0x10,因此IO_list_all被重写为unsortbin-0x10。

      将size域设置为0x60。为什么是0x60而不是70、80呢?

      先来看看,设置为0x60后会给后续的malloc造成什么影响。

unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
…
if (in_smallbin_range (size))
{
victim_index = smallbin_index (size);// victim_index=6
bck = bin_at (av, victim_index);//bck=&av->bins[10]-0x10
fwd = bck->fd;
}
…
mark_bin (av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;//old_top被加入av->bins[10]的链表中了。
bck->fd = victim;

  0x60属于smallbin的范围了,所以此时的old_top被加入到smallbin[4]的链表中。又为何要加入到smallbin[4]中呢?此时IO_list_all=&unsortbin-0x10,距离smallbin[4]的偏移是0x60,再来看看IO_FILE的结构体

struct _IO_FILE {int _flags;           /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags/* The following pointers correspond to the C++ streambuf protocol. *//* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */char* _IO_read_ptr;   /* Current read pointer */char* _IO_read_end;   /* End of get area. */char* _IO_read_base;  /* Start of putback+get area. */char* _IO_write_base; /* Start of put area. */char* _IO_write_ptr;  /* Current put pointer. */char* _IO_write_end;  /* End of put area. */char* _IO_buf_base;   /* Start of reserve area. */char* _IO_buf_end;    /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base;  /* Pointer to first valid character of backup area */char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;
…

  可以看到,IO_FILE偏移0x60的字段是struct _IO_marker *_markers,偏移0x68的字段是struct _IO_FILE *_chain。而这两个的值恰恰是old_top的起始地址。

  原来改为0x60是为了将old_top加入smallbin[4],而smallbin[4]的fd和bk指针恰好对应于IO_FILE结构体中的_markers和_chain字段。这个时候,算是明白参考文章所说,无法控制main_arena中的数据,但是通过chain链,将控制转移到我们到我们能控制的地方。

图3  IO_list_all被重写后

      那如何使用chain字段呢?

while (fp != NULL)
{
…fp = fp->_chain;

      当fp指向old_top的时候,那一切都好说了。为了使用vtable,我们还要过一段校验代码。

      if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T|| (_IO_vtable_offset (fp) == 0&& fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr> fp->_wide_data->_IO_write_base))
#endif)&& _IO_OVERFLOW (fp, EOF) == EOF)    

  1. fp->_mode <= 0不成立,所以
  2. _IO_vtable_offset (fp) == 0、fp->_mode > 0和fp->_wide_data->_IO_write_ptr> fp->_wide_data->_IO_write_base必须成立
  3. 我们将vtable的值改写成我们构造的vtable起始地址
  4. 将_wide_data字段改写成IO_FILE中字段_IO_read_ptr的地址 //此处错误,在参考的利用脚本中并不是改成_IO_read_ptr的地址。而是vtable前0x28个字节,这些字节恰好能满足fp->_wide_data->_IO_write_ptr> fp->_wide_data->_IO_write_base。当然,也可以改成IO_FILE中字段_IO_read_ptr的地址,但是在payload中需要额外构造一些数据来满足条件了

      而传递给over函数的参数是fp,fp指向old_top,起始处被写为”/bin/sh\0x00”

创建第四个house,触发异常

  如上面第三步所述,old_top的size被改写为0x60,本次分配的时候,会先从unsortbin中取下old_top,加入到smallbin[4],同时,unsortbin.bk也被改写成了&IO_list_all-0x10,所以此时的victim->size=0那么不会通过校验,进入malloc_printerr,触发异常。


一点疑惑

  关于前面调用_int_free将old_top释放到unsortbin我是一笔带过。但是这个地方有一点问题。

old_size = (old_size - 4 * SIZE_SZ) & ~MALLOC_ALIGN_MASK;
set_head (old_top, old_size | PREV_INUSE);
chunk_at_offset (old_top, old_size)->size = (2 * SIZE_SZ) | PREV_INUSE;
chunk_at_offset (old_top, old_size + 2 * SIZE_SZ)->size = (2 * SIZE_SZ) | PREV_INUSE;
if (old_size >= MINSIZE){
_int_free (av, old_top, 1);

  old_top被释放之前,用最后的0x20个字节构造了两个chunk的header信息。size都设置为2 * SIZE_SZ。但是就是这里有问题。

nextchunk = chunk_at_offset(p, size);
nextsize = chunksize(nextchunk);
if (__builtin_expect (nextchunk->size <= 2 * SIZE_SZ, 0)
|| __builtin_expect (nextsize >= av->system_mem, 0))
{
errstr = "free(): invalid next size (normal)";
goto errout;

  这个校验会不通过。但是事实却是通过了。很困惑。不知道自己哪点理解出现了偏差。

  近来才想起来还有这个问题没处理,其实代码已经告诉我答案了。

  chunk_at_offset (old_top, old_size)->size = (2 * SIZE_SZ) | PREV_INUSE;

  此时size设置了prev_inuse位,自然在后面的校验中大于2 * SIZE_SZ

  __builtin_expect (nextchunk->size <= 2 * SIZE_SZ


参考资料

[1] CTF Pwn之创造奇迹的Top Chunk

http://bobao.360.cn/ctf/detail/178.html

[2] HITCON CTF Qual 2016 - House of Orange Write up

http://4ngelboy.blogspot.jp/2016/10/hitcon-ctf-qual-2016-house-of-orange.html

[3] glibc-2.23源码

转载于:https://www.cnblogs.com/shangye/p/6268981.html

ctf-HITCON-2016-houseoforange学习相关推荐

  1. [HITCON 2016]Leaking沙箱逃逸学习

    [HITCON 2016]Leaking沙箱逃逸学习 node.js 里提供了 vm 模块,相当于一个虚拟机,可以让你在执行代码时候隔离当前的执行环境,避免被恶意代码攻击.但是这道题比较有意思 考点是 ...

  2. BUUCTF [HITCON 2016] Leaking

    BUUCTF [HITCON 2016] Leaking 考点: node.js中VM2沙箱逃逸 JS通过Buffer 类处理二进制数据的缓冲区 启动环境: "use strict" ...

  3. [HITCON 2016]Leaking-nodejsVM沙箱逃逸

    [HITCON 2016]Leaking 最近想学下nodejs相关的题目,所以去buu上又找了一道来做 进入题目后如上图所示,直接给出了源代码,老样子,拿出之前收藏的nodejs相关安全问题来对比着 ...

  4. 2016中国互联网学习白皮书发布

    近日,学习推动教育变革--<2016中国互联网学习白皮书>发布会在京举行.会上,教育部教育管理信息中心联合北京师范大学教育技术学院.百度文库共同发布<2016中国互联网学习白皮书&g ...

  5. 图说2016深度学习十大指数级增长

    转自:https://www.52ml.net/21402.html http://mp.weixin.qq.com/s?__biz=MzI3MTA0MTk1MA==&mid=26519906 ...

  6. 2016年学习JavaScript是怎样的一种体验

    2016年学习JavaScript是怎样的一种体验 http://www.spotty.com.cn/index.php/archives/564/

  7. Hitcon 2016 Pwn赛题学习

    PS:这是我很久以前写的,大概是去年刚结束Hitcon2016时写的.写完之后就丢在硬盘里没管了,最近翻出来才想起来写过这个,索性发出来 0x0 前言 Hitcon个人感觉是高质量的比赛,相比国内的C ...

  8. 2016年世界编程大赛_在2016年学习的最佳编程语言是什么?

    2016年世界编程大赛 Craig's Best Programming Language to Learn in 2015 article was a huge hit, and in this a ...

  9. CTF Crypto简单题学习思路总结(持续更新)

    系列文章目录 本系列开篇文章,就没有链接了. 文章目录 系列文章目录 前言 一.编码/解码 1.1 BrainFuck密码&ook!密码 1.2 URL编码&HTML实体编码 1.3 ...

  10. CTF之PHP基础学习篇(一)

    文章目录 前言 CTF之PHP基础 一.PHP是什么? 二.配置PHP环境 三.php基础语法 总结 前言 估摸着不少学计算机的同学以及其他专业的小部分同学都对于信息安全感兴趣吧!那对于参加这相关的比 ...

最新文章

  1. 设置centos7语言显示环境
  2. input 属性和用法
  3. Hadoop HA 机制学习:HA是怎么运作,QJM又是怎么发挥功效的
  4. ext grid 重新布局_如何让你的 CSS Grid 布局有良好的可访问性
  5. php curl 库参数,PHP 关于curl库参数问题的求助!!!
  6. [js高手之路]使用原型对象(prototype)需要注意的地方
  7. 数据预处理和特征工程
  8. SQLi LABS Less 9 时间盲注
  9. 深入了解C++变量类型有哪些
  10. Simulink仿真---clark变换、反clark变换
  11. CF909B Segments
  12. 【React】React Fiber
  13. warmup与余弦退火学习率
  14. 高校房产管理系统中周转房有哪些管理功能和范围
  15. 十 LVS 负载均衡
  16. html分享微信qq等,h5移动端调用微信好友,朋友圈,QQ好友,QQ空间等APP分享功能...
  17. win7更新错误0x800b0109_Win7自动更新失败怎么办
  18. 图神经网络学习记录:《图神经网络综述:模型与应用》
  19. css3的半透明效果
  20. Unity Android接入Adtming广告聚合平台

热门文章

  1. 漫步数学分析九——级数
  2. PRML-系列二之2.2
  3. libsvm中数据归一化的重要性
  4. [深度学习-NLP]什么是Self-attention, Muti-attention和Transformer
  5. leetcode —— 206. 反转链表
  6. 吴恩达深度学习 —— 4.5 搭建深层神经网络块
  7. Java中矩阵运算(math3的使用)
  8. CV之 HOG特征描述算子-行人检测
  9. php中mysqli用法举例
  10. P1948 [USACO08JAN]Telephone Lines S(二分+spfa)