description | cover | coverY |
---|---|---|
06/26/2024 |
-8 |
Attacking dynamic memory region vulnerabilities!
{% hint style="info" %} :rotating_light: Let me just start this one off as a preface:
Wow, if you thought heap exploitation was crazy before, just wait until you finish reading this one. {% endhint %}
{% embed url="https://www.synacktiv.com/en/publications/exploring-android-heap-allocations-in-jemalloc-new" %} Synack {% endembed %}
{% embed url="https://ir0nstone.gitbook.io/notes/types/heap" %} ir0nstone {% endembed %}
Wait, Heap Feng Shui?
{% hint style="info" %} :biohazard: This is an "Exploit Delivery Technique". {% endhint %}
This helps an attacker to be able to replace newly freed objects with objects of the attacker's choice.
Knowing information and sizing ahead of time will allow us to overwrite important objects on the heap.
- This really comes in handy with attacks such as Use-After-Free (UAF's)
This is because when an object becomes freed (free()
), the location itself is now freed, but the object pointer still remains available to the attacker. This is known as a dangling pointer. I always pictured dangling pointers as being similar to the Anglerfish that can be found within the deepest parts of the ocean, known as abysses. Better yet, a Danglerfish 😉.
Simply put, a dangling pointer is a pointer that has been recently freed but it's still a pointer that points to invalid data. This can lead to unexpected results or code execution.
Depiction of a dangling pointer. -- Danglerfish
Different allocation regions when allocating memory with JEMalloc
Given the following C code:
#include <stdio.h>
#include <stdlib.h>
int main() {
size_t size = 1337; // Number of bytes to allocate
void *ptr;
// Allocate memory dynamically for 512 bytes
ptr = malloc(size);
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
printf("Memory allocated successfully: %zu bytes\n", size);
// Free the allocated memory
free(ptr);
return 0;
}
Output:
Memory allocated successfully: 1337 bytes
We have allocated 1,337-bytes of data within the heap memory region of the virtual process space.
This means that we our object will be stored within the 22nd bucket (23rd if you're counting from 0, but still 22nd from labeling) with a max of 1,536 bytes that can be allocated. It can't be stored in the 21st bucket as it is only optimized for 1,280-bytes, not enough for 1,337.
This means when we are spraying the heap, we'll be able to spray for the same sized object.
Visual aid for allocating 1,337-bytes on the heap -- It will be stored within the 22nd bucket