linux 堆溢位學習之house of spirit(1) malloc maleficarum hos翻譯
綜述
house of spirit是一種常用的堆溢位技術,而在如今的malloc實現中依然沒有對這種方法進行保護,所以在目前還是一種有效的堆溢位技術。下面我們先從這種方法的來源之本講起,即2005 Malloc Maleficarum
原文
The House of Spirit
The House of Spirit is primarily interesting because of the nature
of the circumstances leading to its application. It is the only
House in the Malloc Maleficarum that can be used to leverage both a
heap and stack overflow. This is because the first step is not to
control the header information of a chunk, but to control a pointer
that is passed to free(). Whether this pointer is on the heap or
not is largely irrelevant.
The general idea involves overwriting a pointer that was previously
returned by a call to malloc(), and that is subsequently passed to
free(). This can lead to the linking of an arbitrary address into a
fastbin. A further call to malloc() can result in this arbitrary
address being used as a chunk of memory by the application. If the
designer can control the applications use of the fake chunk, then
it is possible to overwrite execution control data.
Assume that the designer has overflowed a pointer that is being
passed to free(). The first problem that must be considered is
exactly what the pointer should be overflowed with. Keep in mind
that the ultimate goal of the House of Spirit is to allow the
designer to overwrite some sort of execution control data by
returning an arbitrary chunk to the application. Exactly what
"execution control data" is doesn't particularly matter so long as
overflowing it can result in execution being passed to a designer
controlled memory location. The two most common examples that are
suitable for use with the House of Spirit are function pointers and
pending saved return addresses, which will herein be referred to as
the "target".
In order to successfully apply the House of Spirit it is necessary
to have a designer controlled word value at a lower address than
the target. This word will correspond to the size field of the
chunk header for the fakechunk passed to free(). This means that
the overflowed pointer must be set to the address of the designer
controlled word plus 4. Furthermore, the size of the fakechunk must
be must be located no more than 64 bytes away from the target. This
is 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 the
target.
There is one more requirement for the layout of the fakechunk data
which will be described shortly. For the moment, assume that all of
the above conditions have been met, and that a call to free() is
made on the suitable fakechunk. A call to free() is handled by a
wrapper function called public_fREe():
void
public_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 overflowed
to point to a fakechunk. This is converted to the "corresponding
chunk" of the fakechunk's data, and passed to arena_for_chunk() in
order to find the corresponding arena. In order to avoid special
treatment as an mmap() chunk, and also to get a sensible arena, the
size field of the fakechunk header must have the IS_MMAPPED and
NON_MAIN_ARENA bits cleared. To do this, the designer can simply
ensure that the fake size is a multiple of 8. This would mean the
internal 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 of
Spirit. The designer controlled value of mem is again converted to
a chunk and the fake size value is extracted. Since size is
designer controlled, the fastbin code can be triggered simply by
ensuring that it is less than av->max_fast, which has a default of
64 + 8. The final point of consideration in the layout of the
fakechunk is the nextsize integrity tests.
Since the size of the fakechunk has to be large enough to encompass
the target, the size of the nextchunk must be at an address higher
than the target. The nextsize integrity tests must be handled for
the fakechunk to be put in a fastbin, which means that there must
be yet another designer controlled value at an address higher than
the target.
The exact location of the designer controlled values directly
depend on the size of the allocation request that will subsequently
be used by the designer to overwrite the target. That is, if an
allocation request of N bytes is made (such that N <= 64), then the
designer's lower value must be within N bytes of the target and
must be equal to (N + 8). This is to ensure that the fakechunk is
put in the right fastbin for the subsequent allocation request.
Furthermore, the designer's upper value must be at (N + 8) bytes
above the lower value to ensure that the nextsize integrity tests
are passed.
If such a memory layout can be achieved, then the address of this
"structure" will be placed in a fastbin. The code for the
subsequent malloc() request that uses this arbitrary fastbin entry
is simple and need not be reproduced here. As far as _int_malloc()
is concerned the fake chunk that it is preparing to return to the
application is perfectly valid. Once this has occurred it is simply
up to the designer to manipulate the application in to overwriting
the 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就是有效的。只要這種情況發生了,那麼操縱應用來重寫目標就非常簡單了。