.. | ||
use-after-free | ||
bins-and-memory-allocations.md | ||
double-free.md | ||
heap-functions-security-checks.md | ||
heap-overflow.md | ||
README.md | ||
use-after-free.md |
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ığı:
- 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.
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.
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 izinleriniPROT_NONE
danPROT_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;
vestruct malloc_state *next_free;
yapılarının arenaların bağlı listeleri olduğutop
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:
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 bulunurM
: 1 ise bu parça mmap ile ayrılan bir alana aittir ve heap'in bir parçası değildirP
: 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
{% 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 %}