37 KiB
Bins & Vitengenezaji wa Kumbukumbu
Jifunze AWS hacking kutoka sifuri hadi shujaa na htARTE (HackTricks AWS Red Team Expert)!
Njia nyingine za kusaidia HackTricks:
- Ikiwa unataka kuona kampuni yako ikitangazwa kwenye HackTricks au kupakua HackTricks kwa PDF Angalia MIPANGO YA USAJILI!
- Pata bidhaa rasmi za PEASS & HackTricks
- Gundua Familia ya PEASS, mkusanyiko wetu wa kipekee wa NFTs
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram au tufuate kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu zako za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Taarifa Msingi
Ili kuboresha ufanisi wa jinsi vipande vinavyohifadhiwa, kila kipande sio tu kwenye orodha moja iliyounganishwa, lakini kuna aina kadhaa. Hizi ni vitengenezaji wa kumbukumbu na kuna aina 5 za vitengenezaji: 62 vitengenezaji wadogo, 63 vitengenezaji wakubwa, 1 kikasha kisichopangwa, 10 vitengenezaji wa haraka na vitengenezaji 64 vya tcache kwa kila mnyororo.
Anwani ya awali kwa kila kikasha kisichopangwa, kidogo na kikubwa iko ndani ya safu ile ile. Indeksi 0 haifai, 1 ni kikasha kisichopangwa, kikasha 2-64 ni vitengenezaji wadogo na vitengenezaji 65-127 ni vitengenezaji wakubwa.
Vitengenezaji wa Tcache (Kikasha cha Mnyororo kwa Kila Mnyororo)
Ingawa mnyororo unajaribu kuwa na kumbukumbu yake mwenyewe (angalia Arenas na Subheaps), kuna uwezekano kwamba mchakato na mnyororo mwingi (kama seva ya wavuti) watakamilisha kushiriki kumbukumbu na mnyororo mwingine. Katika kesi hii, suluhisho kuu ni matumizi ya kifungua milango, ambayo inaweza kupunguza kwa kiasi kikubwa kasi ya mnyororo.
Kwa hivyo, tcache inafanana na kikasha cha haraka kwa kila mnyororo kwa njia kwamba ni orodha iliyounganishwa moja kwa moja ambayo haifungi vipande. Kila mnyororo ana vitengenezaji 64 vya tcache vilivyounganishwa kwa mnyororo. Kila kikasha kinaweza kuwa na kiwango cha juu cha vipande sawa 7 vya saizi hiyo hiyo kuanzia 24 hadi 1032B kwenye mifumo ya 64-bit na 12 hadi 516B kwenye mifumo ya 32-bit.
Wakati mnyororo anapofuta kipande, ikiwa sio kikubwa sana kuweza kupangwa kwenye tcache na kikasha cha tcache hakijajaa (tayari kuna vipande 7), kitapangwa hapo. Ikiwa hakiwezi kwenda kwenye tcache, italazimika kusubiri kwa ajili ya kufungua kumbukumbu ili kuweza kufanya operesheni ya bure kwa ujumla.
Wakati kipande kinapopangwa, ikiwa kuna kipande cha bure cha saizi inayohitajika kwenye Tcache itakitumia, la sivyo, italazimika kusubiri kwa ajili ya kufungua kumbukumbu ili kuweza kupata moja kwenye vitengenezaji vya jumla au kuunda mpya.
Pia kuna uboreshaji, katika kesi hii, wakati wa kufungua kumbukumbu, mnyororo atajaza Tcache yake na vipande vya kumbukumbu (7) vya kumbukumbu inayohitajika, hivyo ikihitaji zaidi, itavipata kwenye Tcache.
Ongeza mfano wa kipande cha tcache
```c #include #includeint main(void) { char *chunk; chunk = malloc(24); printf("Address of the chunk: %p\n", (void *)chunk); gets(chunk); free(chunk); return 0; }
Fanya kompyuta na ukague kosa kwa kuweka kizuizi katika opcode ya kurudi kutoka kwa kazi kuu. kisha kwa gef unaweza kuona tcache bin inayotumiwa:
```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 Structs & Functions
Katika msimbo ufuatao inawezekana kuona max bins na vipande kwa kila index, tcache_entry
muundo ulioundwa ili kuepuka kufuta mara mbili na tcache_perthread_struct
, muundo ambao kila mnyororo hutumia kuhifadhi anwani kwa kila index ya benki.
tcache_entry
na tcache_perthread_struct
```c
// From f942a732d3/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>
Kazi `__tcache_init` ndio kazi inayounda na kutenga nafasi kwa ajili ya obj ya `tcache_perthread_struct`
```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));
}
}
Viashiria vya Tcache
Tcache ina viashiria kadhaa kulingana na ukubwa na pointi za awali kwa kila kipande cha kwanza cha kila kiashiria na idadi ya vipande kwa kila kiashiria zinapatikana ndani ya kipande. Hii inamaanisha kwamba kwa kutambua kipande chenye habari hii (kawaida cha kwanza), ni rahisi kupata pointi zote za awali za tcache na idadi ya vipande vya Tcache.
Bins za Haraka
Bins za haraka zinakusudiwa kuongeza kasi ya kutengwa kwa kumbukumbu kwa vipande vidogo kwa kuweka vipande vilivyotolewa hivi karibuni katika muundo wa ufikivu wa haraka. Bins hizi hutumia njia ya Mwisho-Kuingia, Mwanzo-Kutoka (LIFO), ambayo inamaanisha kwamba kipande kilichotolewa hivi karibuni zaidi ndicho kwanza kutumika tena wakati kuna ombi jipya la kutengwa. Tabia hii ni faida kwa kasi, kwani ni haraka kuweka na kuondoa kutoka juu ya rundo (LIFO) ikilinganishwa na foleni (FIFO).
Kwa kuongezea, bins za haraka hutumia orodha za viungo vya moja kwa moja, si za mara mbili, ambayo inaboresha kasi zaidi. Kwa kuwa vipande katika bins za haraka havijunganishwi na majirani, hakuna haja ya muundo tata unaoruhusu kuondolewa katikati. Orodha ya viungo vya moja kwa moja ni rahisi na haraka kwa operesheni hizi.
Kimsingi, kinachotokea hapa ni kwamba kichwa (kipande cha kwanza cha kuangalia) kinaelekeza daima kwenye kipande kilichotolewa hivi karibuni cha ukubwa huo. Hivyo:
- Wakati kipande kipya kinatengwa cha ukubwa huo, kichwa kinaelekeza kwenye kipande huru cha kutumia. Kwa kuwa kipande huru hiki kinaelekeza kwenye kipande kinachofuata cha kutumia, anwani hii inahifadhiwa kwenye kichwa ili kutambua wapi kupata kipande kinachopatikana baadaye
- Wakati kipande kinapotolewa, kipande huru kitahifadhi anwani ya kipande kinachopatikana kwa sasa na anwani ya kipande hiki kilichotolewa hivi karibuni itawekwa kwenye kichwa
Ukubwa wa juu wa orodha ya viungo ni 0x80
na zimepangwa ili kipande cha ukubwa wa 0x20-0x2f
kiwe katika kiashiria 0
, kipande cha ukubwa wa 0x30-0x3f
kingekuwa katika idx
1
...
{% hint style="danger" %} Vipande katika bins za haraka havijawekwa kama vinavyopatikana hivyo vinabaki kama vipande vya bins za haraka kwa muda fulani badala ya kuweza kujumuishwa na vipande vingine huru vinavyowazunguka. {% endhint %}
// 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)
Ongeza mfano wa kipande cha fastbin
```c #include #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; }
Tazama jinsi tunavyoomba na kuachilia vipande 8 vya saizi sawa ili wajaze tcache na cha nane kuhifadhiwa kwenye kisanduku cha haraka.
Sakinisha na ugundue na kivurugaji kwenye opcode ya ret kutoka kwenye kazi kuu. kisha kwa gef unaweza kuona tcache bin kujaa na kipande kimoja kwenye kisanduku cha haraka:
```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
Bakuli lisilo na mpangilio
Bakuli lisilo na mpangilio ni cache inayotumiwa na meneja wa bakuli ili kufanya mgawo wa kumbukumbu uwe haraka zaidi. Hapa ndivyo inavyofanya kazi: Wakati programu inaachilia kipande, na ikiwa kipande hiki hakiwezi kupewa katika tcache au bakuli la haraka na haligongani na kipande cha juu, meneja wa bakuli hauweki mara moja katika bakuli maalum ndogo au kubwa. Badala yake, kwanza inajaribu kulifunga na vipande vingine vya bure vya jirani ili kuunda kibodi kikubwa cha kumbukumbu ya bure. Kisha, inaweka kipande kipya hiki katika bakuli ya jumla inayoitwa "bakuli lisilo na mpangilio."
Wakati programu inahitaji kumbukumbu, meneja wa bakuli huchunguza bakuli lisilo na mpangilio kuona ikiwa kuna kipande cha ukubwa wa kutosha. Ikiipata, inaitumia mara moja. Ikiwa haitapata kipande kinachofaa katika bakuli lisilo na mpangilio, inahamisha vipande vyote katika orodha hii kwenye bakuli zao husika, iwe ndogo au kubwa, kulingana na ukubwa wao.
Tafadhali kumbuka kwamba ikiwa kipande kikubwa kimegawanywa katika sehemu 2 na sehemu iliyobaki ni kubwa kuliko MINSIZE, itarudishwa tena kwenye bakuli lisilo na mpangilio.
Kwa hivyo, bakuli lisilo na mpangilio ni njia ya kuharakisha mgawo wa kumbukumbu kwa haraka kutumia tena kumbukumbu iliyotolewa hivi karibuni na kupunguza haja ya kutafuta na kufunga kwa muda mrefu.
{% hint style="danger" %} Tafadhali kumbuka kwamba hata ikiwa vipande ni vya makundi tofauti, ikiwa kipande kinachopatikana kinagongana na kipande kingine kinachopatikana (hata kama kwa asili wanatoka kwenye bakuli tofauti), vitafungwa pamoja. {% endhint %}
Ongeza mfano wa kipande lisilo na mpangilio
```c #include #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; }
Tambua jinsi tunavyoomba na kuachilia vipande 9 vya saizi sawa ili vijaze tcache na cha nane kuhifadhiwa kwenye sanduku lisiloandikwa kwa sababu ni kubwa sana kwa fastbin na cha tisa hakijaachiliwa hivyo cha tisa na cha nane havitaunganishwa na kipande cha juu.
Sakinisha na uisashe na kuvunja kwa kizuizi katika opcode ya ret kutoka kwenye kazi kuu. kisha kwa gef unaweza kuona tcache bin kujaa na kipande kimoja kwenye sanduku lisiloandikwa:
```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.
Bins Ndogo
Bins ndogo ni haraka kuliko bins kubwa lakini polepole kuliko fast bins.
Kila bin kati ya 62 itakuwa na vipande vya saizi sawa: 16, 24, ... (ikiwa na saizi ya juu ya byte 504 katika bits 32 na 1024 katika bits 64). Hii husaidia katika kasi ya kupata bin ambapo nafasi inapaswa kutengwa na kuingiza na kuondoa vipande kwenye orodha hizi.
Hivi ndivyo saizi ya bin ndogo inavyohesabiwa kulingana na index ya bin:
- Saizi ndogo zaidi: 2*4*index (k.m. index 5 -> 40)
- Saizi kubwa zaidi: 2*8*index (k.m. 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)
// Function to choose between small and large bins:
// Kazi ya kuchagua kati ya makandokando madogo na makandokando makubwa:
#define bin_index(sz) \
((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
Wekeza mfano mdogo wa kipande
```c #include #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; }
Tambua jinsi tunavyoomba na kuachilia vipande 9 vya saizi ile ile ili vijaze tcache na cha nane kuhifadhiwa kwenye sanduku lisilo na mpangilio kwa sababu ni kubwa sana kwa fastbin na cha tisa hakijaachiliwa hivyo cha tisa na cha nane havitaunganishwa na kipande cha juu. Kisha tunaomba kipande kikubwa cha 0x110 ambacho kinasababisha kipande kwenye sanduku lisilo na mpangilio kuingia kwenye sanduku dogo.
Sakinisha na uisashe na kuvunja kwa kusitisha kwenye opcode ya ret kutoka kwenye kazi kuu. kisha kwa gef unaweza kuona tcache bin kujaa na kipande kimoja kwenye sanduku dogo:
```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.
Bins kubwa
Tofauti na bins ndogo, ambazo hushughulikia vipande vya saizi za kudumu, kila bin kubwa hushughulikia safu ya saizi za vipande. Hii ni ya kubadilika zaidi, kuruhusu mfumo kuzoea saizi tofauti bila haja ya bin tofauti kwa kila saizi.
Katika mpangilio wa kumbukumbu, bins kubwa huanza pale ambapo bins ndogo zinaishia. Safu za bins kubwa hukua kwa ukubwa kwa kiasi kikubwa, maana bin ya kwanza inaweza kufunika vipande kutoka 512 hadi 576 baiti, wakati inayofuata inafunika 576 hadi 640 baiti. Mtindo huu unaendelea, na bin kubwa zaidi ikijumuisha vipande vyote zaidi ya 1MB.
Bins kubwa ni polepole kufanya kazi ikilinganishwa na bins ndogo kwa sababu lazima zipange na kutafuta kupitia orodha ya saizi tofauti za vipande ili kupata saizi bora kwa ajili ya mgawo. Wakati kipande kinapowekwa kwenye bin kubwa, lazima kipangwe, na wakati kumbukumbu inapogawiwa, mfumo lazima upate kipande sahihi. Kazi hii ya ziada inawafanya kuwa polepole, lakini kwa kuwa mgawo wa kubwa ni nadra kuliko vipande vidogo, ni sawa kufanya hivyo.
Kuna:
- 32 bins zenye safu ya 64B (zinaingiliana na bins ndogo)
- 16 bins zenye safu ya 512B (zinaingiliana na bins ndogo)
- 8 bins zenye safu ya 4096B (sehemu inaingiliana na bins ndogo)
- 4 bins zenye safu ya 32768B
- 2 bins zenye safu ya 262144B
- 1 bin kwa ajili ya saizi zilizosalia
Msimbo wa Saizi za Bins Kubwa
```c // Froma07e000e82/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>Wekeza mfano wa kipande kikubwa</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 alokesheni kubwa zinafanywa, kisha moja inaachiliwa (ikiwekwa kwenye sanduku lisilo na mpangilio) na alokesheni kubwa zaidi inafanywa (ikihamisha ile iliyofunguliwa kutoka kwenye sanduku lisilo na mpangilio kwenda kwenye sanduku kubwa).
Sakinisha na uisashe na kivamizi kwenye opcode ya ret kutoka kwenye kazi kuu. kisha kwa gef unaweza kuona sanduku la tcache likijazwa na kipande kimoja kwenye sanduku kubwa:
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.
Kipande cha Juu
// 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))
Hii ni kipande kinachojumuisha kipande chote kinachopatikana kwa sasa. Wakati malloc inafanywa, ikiwa hakuna kipande cha bure kinachopatikana kutumika, kipande hiki cha juu kitapunguza ukubwa wake kutoa nafasi inayohitajika. Kiashiria kwa Kipande cha Juu kuhifadhiwa katika muundo wa malloc_state
.
Zaidi ya hayo, mwanzoni, ni sawa kutumia kipande kilichochanganyika kama kipande cha juu.
Angalia mfano wa Kipande cha Juu
```c #include #includeint main(void) { char *chunk; chunk = malloc(24); printf("Address of the chunk: %p\n", (void *)chunk); gets(chunk); return 0; }
Baada ya kuikusanya na kuibugia na kipindi cha kuvunja katika opcode ya ret ya main niliona kwamba malloc ilirudisha anwani: `0xaaaaaaac12a0` na hizi ni vipande:
```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
Mahali ambapo inaweza kuonekana kwamba kipande cha juu kiko kwenye anwani 0xaaaaaaac1ae0
. Hii si mshangao kwa sababu kipande cha hivi karibuni kilichotengwa kilikuwa kwenye 0xaaaaaaac12a0
na ukubwa wa 0x410
na 0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0
. Pia ni rahisi kuona urefu wa Kipande cha Juu kwenye kichwa chake cha kipande:
gef➤ x/8wx 0xaaaaaaac1ae0 - 16
0xaaaaaaac1ad0: 0x00000000 0x00000000 0x00020531 0x00000000
0xaaaaaaac1ae0: 0x00000000 0x00000000 0x00000000 0x00000000
Kumbusho la Mwisho
Wakati malloc inapotumiwa na kipande kinagawanywa (kutoka kwenye orodha isiyofungwa au kutoka kwa kipande cha juu kwa mfano), kipande kilichoundwa kutoka kwa sehemu iliyobaki ya kipande kilichogawanywa huitwa Kumbukumbu ya Mwisho na pointer yake hifadhiwa katika muundo wa malloc_state
.
Mchakato wa Kutengeneza
Angalia:
{% content-ref url="heap-memory-functions/malloc-and-sysmalloc.md" %} malloc-and-sysmalloc.md {% endcontent-ref %}
Mchakato wa Kuachilia
Angalia:
{% content-ref url="heap-memory-functions/free.md" %} free.md {% endcontent-ref %}
Uchunguzi wa Usalama wa Kazi za Heap
Angalia ukaguzi wa usalama uliofanywa na kazi zinazotumiwa sana kwenye heap katika:
{% content-ref url="heap-memory-functions/heap-functions-security-checks.md" %} heap-functions-security-checks.md {% endcontent-ref %}
Marejeo
- 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/
Jifunze AWS hacking kutoka sifuri hadi shujaa na htARTE (HackTricks AWS Red Team Expert)!
Njia nyingine za kusaidia HackTricks:
- Ikiwa unataka kuona kampuni yako ikitangazwa kwenye HackTricks au kupakua HackTricks kwa PDF Angalia MIPANGO YA KUJIUNGA!
- Pata bidhaa rasmi za PEASS & HackTricks
- Gundua Familia ya PEASS, mkusanyiko wetu wa NFTs za kipekee
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram au tufuate kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu zako za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.