Libc Heap
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Osnove heap-a
The heap je ustvari mesto gde program može da skladišti podatke kada ih zatraži pozivanjem funkcija kao što su malloc, calloc… Kada ta memorija više nije potrebna, oslobađa se pozivanjem funkcije free.
Kao što je prikazano, nalazi se odmah nakon učitanog binarnog fajla u memoriji (pogledajte sekciju [heap]):
.png)
Osnovna alokacija chunk-ova
Kada se zatraži čuvanje podataka na heap-u, za njih se rezerviše prostor u heap-u. Taj prostor će pripadati jednoj bin-i i biće rezervisano samo traženi podaci + prostor zaglavlja bina + minimalni offset veličine bina za chunk. Cilj je rezervisati što manje memorije bez komplikovanja pronalaženja gde se svaki chunk nalazi. Za to se koristi metadata chunk informacija da se zna gde su zauzeti/slobodni chunk-ovi.
Postoje različiti načini rezervisanja prostora, uglavnom zavisno od korišćenog bina, ali opšta metodologija je sledeća:
- Program započinje tako što zahteva određenu količinu memorije.
- Ako u listi chunk-ova postoji neki dovoljno veliki da zadovolji zahtev, biće iskorišćen.
- To može značiti i da će deo dostupnog chunk-a biti iskorišćen za ovaj zahtev, a ostatak će biti dodat u listu chunk-ova.
- Ako u listi nema dostupnog chunk-a, ali još ima prostora u već alociranoj heap memoriji, heap manager kreira novi chunk.
- Ako nema dovoljno heap prostora za novi chunk, heap manager traži od kernel-a da proširi memoriju dodeljenu heap-u i potom koristi tu memoriju za kreiranje novog chunk-a.
- Ako sve propadne,
mallocreturns null.
Imajte na umu da ako tražena memorija prelazi određeni prag, mmap će biti korišćen za mapiranje tražene memorije.
Arenas
U multithreaded aplikacijama, heap manager mora da spreči race conditions koje bi mogle dovesti do padova. Inicialno se to radilo pomoću global mutex-a kako bi se osiguralo da samo jedan thread pristupa heap-u u datom trenutku, ali to je izazivalo probleme sa performansama zbog uskog grla koje stvara mutex.
Da bi se to rešilo, ptmalloc2 heap allocator je uveo “arenas”, gde svaka arena funkcioniše kao poseban heap sa sopstvenim strukturama podataka i mutex-om, što omogućava više thread-ova da rade operacije nad heap-om bez međusobnog ometanja, sve dok koriste različite aren-e.
Podrazumevana “main” arena obrađuje operacije nad heap-om za single-threaded aplikacije. Kada se dodaju novi thread-ovi, heap manager im dodeljuje sekundarne arene da bi smanjio konkurenciju. Prvo pokušava da pridruži svaki novi thread neiskorišćenoj areni, kreirajući nove po potrebi, do ograničenja od 2 puta broja CPU jezgara za 32-bit sisteme i 8 puta za 64-bit sisteme. Kada se dostigne limit, thread-ovi moraju deliti arene, što može dovesti do konkurencije.
Za razliku od main arene, koja se širi koristeći brk system call, sekundarne arene kreiraju “subheaps” koristeći mmap i mprotect da bi simulirale ponašanje heap-a, omogućavajući fleksibilnost u upravljanju memorijom za multithreaded operacije.
Subheaps
Subheaps služe kao rezervni memorijski regioni za sekundarne arene u multithreaded aplikacijama, dopuštajući im da rastu i upravljaju sopstvenim heap regionima nezavisno od inicijalnog heap-a. Evo kako se subheaps razlikuju od inicijalnog heap-a i kako rade:
- Initial Heap vs. Subheaps:
- Inicijalni heap se nalazi neposredno nakon binarnog fajla u memoriji i širi se koristeći
sbrksystem call. - Subheaps, koje koriste sekundarne arene, kreiraju se preko
mmap, system call-a koji mapira navedeni memorijski region.
- Memory Reservation with
mmap:
- Kada heap manager kreira subheap, rezerviše veliki blok memorije preko
mmap. Ta rezervacija ne alocira odmah fizičku memoriju; samo označava region koji drugi sistemski procesi ili alokacije ne bi trebalo da koriste. - Po default-u, rezervisana veličina za subheap je 1 MB za 32-bit procese i 64 MB za 64-bit procese.
- Gradual Expansion with
mprotect:
- Rezervisani memorijski region je inicijalno označen kao
PROT_NONE, što znači da kernel još ne mora da alocira fizičku memoriju za taj prostor. - Da bi “porastao” subheap, heap manager koristi
mprotectda promeni dozvole stranica izPROT_NONEuPROT_READ | PROT_WRITE, što tera kernel da alocira fizičku memoriju za prethodno rezervisane adrese. Ovakav korak-po-korak pristup omogućava subheap-u da se širi po potrebi. - Kada se ceo subheap potroši, heap manager kreira novi subheap da bi nastavio alokaciju.
heap_info
Ovaj struct sadrži relevantne informacije o heap-u. Takođe, heap memorija možda neće biti kontinualna nakon više alokacija, pa će ovaj struct čuvati i te informacije.
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/arena.c#L837
typedef struct _heap_info
{
mstate ar_ptr; /* Arena for this heap. */
struct _heap_info *prev; /* Previous heap. */
size_t size; /* Current size in bytes. */
size_t mprotect_size; /* Size in bytes that has been mprotected
PROT_READ|PROT_WRITE. */
size_t pagesize; /* Page size used when allocating the arena. */
/* Make sure the following data is properly aligned, particularly
that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
MALLOC_ALIGNMENT. */
char pad[-3 * SIZE_SZ & MALLOC_ALIGN_MASK];
} heap_info;
malloc_state
Svaki heap (main arena or other threads arenas) ima malloc_state strukturu.
Važno je primetiti da je main arena malloc_state struktura globalna promenljiva u libc-u (dakle smeštena u memorijskom prostoru libc-a).
U slučaju malloc_state struktura heap-ova kod threads, one se nalaze unutar sopstvenog thread “heap”-a.
Ima nekoliko zanimljivih stvari koje treba primetiti iz ove strukture (see C code below):
-
__libc_lock_define (, mutex);služi da osigura da se ovoj strukturi iz heap-a pristupa po 1 thread u isto vreme -
Flags:
-
#define NONCONTIGUOUS_BIT (2U)
#define contiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) == 0) #define noncontiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) != 0) #define set_noncontiguous(M) ((M)->flags |= NONCONTIGUOUS_BIT) #define set_contiguous(M) ((M)->flags &= ~NONCONTIGUOUS_BIT)
- The `mchunkptr bins[NBINS * 2 - 2];` sadrži **pointers** na **prvi i poslednji chunks** malih, velikih i unsorted **bins** (to -2 je zato što se indeks 0 ne koristi)
- Dakle, **first chunk** ovih bins će imati **backwards pointer ka ovoj strukturi**, a **last chunk** ovih bins će imati **forward pointer** ka ovoj strukturi. To praktično znači da ako možete **leak these addresses in the main arena** imaćete pointer na strukturu u **libc**.
- Strukture `struct malloc_state *next;` i `struct malloc_state *next_free;` formiraju povezane liste arena
- `top` chunk je poslednji "chunk", koji predstavlja praktično **ceo preostali prostor heap-a**. Kada je top chunk "prazan", heap je u potpunosti iskorišćen i mora da zatraži više prostora.
- `last reminder` chunk nastaje u slučajevima kada chunk tačne veličine nije dostupan i zato se veći chunk razdeli, a pokazivač na preostali deo se smesti ovde.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1812
struct malloc_state
{
/* Serialize access. */
__libc_lock_define (, mutex);
/* Flags (formerly in max_fast). */
int flags;
/* Set if the fastbin chunks contain recently inserted free blocks. */
/* Note this is a bool but not all targets support atomics on booleans. */
int have_fastchunks;
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
malloc_chunk
Ova struktura predstavlja određeni chunk memorije. Različita polja imaju različito značenje za alocirane i nealocirane chunk-ove.
// https://github.com/bminor/glibc/blob/master/malloc/malloc.c
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk_nextsize;
};
typedef struct malloc_chunk* mchunkptr;
Kao što je ranije komentarisano, ovi chunks takođe imaju neke metapodatke, veoma dobro prikazane na ovoj slici:
.png)
https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png
Metapodaci su obično 0x08B i označavaju trenutnu veličinu chunka koristeći poslednja 3 bita za označavanje:
A: Ako je 1 dolazi iz subheap-a, ako je 0 nalazi se u main arenaM: Ako je 1, ovaj chunk je deo prostora alociranog sa mmap i nije deo heap-aP: Ako je 1, prethodni chunk je u upotrebi
Zatim sledi prostor za user data, i na kraju 0x08B koji označava veličinu prethodnog chunka kada je chunk dostupan (ili služi za čuvanje user data kada je alociran).
Štaviše, kada je dostupan, user data se koristi i za čuvanje sledećih podataka:
fd: Pokazivač na sledeći chunkbk: Pokazivač na prethodni chunkfd_nextsize: Pokazivač na prvi chunk u listi koji je manji od njega samogbk_nextsize: Pokazivač na prvi chunk u listi koji je veći od njega
.png)
https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png
Tip
Pogledajte kako povezivanje liste na ovaj način uklanja potrebu za nizom u kojem bi svaki chunk bio registrovan.
Chunk Pointers
Kada se koristi malloc, vraća se pokazivač na sadržaj u koji se može pisati (upravo posle headers), međutim, pri upravljanju chunks-ima, potreban je pokazivač na početak headers (metapodataka).
Za ove konverzije koriste se sledeće funkcije:
// https://github.com/bminor/glibc/blob/master/malloc/malloc.c
/* Convert a chunk address to a user mem pointer without correcting the tag. */
#define chunk2mem(p) ((void*)((char*)(p) + CHUNK_HDR_SZ))
/* Convert a user mem pointer to a chunk address and extract the right tag. */
#define mem2chunk(mem) ((mchunkptr)tag_at (((char*)(mem) - CHUNK_HDR_SZ)))
/* The smallest possible chunk */
#define MIN_CHUNK_SIZE (offsetof(struct malloc_chunk, fd_nextsize))
/* The smallest size we can malloc is an aligned minimal chunk */
#define MINSIZE \
(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
Poravnanje i minimalna veličina
Pointer ka chunk-u i 0x0f moraju biti 0.
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/sysdeps/generic/malloc-size.h#L61
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
// https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/sysdeps/i386/malloc-alignment.h
#define MALLOC_ALIGNMENT 16
// https://github.com/bminor/glibc/blob/master/malloc/malloc.c
/* Check if m has acceptable alignment */
#define aligned_OK(m) (((unsigned long)(m) & MALLOC_ALIGN_MASK) == 0)
#define misaligned_chunk(p) \
((uintptr_t)(MALLOC_ALIGNMENT == CHUNK_HDR_SZ ? (p) : chunk2mem (p)) \
& MALLOC_ALIGN_MASK)
/* pad request bytes into a usable size -- internal version */
/* Note: This must be a macro that evaluates to a compile time constant
if passed a literal constant. */
#define request2size(req) \
(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
MINSIZE : \
((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
/* Check if REQ overflows when padded and aligned and if the resulting
value is less than PTRDIFF_T. Returns the requested size or
MINSIZE in case the value is less than MINSIZE, or 0 if any of the
previous checks fail. */
static inline size_t
checked_request2size (size_t req) __nonnull (1)
{
if (__glibc_unlikely (req > PTRDIFF_MAX))
return 0;
/* When using tagged memory, we cannot share the end of the user
block with the header for the next chunk, so ensure that we
allocate blocks that are rounded up to the granule size. Take
care not to overflow from close to MAX_SIZE_T to a small
number. Ideally, this would be part of request2size(), but that
must be a macro that produces a compile time constant if passed
a constant literal. */
if (__glibc_unlikely (mtag_enabled))
{
/* Ensure this is not evaluated if !mtag_enabled, see gcc PR 99551. */
asm ("");
req = (req + (__MTAG_GRANULE_SIZE - 1)) &
~(size_t)(__MTAG_GRANULE_SIZE - 1);
}
return request2size (req);
}
Imajte na umu da se pri izračunavanju ukupnog potrebnog prostora SIZE_SZ dodaje samo jednom zato što se polje prev_size može koristiti za čuvanje podataka; dakle potrebno je samo početno zaglavlje.
Dohvatanje podataka chunk-a i izmena metapodataka
Ove funkcije rade tako što primaju pokazivač na chunk i korisne su za proveru/izmenu metapodataka:
- Provera chunk flagova
// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c
/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
#define PREV_INUSE 0x1
/* extract inuse bit of previous chunk */
#define prev_inuse(p) ((p)->mchunk_size & PREV_INUSE)
/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
#define IS_MMAPPED 0x2
/* check for mmap()'ed chunk */
#define chunk_is_mmapped(p) ((p)->mchunk_size & IS_MMAPPED)
/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
from a non-main arena. This is only set immediately before handing
the chunk to the user, if necessary. */
#define NON_MAIN_ARENA 0x4
/* Check for chunk from main arena. */
#define chunk_main_arena(p) (((p)->mchunk_size & NON_MAIN_ARENA) == 0)
/* Mark a chunk as not being on the main arena. */
#define set_non_main_arena(p) ((p)->mchunk_size |= NON_MAIN_ARENA)
- Veličine i pokazivači na druge chunks
/*
Bits to mask off when extracting size
Note: IS_MMAPPED is intentionally not masked off from size field in
macros for which mmapped chunks should never be seen. This should
cause helpful core dumps to occur if it is tried by accident by
people extending or adapting this malloc.
*/
#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
/* Get size, ignoring use bits */
#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))
/* Like chunksize, but do not mask SIZE_BITS. */
#define chunksize_nomask(p) ((p)->mchunk_size)
/* Ptr to next physical malloc_chunk. */
#define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p)))
/* Size of the chunk below P. Only valid if !prev_inuse (P). */
#define prev_size(p) ((p)->mchunk_prev_size)
/* Set the size of the chunk below P. Only valid if !prev_inuse (P). */
#define set_prev_size(p, sz) ((p)->mchunk_prev_size = (sz))
/* Ptr to previous physical malloc_chunk. Only valid if !prev_inuse (P). */
#define prev_chunk(p) ((mchunkptr) (((char *) (p)) - prev_size (p)))
/* Treat space at ptr + offset as a chunk */
#define chunk_at_offset(p, s) ((mchunkptr) (((char *) (p)) + (s)))
- Inuse bit
/* extract p's inuse bit */
#define inuse(p) \
((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)
/* set/clear chunk as being inuse without otherwise disturbing */
#define set_inuse(p) \
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size |= PREV_INUSE
#define clear_inuse(p) \
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size &= ~(PREV_INUSE)
/* check/set/clear inuse bits in known places */
#define inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)
#define set_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)
#define clear_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
- Podesi head i footer (kada su chunk nos u upotrebi
/* Set size at head, without disturbing its use bit */
#define set_head_size(p, s) ((p)->mchunk_size = (((p)->mchunk_size & SIZE_BITS) | (s)))
/* Set size/use field */
#define set_head(p, s) ((p)->mchunk_size = (s))
/* Set size at footer (only when chunk is not in use) */
#define set_foot(p, s) (((mchunkptr) ((char *) (p) + (s)))->mchunk_prev_size = (s))
- Dobij veličinu stvarno upotrebljivih podataka unutar chunk-a
#pragma GCC poison mchunk_size
#pragma GCC poison mchunk_prev_size
/* This is the size of the real usable data in the chunk. Not valid for
dumped heap chunks. */
#define memsize(p) \
(__MTAG_GRANULE_SIZE > SIZE_SZ && __glibc_unlikely (mtag_enabled) ? \
chunksize (p) - CHUNK_HDR_SZ : \
chunksize (p) - CHUNK_HDR_SZ + (chunk_is_mmapped (p) ? 0 : SIZE_SZ))
/* If memory tagging is enabled the layout changes to accommodate the granule
size, this is wasteful for small allocations so not done by default.
Both the chunk header and user data has to be granule aligned. */
_Static_assert (__MTAG_GRANULE_SIZE <= CHUNK_HDR_SZ,
"memory tagging is not supported with large granule.");
static __always_inline void *
tag_new_usable (void *ptr)
{
if (__glibc_unlikely (mtag_enabled) && ptr)
{
mchunkptr cp = mem2chunk(ptr);
ptr = __libc_mtag_tag_region (__libc_mtag_new_tag (ptr), memsize (cp));
}
return ptr;
}
Primeri
Brz heap primer
Brz heap primer iz https://guyinatuxedo.github.io/25-heap/index.html ali za arm64:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(void)
{
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
}
Postavite breakpoint na kraju main funkcije i hajde da otkrijemo gde je informacija uskladištena:
.png)
Može se videti da je string panda uskladišten na 0xaaaaaaac12a0 (što je adresa koju je vraćao malloc u x0). Proverom 0x10 bajtova pre, može se videti da 0x0 predstavlja da je prethodni chunk nije korišćen (dužina 0) i da je dužina ovog chunka 0x21.
Dodatni rezervisani prostor (0x21-0x10=0x11) potiče od dodatih headera (0x10) i 0x1 ne znači da je rezervisano 0x21B, već da poslednja 3 bita dužine trenutnog headera imaju posebna značenja. Pošto je dužina uvek poravnata na 16 bajtova (na 64-bitnim mašinama), ovi bitovi se zapravo nikada neće koristiti za broj dužine.
0x1: Previous in Use - Specifies that the chunk before it in memory is in use
0x2: Is MMAPPED - Specifies that the chunk was obtained with mmap()
0x4: Non Main Arena - Specifies that the chunk was obtained from outside of the main arena
Primer multithreadinga
Multithread
```c #includevoid* threadFuncMalloc(void* arg) { printf(“Hello from thread 1\n”); char* addr = (char*) malloc(1000); printf(“After malloc and before free in thread 1\n”); free(addr); printf(“After free in thread 1\n”); }
void* threadFuncNoMalloc(void* arg) { printf(“Hello from thread 2\n”); }
int main() { pthread_t t1; void* s; int ret; char* addr;
printf(“Before creating thread 1\n”); getchar(); ret = pthread_create(&t1, NULL, threadFuncMalloc, NULL); getchar();
printf(“Before creating thread 2\n”); ret = pthread_create(&t1, NULL, threadFuncNoMalloc, NULL);
printf(“Before exit\n”); getchar();
return 0; }
</details>
Debagovanjem prethodnog primera može se videti kako na početku postoji samo 1 arena:
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Zatim, nakon poziva prvog thread-a, onog koji poziva malloc, kreira se nova arena:
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
i u njoj se mogu naći neki chunks:
<figure><img src="../../images/image (2) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
## Bins & Memory Allocations/Frees
Pogledaj koje su bins, kako su organizovani i kako se memorija dodeljuje i oslobađa u:
<a class="content_ref" href="bins-and-memory-allocations.md"><span class="content_ref_label">Bins & Memory Allocations</span></a>
## Provere sigurnosti Heap funkcija
Funkcije koje rade sa heap-om izvršiće određene provere pre nego što obave svoje akcije kako bi pokušale da se uvere da heap nije korumpiran:
<a class="content_ref" href="heap-memory-functions/heap-functions-security-checks.md"><span class="content_ref_label">Heap Functions Security Checks</span></a>
## musl mallocng exploitation notes (Alpine)
- **Slab group/slot grooming for huge linear copies:** mallocng sizeclasses koriste mmap()'d groups čiji su slots u potpunosti `munmap()`'d kada su prazni. Za duge linearne kopije (~0x15555555 bytes), zadržite span mapiran (izbegavajte rupe od oslobođenih grupa) i postavite victim allocation pored source slot-a.
- **Cycling offset mitigation:** Pri ponovnom korišćenju slot-a mallocng može pomeriti početak user-data za `UNIT` (0x10) višekratnike kada slack primi dodatni 4-byte header. Ovo pomera overwrite offsets (npr. LSB pointer hits) osim ako ne kontrolišete reuse counts ili se držite strides bez slack-a (npr. Lua `Table` objekti sa stride 0x50 pokazuju offset 0). Ispitajte offset-e pomoću muslheap’s `mchunkinfo`:
```gdb
pwndbg> mchunkinfo 0x7ffff7a94e40
... stride: 0x140
... cycling offset : 0x1 (userdata --> 0x7ffff7a94e40)
- Preferirajte korupciju runtime-objekata umesto metapodataka alokatora: mallocng meša cookies/guarded out-of-band metadata, pa ciljate objekte višeg nivoa. U Redis-ovom Lua 5.1,
Table->arraypokazuje na nizTValuetagged vrednosti; prepisivanje LSB-a pokazivača uTValue->value(npr. sa JSON terminator bajtom0x22) može pivotirati reference bez dodirivanja malloc metapodataka. - Debugovanje stripped/static Lua na Alpine: Sastavite odgovarajući Lua, izlistajte simbole sa
readelf -Ws, uklonite simbolе funkcija pomoćuobjcopy --strip-symbolda biste izložili raspored struktura u GDB, zatim koristite Lua-aware pretty-printers (GdbLuaExtension for Lua 5.1) zajedno sa muslheap da proverite stride/reserved/cycling-offset vrednosti pre aktiviranja overflow-a.
Studije slučaja
Istražite primitivе specifične za alokator izvedene iz stvarnih grešaka:
Virtualbox Slirp Nat Packet Heap Exploitation
Gnu Obstack Function Pointer Hijack
References
- https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/
- https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/
- Pumping Iron on the Musl Heap – Real World CVE-2022-24834 Exploitation on an Alpine mallocng Heap
- musl mallocng enframe (v1.2.4)
- muslheap GDB plugin
- GdbLuaExtension (Lua 5.1 support)
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.


