how2heap个人学习总结

how2heap个人学习总结

1.fastbin_dup

double free基本操作

2.27下由于多了tcache,可以先free7个填满tcache再calloc3个后free放入fastbin。calloc与malloc区别除了对语法略有不同,会对内容初始化以外还会跳过tcache直接执行int_malloc。

后续2.31,32,33,34无区别。

2.fastbin_dup_into_stack

double free基操,有一点需要注意,fast chunk在获取时会对其大小

进行检测,检查是否符合当前的fastbin。

获取时最后有两个检测check_remalloced_chunk(关于符号位的检测,对PREV_INUSE§无检测,所以符号位都为0就可以了),alloc_perturb(暂不知,目前无影响)

拓展:默认采用ATOMIC_FASTBINS搜索,不会产生ABA问题。

3.fastbin_dup_consolidate

double free操作,利用malloc 一个largebinchunk 导致 malloc_consolidate(),victim被放至unsortedbin,绕过fastbin double free的检测。

4.unsafe_unlink

经典利用unlink函数,检测fd->bk=victim,bk->fd=victim.

利用:p=victim.

fd=p-24,bk=p-16

效果:

p=p-16,p=p-24.

p[3]=sp,p[0]=xx **==**sp=xx

具体实现中,采用了extend方法(如offbynull),注意一点就是例子都是采用的chunk中设fakechunk,原因是p指向的是fd位。

2.23采用fastbin,2.27为了绕过tcache,采用largebin大小。

2.31增加检测,需要设置fakechunk的size

2.32,33,34无差别。

5.house_of_spirit

示例为2.23.伪造fastbin再free,但nextsize记得设为合法值。

绕过"The chunk.size of the next fake region has to be sane. That is > 2*SIZE_SZ (> 16 on x64) && < av->system_mem (< 128kb by default for the main arena) to pass the nextsize integrity checks

6.poison_null_byte

在这里插入图片描述

示例2.23.这个有些巧妙,b在free后通过off by one 减小大小,同时设置b里面对应presize位为0x20,过chunksize§ != prev_siz(next_chunk§)检测,(原文里说newer versions,咱也不知道那个version,有点不爽)之后malloc两次分割b1,b2,再freeb1和c(c的presize正常)这样实现overlapping。此时就出现了一个小chunkb2存在大chunk的有趣情况。印象里,我们通常用这种方式来实现对main arena位置的泄露。

2.27的话由于tcache,采用了largebin大小。

再看2.31

看一下malloc0x20的图

在这里插入图片描述

0x290是tcache的大小。

在这里插入图片描述

那个算padding的有些巧妙,0x20中0x10是内容,0x10是下一个chunk的头,当时竟然猪脑过载了,想半天,哭笑不得。

总共分7个步骤

step1: allocate padding

step2: allocate prev chunk and victim chunk

step3: link prev into largebin

这一步有一个非常关键的地方,就是largebin有fd_nextsize和bk_nextsize,其充当了fakechunk的fd和bk,unlink时会用到!

step4: allocate prev again to construct fake chunk

step5: bypass unlinking

step6: add fake chunk into unsorted bin by off-by-null

step7: validate the chunk overlapping

从step6时,其实也可以通过unsorted bin的fd,bk获取main arena的地址。太厉害了这思路。反思一下自己做题,还是会的东西少,导致无从下手,坐着就算原地圆寂了也想不出来。

3.32,33,34同3.31.

不清楚2.31与2.27多了那些检测,初步猜想与被extend的chunk大小和presize检测有关。

7.house_of_lore

2.23版本下通过将free状态下smallchunk的bk修改成指定位置后再连续malloc获取指定位置的使用。利用了一下smallbin缺少大小检测。

2.31,32,33,34都采用了栈中创建一个bk链表的方式来进行。

因为2.26后有tcache,无法直接像23一样。通过smallbin连接后,调用时会把smallbinchunk链接入tcache。

疑问来了,为什么要创建bk链表,其实是为了把tcache填满,这里展示一下smallchunk填入tcache的源码

if ((victim = last(bin)) != bin) {
            if (victim == 0) /* initialization check */
                malloc_consolidate(av);
            else {
                bck = victim->bk;
                if (__glibc_unlikely(bck->fd != victim)) {
                    errstr = "malloc(): smallbin double linked list corrupted";
                    goto errout;
                }
                set_inuse_bit_at_offset(victim, nb);
                bin->bk = bck;
                bck->fd = bin;

                if (av != &main_arena) set_non_main_arena(victim);
                check_malloced_chunk(av, victim, nb);
                void *p = chunk2mem(victim);
                alloc_perturb(p, bytes);
                return p;
            }
        }

8.overlapping_chunks

