hacktricks/binary-exploitation/heap
2024-05-10 17:40:15 +00:00
..
use-after-free Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-05-10 17:40:15 +00:00
bins-and-memory-allocations.md Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-05-10 17:40:15 +00:00
double-free.md Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-05-10 17:40:15 +00:00
heap-functions-security-checks.md Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-05-10 17:40:15 +00:00
heap-overflow.md Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-05-10 17:40:15 +00:00
README.md Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-05-10 17:40:15 +00:00
use-after-free.md Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-04-10 15:34:53 +00:00

Heap

Heap Temelleri

Heap, bir programın malloc, calloc gibi fonksiyonları çağırarak veri istediğinde verileri depolayabileceği yerdir. Ayrıca, bu belleğe artık ihtiyaç duyulmadığında free fonksiyonu çağrılarak serbest bırakılır.

Görüldüğü gibi, bu bellek, binary belleğe yüklendikten hemen sonra bulunmaktadır ( [heap] bölümüne bakınız):

Temel Parça Tahsisi

Heap'e depolanacak veri istendiğinde, heap'in bir kısmı buna ayrılır. Bu alan bir bine ait olacak ve yalnızca istenen veri + bin başlıklarının alanı + minimum bin boyutu ofseti, parça için ayrılmış olacaktır. Amacı, her parçanın nerede olduğunu bulmayı karmaşık hale getirmeden mümkün olduğunca az bellek rezerve etmektir. Bunun için, kullanılan/boş parça bilgilerini bilmek için meta veri parça bilgileri kullanılır.

Kullanılan bine bağlı olarak alanı ayırmak için farklı yollar vardır, ancak genel bir metodoloji şöyledir:

  • Program belirli miktarda bellek istemeye başlar.
  • İstek karşılayacak kadar büyük bir parça listesinde varsa, kullanılır.
  • Bu, isteğin bir kısmı için kullanılacak olan mevcut parçanın bir kısmının kullanılacağı ve geri kalanının parça listesine ekleneceği anlamına gelebilir.
  • Liste içinde uygun bir parça yoksa ancak ayrılmış heap belleğinde hala yer varsa, heap yöneticisi yeni bir parça oluşturur.
  • Yeni bir parça tahsis etmek için yeterli heap alanı yoksa, heap yöneticisi kernel'den heap'e ayrılan belleği genişletmesini ister ve ardından bu belleği kullanarak yeni parça oluşturur.
  • Her şey başarısız olursa, malloc null döner.

İstenen belleğin bir eşik değerini aşması durumunda, istenen belleği eşlemek için mmap kullanılacaktır.

Arenalar

Çoklu iş parçacıklı uygulamalarda, heap yöneticisi, çökmelere yol açabilecek yarış koşullarını önlemelidir. Başlangıçta, bunu sadece bir iş parçacığının aynı anda heap'e erişebileceğinden emin olmak için bir global kilitleme kullanarak yapılıyordu, ancak bu, kilitleme nedeniyle performans sorunlarına yol açtı.

Bunu ele almak için, ptmalloc2 heap tahsis edicisi, her birinin kendi veri yapıları ve kilidi olan ayrı bir heap olarak hareket eden "arenaları" tanıttı, bu da farklı arenaları kullansalar bile birden fazla iş parçacığının birbirini engellemeden heap işlemleri yapmasına izin verir.

Varsayılan "ana" arena, tek iş parçacıklı uygulamalar için heap işlemlerini yönetir. Yeni iş parçacıkları eklendiğinde, heap yöneticisi çekişmeyi azaltmak için onlara ikincil arenalar atar. Her yeni iş parçacığını kullanılmayan bir arenaya eklemeye çalışır, gerektiğinde yeni arenalar oluşturur, 32 bit sistemler için CPU çekirdekleri için 2 kat, 64 bit sistemler için 8 kat sınırına ulaşana kadar. Sınır aşıldığında, iş parçacıkları arenaları paylaşmak zorunda kalır, potansiyel çekişmeye yol açar.

