首页 > 学院 > 开发设计 > 正文

linux 堆溢出学习之house of spirit(1)

2019-11-06 08:29:53
字体:
来源:转载
供稿:网友

综述

house of spirit是一种常用的堆溢出技术,而在如今的malloc实现中依然没有对这种方法进行保护,所以在目前还是一种有效的堆溢出技术。下面我们先从这种方法的来源之本讲起,即2005 Malloc Maleficarumcsdn

原文

The House of SpiritThe House of Spirit is PRimarily interesting because of the natureof the circumstances leading to its application. It is the onlyHouse in the Malloc Maleficarum that can be used to leverage both aheap and stack overflow. This is because the first step is not tocontrol the header information of a chunk, but to control a pointerthat is passed to free(). Whether this pointer is on the heap ornot is largely irrelevant.The general idea involves overwriting a pointer that was previouslyreturned by a call to malloc(), and that is subsequently passed tofree(). This can lead to the linking of an arbitrary address into afastbin. A further call to malloc() can result in this arbitraryaddress being used as a chunk of memory by the application. If thedesigner can control the applications use of the fake chunk, thenit is possible to overwrite execution control data.Assume that the designer has overflowed a pointer that is beingpassed to free(). The first problem that must be considered isexactly what the pointer should be overflowed with. Keep in mindthat the ultimate goal of the House of Spirit is to allow thedesigner to overwrite some sort of execution control data byreturning an arbitrary chunk to the application. Exactly what"execution control data" is doesn't particularly matter so long asoverflowing it can result in execution being passed to a designercontrolled memory location. The two most common examples that aresuitable for use with the House of Spirit are function pointers andpending saved return addresses, which will herein be referred to asthe "target".In order to successfully apply the House of Spirit it is necessaryto have a designer controlled Word value at a lower address thanthe target. This word will correspond to the size field of thechunk header for the fakechunk passed to free(). This means thatthe overflowed pointer must be set to the address of the designercontrolled word plus 4. Furthermore, the size of the fakechunk mustbe must be located no more than 64 bytes away from the target. Thisis because the default maximum data size for a fastbin entry is 64,and at least the last 4 bytes of data are required to overwrite thetarget.There is one more requirement for the layout of the fakechunk datawhich will be described shortly. For the moment, assume that all ofthe above conditions have been met, and that a call to free() ismade on the suitable fakechunk. A call to free() is handled by awrapper function called public_fREe():voidpublic_fREe(Void_t* mem){ mstate ar_ptr; mchunkptr p; /* chunk corresponding to mem */ ... p = mem2chunk(mem); if (chunk_is_mmapped(p)) { munmap_chunk(p); return; } ... ar_ptr = arena_for_chunk(p); ... _int_free(ar_ptr, mem);In this situation mem is the value that was originally overflowedto point to a fakechunk. This is converted to the "correspondingchunk" of the fakechunk's data, and passed to arena_for_chunk() inorder to find the corresponding arena. In order to avoid specialtreatment as an mmap() chunk, and also to get a sensible arena, thesize field of the fakechunk header must have the IS_MMAPPED andNON_MAIN_ARENA bits cleared. To do this, the designer can simplyensure that the fake size is a multiple of 8. This would mean theinternal function _int_free() is reached:void_int_free(mstate av, Void_t* mem){ mchunkptr p; /* chunk corresponding to mem */ INTERNAL_SIZE_T size; /* its size */ mfastbinptr* fb; /* associated fastbin */ ... p = mem2chunk(mem); size = chunksize(p); ... if ((unsigned long)(size) <= (unsigned long)(av->max_fast)) { if (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ || __builtin_expect (chunksize (chunk_at_offset (p, size)) >= av->system_mem, 0)) { errstr = "free(): invalid next size (fast)"; goto errout; } ... fb = &(av->fastbins[fastbin_index(size)]); ... p->fd = *fb; *fb = p; }This is all of the code in free() that concerns the House ofSpirit. The designer controlled value of mem is again converted toa chunk and the fake size value is extracted. Since size isdesigner controlled, the fastbin code can be triggered simply byensuring that it is less than av->max_fast, which has a default of64 + 8. The final point of consideration in the layout of thefakechunk is the nextsize integrity tests.Since the size of the fakechunk has to be large enough to encompassthe target, the size of the nextchunk must be at an address higherthan the target. The nextsize integrity tests must be handled forthe fakechunk to be put in a fastbin, which means that there mustbe yet another designer controlled value at an address higher thanthe target.The exact location of the designer controlled values directlydepend on the size of the allocation request that will subsequentlybe used by the designer to overwrite the target. That is, if anallocation request of N bytes is made (such that N <= 64), then thedesigner's lower value must be within N bytes of the target andmust be equal to (N + 8). This is to ensure that the fakechunk isput in the right fastbin for the subsequent allocation request.Furthermore, the designer's upper value must be at (N + 8) bytesabove the lower value to ensure that the nextsize integrity testsare passed.If such a memory layout can be achieved, then the address of this"structure" will be placed in a fastbin. The code for thesubsequent malloc() request that uses this arbitrary fastbin entryis simple and need not be reproduced here. As far as _int_malloc()is concerned the fake chunk that it is preparing to return to theapplication is perfectly valid. Once this has occurred it is simplyup to the designer to manipulate the application in to overwritingthe target.

翻译

house of spirit因为其应用情况受到广泛关注,他是这篇文章中提到方法里,唯一一种同时可以利用堆和栈溢出的方法。这是因为他第一步不是去控制一个chunk的头信息,而是去控制一个传给free函数的指针,至于这个指针是不是在堆上并没有太大的关系。

他的中心思想主要是重写一个之前由malloc分配然后被放进free里的一个指针,这就会导致一个任意地址被链接进fastbin。之后的某个malloc调用可以导致这个任意地址被分配作为一个chunk,如果攻击者可以控制这个fake chunk的应用,那么就有机会可以重写关于执行控制的数据。

假设攻击者溢出了一个被放入free调用的指针,需要考虑的第一个问题是用什么来溢出后填充这个指针。需记住的是house of spirit的最终目的是允许攻击者通过返回给这个应用一个任意位置的chunk来重写某些执行控制数据,至于执行控制数据具体是什么并不是太重要只要溢出它能够导致攻击者想要的执行内容被传送到攻击者控制的内存地址。两个最为常见最为适合用house of spirit的例子的指针是函数指针和存储的返回地址, 这里我们把他们称作“目标”。

为了成功应用house of spirit,攻击者必须要求能够控制低于目标的地址的一个字值(word value),这个字(word)将会和被放进free的fake chunk的头的size域对应。这意味着被溢出的指针将会被设置为攻击者控制的字的地址再加上4,以及fake chunk必须离目标不到64字节。这是因为fastbin的默认块大小是64,而至少我们需要最后4个字节来重写目标。

另外,对于fake chunk的数据分布还有一个要求,我们马上将会讲到。现在我们就先假设之前提到的所有要求都已经被满足了,然后一个对free的调用将会在合适的fake chunk上应用。一个对free的调用将会被一个包装函数,名为public_fREe处理:

void public_fRE(Void_t* mem){ mstate ar_ptr; mchunkptr p; // mem相应的chunk ... p = mem2chunk(mem); if (chunk_is_mmapped(p)) { munmap_chunk(p); return; } ... ar_ptr = arena_for_chunk(p); ... _int_free(ar_ptr, mem);}

在这种情况下,mem是之前已经被溢出并使得指向fake chunk的一个值,然后被转换为fake chunk相应的chunk指针,然后被传仅arena_for_chunk来找到相应的arena,为了避免对于mmap chunk的特殊处理,以及为了得到一个有用的arena,fake chunk头的size域的IS_MMAPPED和NON_MAIN_ARENA位必须为0. 为了做到这个,攻击者只需要确认fake 的size是8的倍数就可以了。这样的话,_int_free函数就会被调用了:

void _int_free(mstate av, Void_t* mem){ mchunkptr p; // mem相应的chunk INTERNAL_SIZE_T size; //size,大小 mfastbinptr* fb; //联系的fast bin ... p = mem2chunk(mem); size = chunksize(p); ... if ((unsigned long)(size) <= (unsigned long)(av->max_fast)) { if (chunk_at_offset(p, size)->size <= 2 * SIZE_SZ || __builtin_expect(chunksize(chunk_at_offset(p, size)) >= av->system_mem, 0)) { errstr = "free(): invalid next size (fast)"; goto errout; } ... fb = &(av->fastbins[fastbin_index(size)]); ... p->fd = *fb; *fb = p; }}

这里是free对于使用house of spirit所需要了解的全部代码了。攻击者控制的mem值再次被转换为chunk指针,然后fake的size值被提取出来。因为size已经是攻击者控制的了,只需要保证这个值小于av->max_fast,fastbin的代码就会被执行了,这里,av->max_fast的默认值为64+8。最后fake chunk的布局需要考虑的是如何通过nextsize正确性的检测。

因为fake chunk的大小必须要足够大才能包裹住目标,所以nextchunk的size的地址必须高于目标。为了能够使得fake chunk被放进fastbin,nextsize一正确性检验必须被处理一下,这就意味着必须有另外一个攻击者控制的值在高于目标的地址出现。

攻击者控制的值的具体位置依赖于将被用来重写目标的分配请求的大小,这就是说,如果一个分配请求了N个字节(N <= 64),那么这个攻击者可以控制的低于这个目标地址的值必须在离目标的N 字节以内,并且必须等于N + 8。这是为了保证fake chunk被放在了之后分配请求所需要的正确的fastbin里。另外,攻击者能控制的另外一个,高于目标地址的值必须比低于的那个值的地址高出(N + 8)字节来保证nextsize的正确性检测可以通过。

如果满足了这样一个内存布局,那么这个结构的地址将会被放进fastbin里。其后对于这个已经被控制的fastbin块的malloc请求的代码非常简单,这里就不再给出了。只要_int_malloc被调用,那么这个准备被返回的fake chunk就是有效的。只要这种情况发生了,那么操纵应用来重写目标就非常简单了。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表