通过修改unsorted bin中chunk2的大小完成对chunk3的覆盖。

给了一堆各版本例子,不过没什么特殊差别。

9.overlapping_chunks2

与1的不同就是先修改size再free,但要注意size修改时要+prev_in_use位。

10.house_of_force

通过修改top chunk的size为-1(特别大)然后再malloc一个bss_var - sizeof(long)*4 - ptr_top的大chunk,再次malloc就可以获取该stack的操作权了。

11.unsorted_bin_into_stack

fakechunk的bk指向自己,在unsortedbin中不就成无限套娃了,我理解是循环足够次数后就自己出来了。

12.unsorted_bin_attack

就是把victim的bk指向stack-16,从而stack=unsortedbin位置。有个疑问,阅读源码发现结束条件是bk指向自己,chunk从unsortedbin中移除会检测一下size是否正常,可是stack的bk没设值,所以它会去哪里?它会一直遍历unsortedbin,这个是后面直接循环足够次数自己出来?有些疑问。

13.large_bin_attack

伪造一个largechunk 的bk和bk_nextsize,减小size,free一个较大chunk,chunk被放置在伪造chunk和largechunk中间,从而修改栈的值。2.23与2.27示例相同。

glibc2.30以后增加两新check

fwd->bk_nextsize->fd_nextsize != fwd

bck->fd != fwd

Since glibc does not check chunk->bk_nextsize if the new inserted chunk is smaller than smallest。

这里最后逻辑思考了一下,想明白了。

p1->bk_nextsize->fd->nextsize=stack

其实正常来说p1的bk_nextsize指向的是largebin的最小chunk,…->fd_nextchunk其实就是最小chunk的fd_nextchunk

贴个源码

if ((unsigned long) (size) <
                        (unsigned long) chunksize_nomask(bck->bk)) {
                        fwd = bck;
                        bck = bck->bk;

                        victim->fd_nextsize = fwd->fd;
                        victim->bk_nextsize = fwd->fd->bk_nextsize;
                        fwd->fd->bk_nextsize =
                            victim->bk_nextsize->fd_nextsize = victim;
                    }

可以看到,如果victim小于最小chunk,直接使用

victim->bk_nextsize = fwd->fd->bk_nextsize;
                        fwd->fd->bk_nextsize =
                            victim->bk_nextsize->fd_nextsize = victim;

这里不难理解,从逻辑上也只能通过fwd的fd的bknextsize来找到victim的bknextsize应该填的位置。

至于为何没有检测上述的check,由于我没有多版本的glibc源码的资源,我只能合理猜想一下,fwd->bk可以通过,可是bins上那个伪chunk哪来的bknextsize,肯定按原来的没法检测,所以也就缺失了检测。3.32,33,34都一样。小声:我觉得只要想检测这块,无非就是再加一条check…

14.house_of_einherjar

大extend之术,确信。通过off-by-one,把pre is ues位改为0,presize设置一下,甚至直接extend到栈。(注意unlink检测!)

2.23,27给的示例一样,31跟27差的有点大,31先overlapping实现对内部小chunk的fd更改,最后tcache poisoning。那个地方paddingchunk是为了绕过tcache计数检测(在tcache的get中),不过我又看了一下源码,没找到对tcache的chunk的size检测,大概是没有吧。有一点疑惑,31可不可以像27一样利用?示例里并没说增加了那些检测导致不行,存疑。

32版本变态了许多,首先是target必须0x10对齐(aligned,看how2heap天天学英语),how2heap里是这样说的

// due to https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a1a486d70ebcc47a686ff5846875eacad0940e41,
	// it must be properly aligned.

还有一个恶心点

d[0x30 / 8] = (long)target ^ ((long)&d[0x30/8] >> 12);

印象里后面版本会对指针加个^=。属实是带恶人了,how2heap最后一个就与它有关。

后面33,34,遛了一遍,应该没啥区别。

15.house_of_orange

house 系列噩梦之一了算是。没办法,直面了。

学习的时候发现一个宝藏文章House of orange - 安全客,安全资讯平台 (anquanke.com)需要注意的是这种方法只适用于libc-2.23及之前的版本,2.23之后的版本增加了vtable check,也有办法绕过,但是2.27及之后的版本取消了abort刷新流的操作,所以这个方法基本就失效了。

