malloc & sysmalloc

Nauka hakowania AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Podsumowanie kolejności alokacji

(W tym podsumowaniu nie są wyjaśnione żadne sprawdzenia, a niektóre przypadki zostały pominięte dla zwięzłości)

  1. __libc_malloc próbuje uzyskać kawałek z tcache, jeśli nie, wywołuje _int_malloc

  2. _int_malloc :

  3. Próbuje wygenerować arenę, jeśli jej nie ma

  4. Jeśli istnieje jakiś kawałek fast bin odpowiedniego rozmiaru, użyj go

  5. Wypełnij tcache innymi szybkimi kawałkami

  6. Jeśli istnieje jakiś kawałek small bin odpowiedniego rozmiaru, użyj go

  7. Wypełnij tcache innymi kawałkami tego samego rozmiaru

  8. Jeśli żądany rozmiar nie jest dla małych binów, scal fast bin z unsorted bin

  9. Sprawdź unsorted bin, użyj pierwszego kawałka z wystarczającą przestrzenią

  10. Jeśli znaleziony kawałek jest większy, podziel go, aby zwrócić część i dodaj resztę z powrotem do unsorted bin

  11. Jeśli kawałek ma taki sam rozmiar jak żądany rozmiar, użyj go do wypełnienia tcache zamiast go zwracać (aż tcache będzie pełne, wtedy zwróć następny)

  12. Dla każdego sprawdzonego kawałka mniejszego rozmiaru, umieść go w odpowiednim małym lub dużym binie

  13. Sprawdź duży bin w indeksie żądanego rozmiaru

  14. Zacznij od pierwszego kawałka, który jest większy niż żądany rozmiar, jeśli znajdziesz taki, zwróć go i dodaj resztki do małego bina

  15. Sprawdź duże biny od następnych indeksów do końca

  16. Od następnego większego indeksu sprawdź, czy jest jakiś kawałek, podziel pierwszy znaleziony kawałek, aby użyć go do żądanego rozmiaru i dodaj resztę do unsorted bin

  17. Jeśli w poprzednich binach nic nie znaleziono, pobierz kawałek z górnego kawałka

  18. Jeśli górny kawałek nie był wystarczająco duży, powiększ go za pomocą sysmalloc

__libc_malloc

Funkcja malloc faktycznie wywołuje __libc_malloc. Ta funkcja sprawdzi tcache, aby zobaczyć, czy jest dostępny jakiś kawałek o pożądanym rozmiarze. Jeśli jest, użyje go, a jeśli nie, sprawdzi, czy jest to pojedynczy wątek, a w takim przypadku wywoła _int_malloc w głównej arenie, a jeśli nie, wywoła _int_malloc w arenie wątku.

Kod __libc_malloc

```c // From https://github.com/bminor/glibc/blob/master/malloc/malloc.c

#if IS_IN (libc) void * __libc_malloc (size_t bytes) { mstate ar_ptr; void *victim;

_Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2, "PTRDIFF_MAX is not more than half of SIZE_MAX");

if (!__malloc_initialized) ptmalloc_init (); #if USE_TCACHE /* int_free also calls request2size, be careful to not pad twice. */ size_t tbytes = checked_request2size (bytes); if (tbytes == 0) { __set_errno (ENOMEM); return NULL; } size_t tc_idx = csize2tidx (tbytes);

MAYBE_INIT_TCACHE ();

DIAG_PUSH_NEEDS_COMMENT; if (tc_idx < mp_.tcache_bins && tcache != NULL && tcache->counts[tc_idx] > 0) { victim = tcache_get (tc_idx); return tag_new_usable (victim); } DIAG_POP_NEEDS_COMMENT; #endif

if (SINGLE_THREAD_P) { victim = tag_new_usable (_int_malloc (&main_arena, bytes)); assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || &main_arena == arena_for_chunk (mem2chunk (victim))); return victim; }

arena_get (ar_ptr, bytes);

victim = _int_malloc (ar_ptr, bytes); /* Retry with another arena only if we were able to find a usable arena before. */ if (!victim && ar_ptr != NULL) { LIBC_PROBE (memory_malloc_retry, 1, bytes); ar_ptr = arena_get_retry (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); }

if (ar_ptr != NULL) __libc_lock_unlock (ar_ptr->mutex);

victim = tag_new_usable (victim);

assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))); return victim; }

</details>

Zauważ, że zawsze oznacza zwrócony wskaźnik tagiem `tag_new_usable`, z kodu:
```c
void *tag_new_usable (void *ptr)

Allocate a new random color and use it to color the user region of
a chunk; this may include data from the subsequent chunk's header
if tagging is sufficiently fine grained.  Returns PTR suitably
recolored for accessing the memory there.

_int_malloc

To jest funkcja, która alokuje pamięć przy użyciu innych kubełków i najwyższego fragmentu.

  • Rozpoczęcie

Zaczyna od zdefiniowania kilku zmiennych i uzyskania rzeczywistego rozmiaru, jaki musi mieć przestrzeń pamięci żądania:

Fast Bin

Jeśli potrzebny rozmiar mieści się w rozmiarach Fast Bins, spróbuj użyć fragmentu z fast bin. W zasadzie, na podstawie rozmiaru znajdzie indeks fast bin, w którym powinny znajdować się poprawne fragmenty, i jeśli takie istnieją, zwróci jeden z nich. Ponadto, jeśli tcache jest włączone, wypełni tcache bin tego rozmiaru fragmentami z fast bins.

Podczas wykonywania tych działań, tutaj wykonywane są pewne kontrole bezpieczeństwa:

  • Jeśli fragment jest źle wyrównany: malloc(): wykryto źle wyrównany fragment fastbin 2

  • Jeśli następny fragment jest źle wyrównany: malloc(): wykryto źle wyrównany fragment fastbin

  • Jeśli zwrócony fragment ma niepoprawny rozmiar z powodu jego indeksu w fast bin: malloc(): korupcja pamięci (fast)

  • Jeśli którykolwiek fragment użyty do wypełnienia tcache jest źle wyrównany: malloc(): wykryto źle wyrównany fragment fastbin 3

Last updated