hacktricks/binary-exploitation/heap/README.md

191 lines
12 KiB
Markdown
Raw Normal View History

# 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):
<figure><img src="../../.gitbook/assets/image (1241).png" alt=""><figcaption></figcaption></figure>
### 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.
2. **`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.
3. **`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_NONE`dan `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.
```c
// 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.
```c
// 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:
<figure><img src="../../.gitbook/assets/image (1242).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
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
<figure><img src="../../.gitbook/assets/image (1243).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
{% 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](https://guyinatuxedo.github.io/25-heap/index.html) adresindeki hızlı heap örneği:
```c
#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:
<figure><img src="../../.gitbook/assets/image (1239).png" alt=""><figcaption></figcaption></figure>
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](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](heap-functions-security-checks.md)
{% endcontent-ref %}
## Referanslar
* [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](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://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)