文章中有这样一段总结,算是非常清晰了**:**house of orange的主要过程就是通过unsorted bin attack修改IO_list_all,但是unsorted bin attack写入的地址不是我们可控的,写入的是main arena+88,所以需要通过某个中间媒介。我们发现在IO_list_all+0x68的位置是chain域(用于链接FILE结构体链表的指针域),然后又发现main arena+88+0x68的位置是smallbin中size=0x60的chunk数组,这个smallbin中0x60的数组中的chunk是我们可以构造的,也就是我们是可控的,所以可以在这里伪造fake file结构体。在house of orange中采用的方法就是将old top chunk的size修改为0x60这样就会被我们链入smallbin的0x60的数组中,同时在old top chunk中构造fake file结构体(就是FSOP中的构造方法),通过执行overflow的if判断(IO_write_base=0,IO_write_ptr=1,mode=0),布置好vtable和system函数,令_IO_file_jumps中overflow的函数指针是system函数,/bin/sh参数的话就布置到fake file结构体的开头,因为调用vtable中函数的时候,会将IO_FILE指针作为函数的参数。

需要注意的是house of orange中由于_mode因随机化有1/2的几率是负数,所以成功几率是1/2.

house of orange中的函数调用流程:

__libc_malloc => malloc_printerr => libc_message => abort => _IO_flush_all_lockp

malloc_printerr是malloc中用来打印错误的函数,所以house of orange最后getshell的时候前面会有一个报错,显示malloc出错了,这是正常现象

这里是张malloc0x1000后触发brk的内存图

在这里插入图片描述

有一点小思考,通过一系列操作后,stdout被设计到了old top chunk,因为调用stdout的overflow后直接getshell了,所以其下一个连接位置其实也不重要。

16.house_of_roman

这个利用方式跟平常写题见过的差不多。不过平常会通过偏移找到准确的system/execve。这道题的话则利用malloc不会对内容清理,导致存留原先smallbin的fd,先malloc一个fastbin通过覆盖修改到hook,这里有个15/16的爆破成功几率。第二步的话通过unsortedbin attack修改hook的值,第三步再来个覆盖至system,还是几率调用成功。

下次malloc(“bin/sh”)直接就调用system了。

这种利用方式,目测应该是缺少输出方式,否则直接通过偏移就能找到准确地址了。

17.tcache_poisoning

其实就是free俩(绕过数量检测)tcachechunk后修改fd,之后再malloc两次获得目标地址。

2.27,31给的都一样。2.32的tcache增加了一个0x10地址对齐的检测需要绕过,后面更改地址时还要来个12位后的亦或(因为aslr机制下,最后1.5字节是固定的)2.32,33,34看起来与2.31无差。

18.tcache_house_of_spirit

给的演示,27到34都一样。这个看起来比上一个还要简单,直接在stack里创建fakechunk,之后free会进入tcache。但是和上一个有个不一样的点,上一个进行的16字节对齐,这个却并没有。好像又是栈对齐问题,有些不清晰,下次找个时间好好调试一下,留的坑总是要填的。

19.house_of_botcake

还是蛮简单的,示例2.27,先把tcache填满,然后free a和pre,合并到unsortedbin,malloc一个tcache,之后free a,进入tcache,后面一个简单的tcache_poisoning,但是利用方式完善了。有一点需要注意,pre物理地址在a前,所以a的大小不会更改,free才能名正言顺进tcache。

后面2.32,33,34内容反而减少了一些,没有tcache_poisoning,没送佛送到西…

20.tcache_stashing_unlink_attack

挺有意思的一个利用,先把tcache填满,之后再free掉0,2chunk进unsortedbin,之后申请大一些的大小,将0,2放入smallbin,把2的bk指向stack,之后再calloc(calloc不会从tcache找)。导致2和伪chunk都进入tcache。示例标注有个fakechunk的bck->fd=victim的检测需要过。给的2.27-34示例都是一样的。从smallbin放到tcache缺少大小检测。

21.fastbin_reverse_into_tcache

并没有演示什么利用,但跟上一个smallbin放入进行了一个对照,就像题目那样reverse,其实反映的是FIFO和FILO的的区别。

22.decrypt_safe_linking

这个展示了一下2.32加入的safe linking机制的算法。

	for(int i=1; i<6; i++) {
		int bits = 64-12*i;
		if(bits < 0) bits = 0;
		plain = ((cipher ^ key) >> bits) << bits;
		key = plain >> 12;
		printf("round %d:\n", i);
		printf("key:    %#016lx\n", key);
		printf("plain:  %#016lx\n", plain);
		printf("cipher: %#016lx\n\n", cipher);
	}

house_of_mind_fastbin 与house_of_storm有点难,容我换换脑子,改日再更。

bits = 0;
plain = ((cipher ^ key) >> bits) << bits;
key = plain >> 12;
printf(“round %d:\n”, i);
printf(“key: %#016lx\n”, key);
printf(“plain: %#016lx\n”, plain);
printf(“cipher: %#016lx\n\n”, cipher);
}


house_of_mind_fastbin 与house_of_storm有些难,容我换换脑子,改日补上。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值