Ana arenanın aksine, brk sistem çağrısını kullanarak genişleyen ana arenalar, çoklu iş parçacıklı işlemler için belleği yönetme esnekliği sağlayan mmap ve mprotect kullanarak "alt heap"ler oluşturan ikincil arenalar oluşturur.

Alt Heap'ler

Alt heap'ler, çoklu iş parçacıklı uygulamalardaki ikincil arenalar için bellek rezervleri olarak hizmet eder, kendi heap bölgelerini ana heap'ten ayrı olarak büyütmelerine ve yönetmelerine olanak tanır. İşte alt heap'lerin başlangıç heap'inden nasıl farklı olduğu ve nasıl çalıştığı:

  1. Başlangıç Heap'i vs. Alt Heap'ler:
  • Başlangıç heap'i, programın binary'sinin hemen ardında bulunur ve sbrk sistem çağrısını kullanarak genişler.
  • İkincil arenalar tarafından kullanılan alt heap'ler, belirli bir bellek bölgesini eşleyen mmap kullanılarak oluşturulur.
  1. mmap ile Bellek Rezervasyonu:
  • Heap yöneticisi bir alt heap oluşturduğunda, mmap aracılığıyla büyük bir bellek bloğu rezerve eder. Bu rezervasyon hemen bellek tahsis etmez; sadece diğer sistem işlemlerinin veya tahsislerin kullanmaması gereken bir bölgeyi belirler.
  • Varsayılan olarak, 32 bit işlemler için bir alt heap için ayrılan boyut 1 MB, 64 bit işlemler için ise 64 MB'dir.
  1. mprotect ile Aşamalı Genişleme:
  • Rezerve edilen bellek bölgesi başlangıçta PROT_NONE olarak işaretlenir, bu da kernelin bu alana henüz fiziksel bellek tahsis etmesine gerek olmadığını gösterir.
  • Alt heap'i "genişletmek" için heap yöneticisi, mprotect kullanarak sayfa izinlerini PROT_NONEdan PROT_READ | PROT_WRITE'a değiştirir, bu da kernelin önceden rezerve edilen adreslere fiziksel bellek tahsis etmesini sağlar. Bu adım adım yaklaşım, alt heap'in ihtiyaç duyuldukça genişlemesine olanak tanır.
  • Tüm alt heap tükenene kadar, heap yöneticisi yeni bir alt heap oluşturarak tahsis işlemine devam eder.

malloc_state

Her heap'in (ana arena veya diğer iş parçacıklarının arenaları) bir malloc_state yapısı vardır.
Önemli bir nokta, ana arenanın malloc_state yapısının libc'de global bir değişken olduğudur (bu nedenle libc bellek alanında bulunur).
İş parçacıklarının arenalarının malloc_state yapıları ise kendi iş parçacığı "heap"lerinin içinde bulunur.

Bu yapıdan bazı ilginç noktaları not etmek önemlidir (aşağıdaki C koduna bakınız):

  • mchunkptr bins[NBINS * 2 - 2];, küçük, büyük ve sıralanmamış binlerin ilk ve son parçalarına işaretçiler içerir (-2, çünkü indeks 0 kullanılmaz)
  • Dolayısıyla, bu binlerin ilk parçaları bu yapıya ters işaretçiye sahip olacak ve bu binlerin son parçaları bu yapıya ileri işaretçiye sahip olacaktır. Bu temelde, eğer bu adresleri ana arenada sızdırabilirseniz, libc içindeki yapıya bir işaretçiye sahip olacaksınız.
  • struct malloc_state *next; ve struct malloc_state *next_free; yapılarının arenaların bağlı listeleri olduğu
  • top parça, temelde tüm heap hatırlama alanı olan son "parçadır". Top parça "boş" olduğunda, heap tamamen kullanılmıştır ve daha fazla alan istenmesi gerekir.
  • last reminder parça, tam bir boyutta parça mevcut olmadığı durumlardan kaynaklanan, daha büyük bir parça bölündüğünde, geriye kalan kısmın yerleştirildiği bir noktadır.
