Bins & Memory Allocations
Tip
AWS ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:HackTricks Training GCP Red Team Expert (GRTE)
Azure ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks μ§μνκΈ°
- ꡬλ κ³ν νμΈνκΈ°!
- **π¬ λμ€μ½λ κ·Έλ£Ή λλ ν λ κ·Έλ¨ κ·Έλ£Ήμ μ°Έμ¬νκ±°λ νΈμν° π¦ @hacktricks_liveλ₯Ό νλ‘μ°νμΈμ.
- HackTricks λ° HackTricks Cloud κΉνλΈ λ¦¬ν¬μ§ν 리μ PRμ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.
Basic Information
μ²ν¬κ° μ μ₯λλ ν¨μ¨μ±μ κ°μ νκΈ° μν΄, κ° μ²ν¬λ λ¨μΌ μ°κ²° 리μ€νΈμλ§ μμ§ μκ³ μ¬λ¬ μ νμ΄ μμ΅λλ€. μ΄κ²μ΄ λ°λ‘ λΉ(bins)μ΄λ©°, 5κ°μ§ μ νμ λΉμ΄ μμ΅λλ€: 62 μμ λΉ, 63 ν° λΉ, 1 μ λ ¬λμ§ μμ λΉ, 10 λΉ λ₯Έ λΉ λ° 64 μ€λ λλΉ tcache λΉ.
κ° μ λ ¬λμ§ μμ, μμ λ° ν° λΉμ λν μ΄κΈ° μ£Όμλ λμΌν λ°°μ΄ λ΄μ μμ΅λλ€. μΈλ±μ€ 0μ μ¬μ©λμ§ μμΌλ©°, 1μ μ λ ¬λμ§ μμ λΉ, 2-64λ μμ λΉ, 65-127μ ν° λΉμ λλ€.
Tcache (Per-Thread Cache) Bins
μ€λ λκ° μμ μ νμ κ°μ§λ €κ³ μλνλλΌλ(see Arenas and Subheaps), λ§μ μ€λ λλ₯Ό κ°μ§ νλ‘μΈμ€(μ: μΉ μλ²)κ° λ€λ₯Έ μ€λ λμ νμ 곡μ ν κ°λ₯μ±μ΄ μμ΅λλ€. μ΄ κ²½μ°, μ£Όμ ν΄κ²°μ± μ **λ½(lockers)**μ μ¬μ©μ΄λ©°, μ΄λ μ€λ λλ₯Ό μλΉν λλ¦¬κ² λ§λ€ μ μμ΅λλ€.
λ°λΌμ, tcacheλ μ²ν¬λ₯Ό λ³ν©νμ§ μλ λ¨μΌ μ°κ²° 리μ€νΈλΌλ μ μμ μ€λ λλΉ λΉ λ₯Έ λΉκ³Ό μ μ¬ν©λλ€. κ° μ€λ λλ 64κ°μ λ¨μΌ μ°κ²° tcache λΉμ κ°μ§λλ€. κ° λΉμ 7κ°μ λμΌν ν¬κΈ°μ μ²ν¬λ₯Ό κ°μ§ μ μμΌλ©°, ν¬κΈ°λ 64λΉνΈ μμ€ν μμ 24Bμμ 1032B, 32λΉνΈ μμ€ν μμ 12Bμμ 516Bμ λλ€.
μ€λ λκ° μ²ν¬λ₯Ό ν΄μ ν λ, tcacheμ ν λΉλ μ μμ λ§νΌ ν¬μ§ μλ€λ©΄ ν΄λΉ tcache λΉμ΄ κ°λ μ°¨ μμ§ μλ€λ©΄(μ΄λ―Έ 7κ°μ μ²ν¬κ° μλ κ²½μ°), κ±°κΈ°μ ν λΉλ©λλ€. tcacheλ‘ κ° μ μλ€λ©΄, μ μμ μΌλ‘ ν΄μ μμ μ μννκΈ° μν΄ ν λ½μ κΈ°λ€λ €μΌ ν©λλ€.
μ²ν¬κ° ν λΉλ λ, νμν ν¬κΈ°μ λ¬΄λ£ μ²ν¬κ° Tcacheμ μλ€λ©΄ μ¬μ©νκ³ , κ·Έλ μ§ μμΌλ©΄ μ μ λΉμμ νλλ₯Ό μ°Ύκ±°λ μλ‘ μμ±νκΈ° μν΄ ν λ½μ κΈ°λ€λ €μΌ ν©λλ€.
λν μ΅μ νκ° μμΌλ©°, μ΄ κ²½μ° ν λ½μ κ°μ§ μνμμ μ€λ λλ μμ²λ ν¬κΈ°μ ν μ²ν¬(7)λ‘ Tcacheλ₯Ό μ±μλλ€, λ°λΌμ λ νμν κ²½μ° Tcacheμμ μ°Ύμ μ μμ΅λλ€.
Add a tcache chunk example
```c #includeint main(void) { char *chunk; chunk = malloc(24); printf(βAddress of the chunk: %p\nβ, (void *)chunk); gets(chunk); free(chunk); return 0; }
μ»΄νμΌνκ³ main ν¨μμ ret opcodeμμ μ€λ¨μ μ μ€μ νμ¬ λλ²κΉ
ν©λλ€. κ·Έλ° λ€μ gefλ₯Ό μ¬μ©νμ¬ μ¬μ© μ€μΈ tcache binμ νμΈν μ μμ΅λλ€:
```bash
gefβ€ heap bins
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Tcachebins for thread 1 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tcachebins[idx=0, size=0x20, count=1] β Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
Tcache ꡬ쑰체 λ° ν¨μ
λ€μ μ½λμμλ max binsμ chunks per index, μ΄μ€ ν΄μ λ₯Ό λ°©μ§νκΈ° μν΄ μμ±λ tcache_entry ꡬ쑰체μ κ° μ€λ λκ° binμ κ° μΈλ±μ€μ λν μ£Όμλ₯Ό μ μ₯νλ λ° μ¬μ©νλ **tcache_perthread_struct**λ₯Ό λ³Ό μ μμ΅λλ€.
tcache_entry λ° tcache_perthread_struct
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c
/* We want 64 entries. This is an arbitrary limit, which tunables can reduce. */
define TCACHE_MAX_BINS 64
define MAX_TCACHE_SIZE tidx2usize (TCACHE_MAX_BINS-1)
/* Only used to pre-fill the tunables. */
define tidx2usize(idx) (((size_t) idx) * MALLOC_ALIGNMENT + MINSIZE - SIZE_SZ)
/* When βxβ is from chunksize(). */
define csize2tidx(x) (((x) - MINSIZE + MALLOC_ALIGNMENT - 1) / MALLOC_ALIGNMENT)
/* When βxβ is a user-provided size. */
define usize2tidx(x) csize2tidx (request2size (x))
/* With rounding and alignment, the bins are⦠idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit) idx 1 bytes 25..40 or 13..20 idx 2 bytes 41..56 or 21..28 etc. */
/* This is another arbitrary limit, which tunables can change. Each tcache bin will hold at most this number of chunks. */
define TCACHE_FILL_COUNT 7
/* Maximum chunks in tcache bins for tunables. This value must fit the range of tcache->counts[] entries, else they may overflow. */
define MAX_TCACHE_COUNT UINT16_MAX
[β¦]
typedef struct tcache_entry { struct tcache_entry next; / This field exists to detect double frees. */ uintptr_t key; } tcache_entry;
/* There is one of these for each thread, which contains the per-thread cache (hence βtcache_perthread_structβ). Keeping overall size low is mildly important. Note that COUNTS and ENTRIES are redundant (we could have just counted the linked list each time), this is for performance reasons. */ typedef struct tcache_perthread_struct { uint16_t counts[TCACHE_MAX_BINS]; tcache_entry *entries[TCACHE_MAX_BINS]; } tcache_perthread_struct;
</details>
ν¨μ `__tcache_init`λ `tcache_perthread_struct` κ°μ²΄λ₯Ό μμ±νκ³ κ³΅κ°μ ν λΉνλ ν¨μμ
λλ€.
<details>
<summary>tcache_init μ½λ</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3241C1-L3274C2
static void
tcache_init(void)
{
mstate ar_ptr;
void *victim = 0;
const size_t bytes = sizeof (tcache_perthread_struct);
if (tcache_shutting_down)
return;
arena_get (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
if (!victim && ar_ptr != NULL)
{
ar_ptr = arena_get_retry (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
}
if (ar_ptr != NULL)
__libc_lock_unlock (ar_ptr->mutex);
/* In a low memory situation, we may not be able to allocate memory
- in which case, we just keep trying later. However, we
typically do this very early, so either there is sufficient
memory, or there isn't enough memory to do non-trivial
allocations anyway. */
if (victim)
{
tcache = (tcache_perthread_struct *) victim;
memset (tcache, 0, sizeof (tcache_perthread_struct));
}
}
Tcache μΈλ±μ€
Tcacheλ ν¬κΈ°μ κ° μΈλ±μ€μ 첫 λ²μ§Έ μ²ν¬μ λν μ΄κΈ° ν¬μΈν° λ° μΈλ±μ€λΉ μ²ν¬ μκ° μ²ν¬ λ΄λΆμ μμΉνλ μ¬λ¬ κ°μ λΉμ κ°μ§κ³ μμ΅λλ€. μ΄λ μ΄ μ 보λ₯Ό κ°μ§ μ²ν¬(λ³΄ν΅ μ²« λ²μ§Έ)λ₯Ό μ°ΎμΌλ©΄ λͺ¨λ tcache μ΄κΈ° ν¬μΈνΈμ Tcache μ²ν¬μ μλ₯Ό μ°Ύμ μ μμμ μλ―Έν©λλ€.
λΉ λ₯Έ λΉ
λΉ λ₯Έ λΉμ μμ μ²ν¬μ λν λ©λͺ¨λ¦¬ ν λΉ μλλ₯Ό λμ΄κΈ° μν΄ μ΅κ·Όμ ν΄μ λ μ²ν¬λ₯Ό λΉ λ₯Έ μ κ·Ό ꡬ쑰μ μ μ§νλλ‘ μ€κ³λμμ΅λλ€. μ΄ λΉμ νμ μ μΆ(LIFO) λ°©μμ μ¬μ©νλ―λ‘, κ°μ₯ μ΅κ·Όμ ν΄μ λ μ²ν¬κ° μλ‘μ΄ ν λΉ μμ²μ΄ μμ λ κ°μ₯ λ¨Όμ μ¬μ¬μ©λ©λλ€. μ΄ λμμ μλμ μ 리νλ©°, μ€νμ 맨 μμμ μ½μ νκ³ μ κ±°νλ κ²μ΄ ν(FIFO)λ³΄λ€ λΉ λ¦ λλ€.
λν, λΉ λ₯Έ λΉμ λ¨μΌ μ°κ²° 리μ€νΈλ₯Ό μ¬μ©νλ©°, μ΄μ€ μ°κ²° 리μ€νΈλ₯Ό μ¬μ©νμ§ μμ μλκ° λμ± ν₯μλ©λλ€. λΉ λ₯Έ λΉμ μ²ν¬λ μ΄μκ³Ό λ³ν©λμ§ μκΈ° λλ¬Έμ μ€κ°μμ μ κ±°ν μ μλ 볡μ‘ν κ΅¬μ‘°κ° νμνμ§ μμ΅λλ€. λ¨μΌ μ°κ²° 리μ€νΈλ μ΄λ¬ν μμ μ λν΄ λ κ°λ¨νκ³ λΉ λ¦ λλ€.
κΈ°λ³Έμ μΌλ‘ μ¬κΈ°μ λ°μνλ κ²μ ν€λ(νμΈν 첫 λ²μ§Έ μ²ν¬μ λν ν¬μΈν°)κ° νμ ν΄λΉ ν¬κΈ°μ μ΅μ ν΄μ λ μ²ν¬λ₯Ό κ°λ¦¬ν€κ³ μλ€λ κ²μ λλ€. κ·Έλμ:
- ν΄λΉ ν¬κΈ°μ μλ‘μ΄ μ²ν¬κ° ν λΉλλ©΄ ν€λλ μ¬μ©ν μ μλ λ¬΄λ£ μ²ν¬λ₯Ό κ°λ¦¬ν΅λλ€. μ΄ λ¬΄λ£ μ²ν¬κ° λ€μ μ¬μ©ν μ²ν¬λ₯Ό κ°λ¦¬ν€λ―λ‘ μ΄ μ£Όμκ° ν€λμ μ μ₯λμ΄ λ€μ ν λΉμ΄ μ¬μ© κ°λ₯ν μ²ν¬λ₯Ό μ΄λμ κ°μ Έμ¬μ§ μ μ μμ΅λλ€.
- μ²ν¬κ° ν΄μ λλ©΄ λ¬΄λ£ μ²ν¬λ νμ¬ μ¬μ© κ°λ₯ν μ²ν¬μ λν μ£Όμλ₯Ό μ μ₯νκ³ , μ΄ μλ‘ ν΄μ λ μ²ν¬μ λν μ£Όμκ° ν€λμ λ£μ΄μ§λλ€.
μ°κ²° 리μ€νΈμ μ΅λ ν¬κΈ°λ 0x80μ΄λ©°, ν¬κΈ° 0x20μ μ²ν¬λ μΈλ±μ€ 0μ, ν¬κΈ° 0x30μ μ²ν¬λ μΈλ±μ€ 1μ λ°°μΉλ©λλ€β¦
Caution
λΉ λ₯Έ λΉμ μ²ν¬λ μ¬μ© κ°λ₯ μνλ‘ μ€μ λμ§ μμΌλ―λ‘ μ£Όλ³μ λ€λ₯Έ λ¬΄λ£ μ²ν¬μ λ³ν©λ μ μλ λμ μΌμ μκ° λμ λΉ λ₯Έ λΉ μ²ν¬λ‘ μ μ§λ©λλ€.
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
/*
Fastbins
An array of lists holding recently freed small chunks. Fastbins
are not doubly linked. It is faster to single-link them, and
since chunks are never removed from the middles of these lists,
double linking is not necessary. Also, unlike regular bins, they
are not even processed in FIFO order (they use faster LIFO) since
ordering doesn't much matter in the transient contexts in which
fastbins are normally used.
Chunks in fastbins keep their inuse bit set, so they cannot
be consolidated with other free chunks. malloc_consolidate
releases all chunks in fastbins and consolidates them with
other free chunks.
*/
typedef struct malloc_chunk *mfastbinptr;
#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])
/* offset 2 to use otherwise unindexable first 2 bins */
#define fastbin_index(sz) \
((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
/* The maximum fastbin request size we support */
#define MAX_FAST_SIZE (80 * SIZE_SZ / 4)
#define NFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) + 1)
λΉ λ₯Έ λΉ μ²ν¬ μμ μΆκ°
```c #includeint main(void) { char *chunks[8]; int i;
// Loop to allocate memory 8 times for (i = 0; i < 8; i++) { chunks[i] = malloc(24); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, βMemory allocation failed at iteration %d\nβ, i); return 1; } printf(βAddress of chunk %d: %p\nβ, i, (void *)chunks[i]); }
// Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); }
return 0; }
8κ°μ λμΌν ν¬κΈ°μ μ²ν¬λ₯Ό ν λΉνκ³ ν΄μ νλ λ°©λ²μ μ μνμ¬ tcacheλ₯Ό μ±μ°κ³ μ¬λ λ²μ§Έ μ²ν¬κ° λΉ λ₯Έ μ²ν¬μ μ μ₯λ©λλ€.
μ΄λ₯Ό μ»΄νμΌνκ³ `main` ν¨μμ `ret` opcodeμ μ€λ¨μ μ μ€μ νμ¬ λλ²κΉ
ν©λλ€. κ·Έλ° λ€μ `gef`λ₯Ό μ¬μ©νλ©΄ tcache λΉμ΄ κ°λ μ°¨ μκ³ νλμ μ²ν¬κ° λΉ λ₯Έ λΉμ μλ κ²μ λ³Ό μ μμ΅λλ€:
```bash
gefβ€ heap bins
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Tcachebins for thread 1 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tcachebins[idx=0, size=0x20, count=7] β Chunk(addr=0xaaaaaaac1770, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac1750, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac1730, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac1710, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac16f0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac16d0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Fastbins for arena at 0xfffff7f90b00 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Fastbins[idx=0, size=0x20] β Chunk(addr=0xaaaaaaac1790, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
Fastbins[idx=1, size=0x30] 0x00
μ λ ¬λμ§ μμ λΉ
μ λ ¬λμ§ μμ λΉμ λ©λͺ¨λ¦¬ ν λΉμ λ λΉ λ₯΄κ² νκΈ° μν΄ ν κ΄λ¦¬μμ μν΄ μ¬μ©λλ μΊμμ λλ€. μλ λ°©μμ λ€μκ³Ό κ°μ΅λλ€: νλ‘κ·Έλ¨μ΄ μ²ν¬λ₯Ό ν΄μ νλ©΄, μ΄ μ²ν¬κ° tcache λλ λΉ λ₯Έ λΉμ ν λΉλ μ μκ³ μ΅μμ μ²ν¬μ μΆ©λνμ§ μλ κ²½μ°, ν κ΄λ¦¬μλ μ¦μ μ΄λ₯Ό νΉμ μμ λΉμ΄λ ν° λΉμ λ£μ§ μμ΅λλ€. λμ , λ¨Όμ μΈμ ν λ¬΄λ£ μ²ν¬μ λ³ν©νμ¬ λ ν° λ¬΄λ£ λ©λͺ¨λ¦¬ λΈλ‘μ μμ±νλ €κ³ μλν©λλ€. κ·Έλ° λ€μ, μ΄ μλ‘μ΄ μ²ν¬λ₯Ό βμ λ ¬λμ§ μμ λΉβμ΄λΌκ³ λΆλ¦¬λ μΌλ° λΉμ λ°°μΉν©λλ€.
νλ‘κ·Έλ¨μ΄ λ©λͺ¨λ¦¬λ₯Ό μμ²νλ©΄, ν κ΄λ¦¬μλ μ λ ¬λμ§ μμ λΉμ νμΈνμ¬ μΆ©λΆν ν¬κΈ°μ μ²ν¬κ° μλμ§ νμΈν©λλ€. λ§μ½ μ°ΎμΌλ©΄ μ¦μ μ¬μ©ν©λλ€. μ λ ¬λμ§ μμ λΉμμ μ ν©ν μ²ν¬λ₯Ό μ°Ύμ§ λͺ»νλ©΄, μ΄ λͺ©λ‘μ λͺ¨λ μ²ν¬λ₯Ό ν¬κΈ°μ λ°λΌ ν΄λΉ λΉ(μμ λΉ λλ ν° λΉ)μΌλ‘ μ΄λν©λλ€.
λ ν° μ²ν¬κ° λ κ°μ μ λ°μΌλ‘ λλκ³ λλ¨Έμ§κ° MINSIZEλ³΄λ€ ν¬λ©΄, λ€μ μ λ ¬λμ§ μμ λΉμ λ°°μΉλ©λλ€.
λ°λΌμ μ λ ¬λμ§ μμ λΉμ μ΅κ·Όμ ν΄μ λ λ©λͺ¨λ¦¬λ₯Ό λΉ λ₯΄κ² μ¬μ¬μ©νμ¬ λ©λͺ¨λ¦¬ ν λΉ μλλ₯Ό λμ΄κ³ , μκ° μλͺ¨μ μΈ κ²μ λ° λ³ν©μ νμμ±μ μ€μ΄λ λ°©λ²μ λλ€.
Caution
μ²ν¬κ° μλ‘ λ€λ₯Έ λ²μ£Όμ μνλλΌλ, μ¬μ© κ°λ₯ν μ²ν¬κ° λ€λ₯Έ μ¬μ© κ°λ₯ν μ²ν¬μ μΆ©λνλ κ²½μ°(μλ μλ‘ λ€λ₯Έ λΉμ μνλλΌλ) λ³ν©λ©λλ€.
μ λ ¬λμ§ μμ μ²ν¬ μμ μΆκ°
```c #includeint main(void) { char *chunks[9]; int i;
// Loop to allocate memory 8 times for (i = 0; i < 9; i++) { chunks[i] = malloc(0x100); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, βMemory allocation failed at iteration %d\nβ, i); return 1; } printf(βAddress of chunk %d: %p\nβ, i, (void *)chunks[i]); }
// Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); }
return 0; }
9κ°μ λμΌν ν¬κΈ°μ μ²ν¬λ₯Ό ν λΉνκ³ ν΄μ νλ λ°©λ²μ μ£Όλͺ©νμΈμ. μ΄ μ²ν¬λ€μ **tcacheλ₯Ό μ±μ°κ³ **, μ¬λ λ²μ§Έ μ²ν¬λ **fastbinμ λΉν΄ λ무 컀μ** μ λ ¬λμ§ μμ λΉμ μ μ₯λ©λλ€. μν λ²μ§Έ μ²ν¬λ ν΄μ λμ§ μμΌλ―λ‘ μν λ²μ§Έμ μ¬λ λ²μ§Έ μ²ν¬λ **μμ μ²ν¬μ λ³ν©λμ§ μμ΅λλ€**.
μ΄λ₯Ό μ»΄νμΌνκ³ `main` ν¨μμ `ret` opcodeμ μ€λ¨μ μ μ€μ νμ¬ λλ²κΉ
νμΈμ. κ·Έλ° λ€μ `gef`λ₯Ό μ¬μ©νλ©΄ tcache λΉμ΄ κ°λ μ°¨ μκ³ νλμ μ²ν¬κ° μ λ ¬λμ§ μμ λΉμ μλ κ²μ λ³Ό μ μμ΅λλ€:
```bash
gefβ€ heap bins
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Tcachebins for thread 1 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tcachebins[idx=15, size=0x110, count=7] β Chunk(addr=0xaaaaaaac1d10, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac1c00, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac1af0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac19e0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac18d0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac17c0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac12a0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Fastbins for arena at 0xfffff7f90b00 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Fastbins[idx=0, size=0x20] 0x00
Fastbins[idx=1, size=0x30] 0x00
Fastbins[idx=2, size=0x40] 0x00
Fastbins[idx=3, size=0x50] 0x00
Fastbins[idx=4, size=0x60] 0x00
Fastbins[idx=5, size=0x70] 0x00
Fastbins[idx=6, size=0x80] 0x00
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Unsorted Bin for arena at 0xfffff7f90b00 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[+] unsorted_bins[0]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10
β Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in unsorted bin.
μμ λΉ
μμ λΉμ ν° λΉλ³΄λ€ λΉ λ₯΄μ§λ§ λΉ λ₯Έ λΉλ³΄λ€λ λ립λλ€.
62κ°μ κ° λΉμ κ°μ ν¬κΈ°μ μ²ν¬λ₯Ό κ°μ§λλ€: 16, 24, β¦ (32λΉνΈμμ μ΅λ ν¬κΈ°λ 504λ°μ΄νΈ, 64λΉνΈμμ 1024λ°μ΄νΈ). μ΄λ 곡κ°μ΄ ν λΉλμ΄μΌ ν λΉμ μ°Ύκ³ μ΄ λͺ©λ‘μμ νλͺ©μ μ½μ νκ³ μ κ±°νλ μλλ₯Ό λμ΄λ λ° λμμ΄ λ©λλ€.
μμ λΉμ ν¬κΈ°λ λΉμ μΈλ±μ€μ λ°λΌ λ€μκ³Ό κ°μ΄ κ³μ°λ©λλ€:
- κ°μ₯ μμ ν¬κΈ°: 2*4*index (μ: μΈλ±μ€ 5 -> 40)
- κ°μ₯ ν° ν¬κΈ°: 2*8*index (μ: μΈλ±μ€ 5 -> 80)
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
#define NSMALLBINS 64
#define SMALLBIN_WIDTH MALLOC_ALIGNMENT
#define SMALLBIN_CORRECTION (MALLOC_ALIGNMENT > CHUNK_HDR_SZ)
#define MIN_LARGE_SIZE ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH)
#define in_smallbin_range(sz) \
((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
#define smallbin_index(sz) \
((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\
+ SMALLBIN_CORRECTION)
μμ λΉκ³Ό ν° λΉ μ¬μ΄λ₯Ό μ ννλ ν¨μ:
#define bin_index(sz) \
((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
μμ μ²ν¬ μμ μΆκ°
```c #includeint main(void) { char *chunks[10]; int i;
// Loop to allocate memory 8 times for (i = 0; i < 9; i++) { chunks[i] = malloc(0x100); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, βMemory allocation failed at iteration %d\nβ, i); return 1; } printf(βAddress of chunk %d: %p\nβ, i, (void *)chunks[i]); }
// Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); }
chunks[9] = malloc(0x110);
return 0; }
9κ°μ λμΌν ν¬κΈ°μ μ²ν¬λ₯Ό ν λΉνκ³ ν΄μ νλ λ°©λ²μ μ μνμΈμ. μ΄ μ²ν¬λ€μ **tcacheλ₯Ό μ±μ°κ³ **, μ¬λ λ²μ§Έ μ²ν¬λ **fastbinμ λΉν΄ λ무 컀μ** μ λ ¬λμ§ μμ λΉμ μ μ₯λ©λλ€. μν λ²μ§Έ μ²ν¬λ ν΄μ λμ§ μμΌλ―λ‘ μν λ²μ§Έμ μ¬λ λ²μ§Έ μ²ν¬λ **top chunkμ λ³ν©λμ§ μμ΅λλ€**. κ·Έλ° λ€μ 0x110 ν¬κΈ°μ λ ν° μ²ν¬λ₯Ό ν λΉνλ©΄ **μ λ ¬λμ§ μμ λΉμ μ²ν¬κ° μμ λΉμΌλ‘ μ΄λν©λλ€**.
μ΄λ₯Ό μ»΄νμΌνκ³ `main` ν¨μμ `ret` opcodeμ μ€λ¨μ μ μ€μ νμ¬ λλ²κΉ
νμΈμ. κ·Έλ° λ€μ `gef`λ₯Ό μ¬μ©νλ©΄ tcache λΉμ΄ κ°λ μ°¨ μκ³ νλμ μ²ν¬κ° μμ λΉμ μλ κ²μ λ³Ό μ μμ΅λλ€:
```bash
gefβ€ heap bins
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Tcachebins for thread 1 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tcachebins[idx=15, size=0x110, count=7] β Chunk(addr=0xaaaaaaac1d10, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac1c00, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac1af0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac19e0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac18d0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac17c0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β Chunk(addr=0xaaaaaaac12a0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Fastbins for arena at 0xfffff7f90b00 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Fastbins[idx=0, size=0x20] 0x00
Fastbins[idx=1, size=0x30] 0x00
Fastbins[idx=2, size=0x40] 0x00
Fastbins[idx=3, size=0x50] 0x00
Fastbins[idx=4, size=0x60] 0x00
Fastbins[idx=5, size=0x70] 0x00
Fastbins[idx=6, size=0x80] 0x00
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Unsorted Bin for arena at 0xfffff7f90b00 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[+] Found 0 chunks in unsorted bin.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Small Bins for arena at 0xfffff7f90b00 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[+] small_bins[16]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10
β Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in 1 small non-empty bins.
λν λΉ
μμ λΉμ΄ κ³ μ ν¬κΈ°μ μ²ν¬λ₯Ό κ΄λ¦¬νλ κ²κ³Ό λ¬λ¦¬, κ° λν λΉμ μ²ν¬ ν¬κΈ°μ λ²μλ₯Ό μ²λ¦¬ν©λλ€. μ΄λ λ μ μ°νμ¬ μμ€ν μ΄ λ€μν ν¬κΈ°λ₯Ό μμ©ν μ μκ² νλ©°, κ° ν¬κΈ°λ§λ€ λ³λμ λΉμ΄ νμνμ§ μμ΅λλ€.
λ©λͺ¨λ¦¬ ν λΉκΈ°μμ λν λΉμ μμ λΉμ΄ λλλ μ§μ μμ μμν©λλ€. λν λΉμ λ²μλ μ μ§μ μΌλ‘ 컀μ§λ©°, 첫 λ²μ§Έ λΉμ 512λ°μ΄νΈμμ 576λ°μ΄νΈκΉμ§μ μ²ν¬λ₯Ό ν¬ν¨ν μ μκ³ , λ€μ λΉμ 576λ°μ΄νΈμμ 640λ°μ΄νΈκΉμ§λ₯Ό ν¬ν¨ν©λλ€. μ΄ ν¨ν΄μ κ³μλλ©°, κ°μ₯ ν° λΉμ 1MB μ΄μμ λͺ¨λ μ²ν¬λ₯Ό ν¬ν¨ν©λλ€.
λν λΉμ μμ λΉμ λΉν΄ μλ μλκ° λ립λλ€. μλνλ©΄ ν λΉμ κ°μ₯ μ ν©ν μ²ν¬λ₯Ό μ°ΎκΈ° μν΄ λ€μν μ²ν¬ ν¬κΈ°μ λͺ©λ‘μ μ λ ¬νκ³ κ²μν΄μΌ νκΈ° λλ¬Έμ λλ€. μ²ν¬κ° λν λΉμ μ½μ λ λ μ λ ¬ν΄μΌ νκ³ , λ©λͺ¨λ¦¬κ° ν λΉλ λ μμ€ν μ μ¬λ°λ₯Έ μ²ν¬λ₯Ό μ°ΎμμΌ ν©λλ€. μ΄ μΆκ° μμ μΌλ‘ μΈν΄ λλ €μ§μ§λ§, λν ν λΉμ΄ μμ ν λΉλ³΄λ€ λ μΌλ°μ μ΄κΈ° λλ¬Έμ μ΄λ μμ© κ°λ₯ν κ±°λμ λλ€.
λ€μκ³Ό κ°μ λΉμ΄ μμ΅λλ€:
- 64B λ²μμ 32κ° λΉ (μμ λΉκ³Ό μΆ©λ)
- 512B λ²μμ 16κ° λΉ (μμ λΉκ³Ό μΆ©λ)
- 4096B λ²μμ 8κ° λΉ (μΌλΆ μμ λΉκ³Ό μΆ©λ)
- 32768B λ²μμ 4κ° λΉ
- 262144B λ²μμ 2κ° λΉ
- λλ¨Έμ§ ν¬κΈ°λ₯Ό μν 1κ° λΉ
λν λΉ ν¬κΈ° μ½λ
```c // From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711#define largebin_index_32(sz)
(((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :
126)
#define largebin_index_32_big(sz)
(((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :
126)
// XXX It remains to be seen whether it is good to keep the widths of
// XXX the buckets the same or whether it should be scaled by a factor
// XXX of two as well.
#define largebin_index_64(sz)
(((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :
126)
- #define largebin_index(sz)
(SIZE_SZ == 8 ? largebin_index_64 (sz) \ - MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz) \
- largebin_index_32 (sz))
</details>
<details>
<summary>ν° μ²ν¬ μμ μΆκ°</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[2];
chunks[0] = malloc(0x1500);
chunks[1] = malloc(0x1500);
free(chunks[0]);
chunks[0] = malloc(0x2000);
return 0;
}
2κ°μ ν° ν λΉμ΄ μνλ ν, νλκ° ν΄μ λμ΄(μ λ ¬λμ§ μμ λΉμ λ£μ΄μ§) λ ν° ν λΉμ΄ μ΄λ£¨μ΄μ§λλ€(ν΄μ λ κ²μ΄ μ λ ¬λμ§ μμ λΉμμ ν° λΉμΌλ‘ μ΄λλ¨).
μ΄λ₯Ό μ»΄νμΌνκ³ main ν¨μμ ret opcodeμμ μ€λ¨μ μ μ€μ νμ¬ λλ²κΉ
ν©λλ€. κ·Έλ° λ€μ gefλ₯Ό μ¬μ©νλ©΄ tcache λΉμ΄ κ°λ μ°¨ μκ³ νλμ μ²ν¬κ° ν° λΉμ μμμ νμΈν μ μμ΅λλ€:
gefβ€ heap bin
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Tcachebins for thread 1 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
All tcachebins are empty
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Fastbins for arena at 0xfffff7f90b00 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Fastbins[idx=0, size=0x20] 0x00
Fastbins[idx=1, size=0x30] 0x00
Fastbins[idx=2, size=0x40] 0x00
Fastbins[idx=3, size=0x50] 0x00
Fastbins[idx=4, size=0x60] 0x00
Fastbins[idx=5, size=0x70] 0x00
Fastbins[idx=6, size=0x80] 0x00
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Unsorted Bin for arena at 0xfffff7f90b00 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[+] Found 0 chunks in unsorted bin.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Small Bins for arena at 0xfffff7f90b00 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[+] Found 0 chunks in 0 small non-empty bins.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Large Bins for arena at 0xfffff7f90b00 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[+] large_bins[100]: fw=0xaaaaaaac1290, bk=0xaaaaaaac1290
β Chunk(addr=0xaaaaaaac12a0, size=0x1510, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in 1 large non-empty bins.
μμ μ²ν¬
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
/*
Top
The top-most available chunk (i.e., the one bordering the end of
available memory) is treated specially. It is never included in
any bin, is used only if no other chunk is available, and is
released back to the system if it is very large (see
M_TRIM_THRESHOLD). Because top initially
points to its own bin with initial zero size, thus forcing
extension on the first malloc request, we avoid having any special
code in malloc to check whether it even exists yet. But we still
need to do so when getting memory from system, so we make
initial_top treat the bin as a legal but unusable chunk during the
interval between initialization and the first call to
sysmalloc. (This is somewhat delicate, since it relies on
the 2 preceding words to be zero during this interval as well.)
*/
/* Conveniently, the unsorted bin can be used as dummy top on first call */
#define initial_top(M) (unsorted_chunks (M))
κΈ°λ³Έμ μΌλ‘, μ΄κ²μ νμ¬ μ¬μ© κ°λ₯ν λͺ¨λ νμ ν¬ν¨νλ μ²ν¬μ
λλ€. mallocμ΄ μνλ λ, μ¬μ©ν μ μλ λ¬΄λ£ μ²ν¬κ° μμΌλ©΄ μ΄ μ΅μμ μ²ν¬μ ν¬κΈ°κ° μ€μ΄λ€μ΄ νμν 곡κ°μ μ 곡ν©λλ€.
μ΅μμ μ²ν¬μ λν ν¬μΈν°λ malloc_state ꡬ쑰체μ μ μ₯λ©λλ€.
κ²λ€κ°, μ²μμλ μ λ ¬λμ§ μμ μ²ν¬λ₯Ό μ΅μμ μ²ν¬λ‘ μ¬μ©ν μ μμ΅λλ€.
μ΅μμ μ²ν¬ μμ κ΄μ°°νκΈ°
```c #includeint main(void) { char *chunk; chunk = malloc(24); printf(βAddress of the chunk: %p\nβ, (void *)chunk); gets(chunk); return 0; }
`main`μ `ret` opcodeμμ μ€λ¨μ μ μ€μ νμ¬ μ»΄νμΌνκ³ λλ²κΉ
ν ν, mallocμ΄ μ£Όμ `0xaaaaaaac12a0`λ₯Ό λ°ννμΌλ©°, λ€μμ μ²ν¬λ€μ
λλ€:
```bash
gefβ€ heap chunks
Chunk(addr=0xaaaaaaac1010, size=0x290, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac12a0 41 41 41 41 41 41 41 00 00 00 00 00 00 00 00 00 AAAAAAA.........]
Chunk(addr=0xaaaaaaac12c0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac12c0 41 64 64 72 65 73 73 20 6f 66 20 74 68 65 20 63 Address of the c]
Chunk(addr=0xaaaaaaac16d0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac16d0 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 00 AAAAAAA.........]
Chunk(addr=0xaaaaaaac1ae0, size=0x20530, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) β top chunk
μλ¨ μ²ν¬κ° μ£Όμ 0xaaaaaaac1ae0μ μλ€λ κ²μ λ³Ό μ μμ΅λλ€. μ΄λ λ§μ§λ§μΌλ‘ ν λΉλ μ²ν¬κ° 0xaaaaaaac12a0μ ν¬κΈ° 0x410μΌλ‘ μμκΈ° λλ¬Έμ λλΌμ΄ μΌμ΄ μλλλ€. 0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0μ
λλ€.
μλ¨ μ²ν¬μ μ²ν¬ ν€λμμ μλ¨ μ²ν¬μ κΈΈμ΄λ₯Ό νμΈν μλ μμ΅λλ€:
gefβ€ x/8wx 0xaaaaaaac1ae0 - 16
0xaaaaaaac1ad0: 0x00000000 0x00000000 0x00020531 0x00000000
0xaaaaaaac1ae0: 0x00000000 0x00000000 0x00000000 0x00000000
λ§μ§λ§ λλ¨Έμ§
mallocμ΄ μ¬μ©λκ³ μ²ν¬κ° λλμ΄μ§ λ(μ: μ λ ¬λμ§ μμ λΉμμ λλ μ΅μμ μ²ν¬μμ), λλμ΄μ§ μ²ν¬μ λλ¨Έμ§ λΆλΆμμ μμ±λ μ²ν¬λ₯Ό Last RemainderλΌκ³ νλ©°, κ·Έ ν¬μΈν°λ malloc_state ꡬ쑰체μ μ μ₯λ©λλ€.
ν λΉ νλ¦
λ€μ λ΄μ©μ νμΈνμΈμ:
ν΄μ νλ¦
λ€μ λ΄μ©μ νμΈνμΈμ:
ν ν¨μ 보μ κ²μ¬
νμμ λ§μ΄ μ¬μ©λλ ν¨μλ€μ΄ μννλ 보μ κ²μ¬λ₯Ό νμΈνμΈμ:
Heap Functions Security Checks
μ°Έκ³ λ¬Έν
- 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/
- https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/core_functions
- https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/
Tip
AWS ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:HackTricks Training GCP Red Team Expert (GRTE)
Azure ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks μ§μνκΈ°
- ꡬλ κ³ν νμΈνκΈ°!
- **π¬ λμ€μ½λ κ·Έλ£Ή λλ ν λ κ·Έλ¨ κ·Έλ£Ήμ μ°Έμ¬νκ±°λ νΈμν° π¦ @hacktricks_liveλ₯Ό νλ‘μ°νμΈμ.
- HackTricks λ° HackTricks Cloud κΉνλΈ λ¦¬ν¬μ§ν 리μ PRμ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.