// From https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_state
struct malloc_state
{
/* Serialize access.  */
__libc_lock_define (, mutex);
/* Flags (formerly in max_fast).  */
int flags;

/* 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;
};

typedef struct malloc_state *mstate;

malloc_chunk

Bu yapı belirli bir bellek parçasını temsil eder. Çeşitli alanlar ayrılmış ve ayrılmamış parçalar için farklı anlamlara sahiptir.

// From https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_chunk
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;

Daha önce belirtildiği gibi, bu parçaların bazı meta verileri de bulunmaktadır, bu meta veriler bu resimde çok iyi temsil edilmiştir:

https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png

Meta veriler genellikle mevcut parça boyutunu belirten 0x08B'yi gösterir ve son 3 biti kullanarak aşağıdakileri belirtir:

  • A: 1 ise alt heap'ten gelir, 0 ise ana arenada bulunur
  • M: 1 ise bu parça mmap ile ayrılan bir alana aittir ve heap'in bir parçası değildir
  • P: 1 ise önceki parça kullanımdadır

Ardından, kullanıcı verileri için alan ve son olarak parça kullanımda değilken (veya ayrıldığında kullanıcı verilerini saklamak için) önceki parça boyutunu belirtmek için 0x08B bulunur.

Ayrıca, kullanılabilir olduğunda, kullanıcı verileri aynı zamanda bazı verileri içerecek şekilde kullanılır:

  • Bir sonraki parçaya işaretçi
  • Önceki parçaya işaretçi
  • Listede bir sonraki parçanın boyutu
  • Listede önceki parçanın boyutu

https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png

{% hint style="info" %} Listeyi bu şekilde beğenmek, her bir parçanın kaydedildiği bir diziye ihtiyaç duymadan yapılabilir. {% endhint %}

Hızlı Heap Örneği

Arm64'te https://guyinatuxedo.github.io/25-heap/index.html adresindeki hızlı heap örneği:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(void)
{
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
}

Ana fonksiyonun sonunda bir kesme noktası belirleyin ve bilgilerin nerede saklandığını bulalım:

Görülebileceği gibi, dize panda 0xaaaaaaac12a0 adresinde saklandı (bu adres, x0 içindeki malloc tarafından yanıt olarak verilen adresdi). Onun 0x10 byte öncesini kontrol etmek mümkün olduğunda, 0x0'ın önceki parçanın kullanılmadığını (uzunluğu 0) ve bu parçanın uzunluğunun 0x21 olduğunu görmek mümkündür.

Ekstra boşluklar ayrılmıştır (0x21-0x10=0x11) eklenen başlıklardan (0x10) gelir ve 0x1, 0x21B ayrılmış olduğu anlamına gelmez ancak mevcut başlığın uzunluğunun son 3 bitinin bazı özel anlamlara sahip olduğu anlamına gelir. Uzunluk her zaman 16 bayt hizalı olduğundan (64 bit makinelerde), bu bitler aslında uzunluk numarası tarafından asla kullanılmayacak.

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

Bins ve Bellek Tahsisleri/Serbest Bırakmalar

Kontrol edin nelerin bins olduğunu ve nasıl düzenlendiğini ve belleğin nasıl tahsis edildiğini ve serbest bırakıldığını:

{% content-ref url="bins-and-memory-allocations.md" %} bins-and-memory-allocations.md {% endcontent-ref %}

Heap Fonksiyonları Güvenlik Kontrolleri

Heap ile ilgili fonksiyonlar, işlemlerini gerçekleştirmeden önce belirli kontroller yapacak ve heap'in bozulmadığından emin olmaya çalışacak:

{% content-ref url="heap-functions-security-checks.md" %} heap-functions-security-checks.md {% endcontent-ref %}

Referanslar