Translated ['binary-exploitation/heap/README.md'] to tr

This commit is contained in:
Translator 2024-05-09 18:06:54 +00:00
parent 5db086f6da
commit c123ff05a0
7 changed files with 210 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View file

@ -1,3 +1,212 @@
# Heap
# Yığın
## 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çaya ayrılmış olacaktır. Amaç, 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 her parçanın bilgilerini bilmek için parça bilgileri kullanılır.
Kullanılan bine bağlı olarak alanı rezerve etmenin 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ının kullanılabilir parçadan kullanılacağı ve geri kalanının parçalar listesine ekleneceği anlamına gelebilir.
* Eğer listede 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 ayrılmak için yeterli heap alanı yoksa, heap yöneticisi kernelden heap'e ayrılan belleği genişletmesini ve ardından bu belleği kullanarak yeni parça oluşturmasını ister.
* Her şey başarısız olursa, `malloc` null döner.
Unutulmamalıdır ki istenen **bellek bir eşiği geçerse**, 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 kilitle** yapmıştır, ancak bu, kilitleme nedeniyle performans sorunlarına yol açmıştır.
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ı, böylece 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ı** eklenirken, heap yöneticisi çekişmeyi azaltmak için onlara **ikincil arenalar** atar. İlk olarak, her yeni iş parçacığını kullanılmayan bir arenaya bağlamaya çalışır, gerekirse yeni arenalar oluşturur, 32 bit sistemler için CPU çekirdeklerinin 2 katı ve 64 bit sistemler için 8 katı kadar bir sınıra kadar. Sınır aşıldığında, **iş parçacıkları arenaları paylaşmak zorunda kalır**, bu da potansiyel çekişmelere yol açar.
Ana arenanın aksine, ikincil 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ş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, bir alt heap için ayrılan boyut, 32 bit işlemler için 1 MB ve 64 bit işlemler için 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 etmesi gerekmeyeceğini 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üketildiğinde, heap yöneticisi devam etmek için yeni bir alt heap oluşturur.
### Meta Veriler
Daha önce belirtildiği gibi, bu parçaların her birinin bazı meta verileri vardı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'dir ve son 3 biti kullanarak aşağıdakileri belirtir:
* `A`: 1 ise alt heap'ten gelir, 0 ise ana arenadadır
* `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 mevcut olduğunda (veya ayrıldığında kullanıcı verilerini depolamak için) önceki parça boyutunu belirtmek için 0x08B bulunur.
Ayrıca, mevcut olduğunda, kullanıcı verileri aynı zamanda bazı verileri de içerecek şekilde kullanılır:
* Bir sonraki parçaya işaretçi
* Önceki parçaya işaretçi
* Listenin bir sonraki parça boyutu
* Listenin bir önceki parça 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>
Listeyi bu şekilde bağlamak, her bir parçanın kaydedildiği bir diziye ihtiyaç duymadan yapılmasını sağlar.
## Serbest Bırakma Korumaları
Serbest işlevinin kazara veya kasıtlı kötüye kullanımından korunmak için, işlemlerini gerçekleştirmeden önce bazı kontroller yapar:
* Adresin [8 bayt veya 64 bit sınırında](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4182) hizalandığından emin olur (`(adres % 16) == 0`), çünkü _malloc_ tüm tahsislerin hizalandığından emin olur.
* Parçanın boyut alanının imkansız olmadığını kontrol eder - ya çok küçük olduğu için, çok büyük olduğu için, hizalanmış bir boyutta olmadığı için veya [işlem adres alanının sonunu aşabileceği için](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4175).
* Parçanın arenanın sınırları içinde olduğunu kontrol eder.
* Parçanın zaten serbest bırakılmış olmadığını kontrol eder, bunu yaparak, başlangıçtaki sonraki parçanın başındaki metadatada bulunan ilgili "P" bitini kontrol eder.
## Bins
Chunks'ın nasıl depolandığındaki verimliliği artırmak için her bir chunk sadece bir bağlı liste içinde değil, çeşitli tiplerde bulunur. Bunlar "bins"lerdir ve 5 tür bin vardır: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) küçük bins, 63 büyük bins, 1 sırasız bin, 10 hızlı bins ve her bir iş parçacığı için 64 tcache bins.
Sırasız, küçük ve büyük bins'e ait başlangıç adresi aynı dizinin içindedir. İndeks 0 kullanılmaz, 1 sırasız bin, 2-64 arası küçük bins'ler ve 65-127 arası büyük bins'lerdir.
### Küçük Bins
Küçük bins'ler büyük bins'lerden daha hızlı ancak hızlı bins'lerden daha yavaştır.
62'nin her bir bininde **aynı boyutta parçalar** bulunur: 16, 24, ... (32 bit'te maksimum 504 bayt, 64 bit'te 1024 bayt). Bu, bir alana yer tahsis edileceği binin bulunması, girişlerin bu listelerden çıkarılması ve eklenmesinde hız sağlar.
### Büyük Bins
Küçük bins'lerin aksine, her **büyük bin belirli bir parça boyutu aralığını yönetir**. Bu daha esnek bir yapıdır, çeşitli boyutları **ayrı bir bin olmadan** barındırabilir.
Bir bellek tahsis edicisinde, büyük bins küçük bins'lerin bittiği yerden başlar. Büyük bins'ler için aralıklar giderek büyür, yani ilk bin 512 ila 576 bayt arasındaki parçaları kapsayabilirken, bir sonraki 576 ila 640 baytı kapsar. Bu desen devam eder, en büyük bin 1MB'nin üzerindeki tüm parçaları içerir.
Büyük bins'ler, bir tahsis için en iyi uyumu bulmak için **farklı parça boyutlarının listesini sıralamak ve aramak zorunda olduklarından küçük bins'lere göre daha yavaş çalışır**. Bir parça büyük bir bine eklenirken sıralanmalı ve bellek tahsis edildiğinde sistem doğru parçayı bulmalıdır. Bu ek işlem onları **daha yavaş** yapar, ancak büyük tahsisler küçük olanlardan daha az olduğundan kabul edilebilir bir takas yapılır.
Şunlar vardır:
* 64B aralığından 32 bin
* 512B aralığından 16 bin
* 4096B aralığından 8 bin
* 32768B aralığından 4 bin
* 262144B aralığından 2 bin
* Geri kalan boyutlar için 1 bin
### Sırasız Bin
Sırasız bin, bellek tahsisini hızlandırmak için kullanılan bir **hızlı önbellek**tir. İşleyişi şöyledir: Bir program belleği serbest bıraktığında, bellek yöneticisi hemen onu belirli bir bine koymaz. Bunun yerine, önce **bitişik serbest parçalarla birleştirmeye çalışır** ve daha büyük bir serbest bellek bloğu oluşturur. Daha sonra, bu yeni parçayı "sırasız bin" adı verilen genel bir bine yerleştirir.
Bir program **bellek istediğinde**, bellek yöneticisi önce sırasız bin'i kontrol eder ve doğru boyutta bir parça bulunup bulunmadığına bakar. Bir tane bulursa hemen kullanır, bu diğer bins'lerde arama yapmaktan daha hızlıdır. Uygun bir parça bulamazsa, serbest bırakılan parçaları doğru bins'lerine, küçük veya büyük, boyutlarına göre taşır.
Bu nedenle, sırasız bin, bellek tahsisini hızlandırmak için yakın zamanda serbest bırakılan belleği hızlı bir şekilde yeniden kullanarak ve zaman alıcı aramaları ve birleştirmeleri azaltarak bir yol sağlar.
{% hint style="danger" %}
Farklı kategorilerdeki parçalar bile olsalar, zaman zaman bir kullanılabilir parça başka bir kullanılabilir parça ile çakışıyorsa (farklı kategorilerde olsalar bile), birleştirileceklerdir.
{% endhint %}
### Hızlı Bins
Hızlı bins'ler, **küçük parçalar için bellek tahsisini hızlandırmak için tasarlanmıştır** ve yakın zamanda serbest bırakılan parçaları hızlı erişimli bir yapıda tutarak bunu sağlar. Bu bins'ler, Son Giren İlk Çıkar (LIFO) yaklaşımını kullanır, yani **en son serbest bırakılan parça**, yeni bir tahsis isteği olduğunda ilk olarak yeniden kullanılır. Bu davranış, bir yığının (LIFO) üstünden (FIFO'ya kıyasla) ekleme ve çıkarma yapmanın daha hızlı olması nedeniyle hız açısından avantajlıdır.
Ayrıca, **hızlı bins'ler tek yönlü bağlı listeleri** kullanır, çift yönlü değil, bu da hızı daha da artırır. Hızlı bins'lerdeki parçalar komşularla birleştirilmediği için, ortadan kaldırma izni veren karmaşık bir yapıya ihtiyaç yoktur. Tek yönlü bağlı liste, bu işlemler için daha basit ve daha hızlıdır.
Temelde burada olan şudur: Başlık (kontrol edilecek ilk parçanın işaretçisi) her zaman o boyuttaki en son serbest bırakılan parçaya işaret eder. Dolayısıyla:
* O boyutta yeni bir parça tahsis edildiğinde, başlık kullanılacak bir serbest parçaya işaret eder. Bu serbest parça bir sonraki kullanılacak parçaya işaret ettiği için, bu adres başlıkta saklanır, böylece bir sonraki tahsis nereden alacağını bilir
* Bir parça serbest bırakıldığında, serbest parça mevcut kullanılabilir parçanın adresini kaydeder ve bu yeni serbest bırakılan parçanın adresi başlığa konur
{% hint style="danger" %}
Hızlı bins'lerdeki parçalar otomatik olarak kullanılabilir olarak ayarlanmaz, bu nedenle diğer parçalarla birleştirilebilme yeteneğine sahip olmaları yerine bir süre hızlı bins parçaları olarak kalırlar.
{% endhint %}
### Tcache (İş Parçacığı Başına Önbellek) Bins
İş parçacıkları kendi belleğe sahip olmaya çalışsa da (bkz. [Arenalar](./#arenas) ve [Alt-bellekler](./#subheaps)), birçok iş parçacığına sahip bir sürecin (örneğin bir web sunucusu) **başka iş parçacıklarıyla belleği paylaşması mümkündür**. Bu durumda, ana çözüm **kilitlerin** kullanılmasıdır, bu da **iş parçacıklarını önemli ölçüde yavaşlatabilir**.
Bu nedenle, bir tcache, her iş parçacığı için bir hızlı bin gibi **tek yönlü bağlı liste** olan bir yapıdır ve parçaları birleştirmez. Her iş parçacığı **64 tek yönlü tcache bins'ine** sahiptir. Her bir bin, [64 bit sistemlerde 24 ila 1032B ve 32 bit sistemlerde 12 ila 516B arasında](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315) maksimum [7 aynı boyutta parça](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) içerebilir.
Bir iş parçacığı bir parçayı serbest bıraktığında, **eğer tcache'e tahsis edilecek kadar büyük değilse** ve ilgili tcache bin **dolu değilse** (zaten 7 parça), **oraya tahsis edilecektir**. Tcache'e gidemezse, genel bins'lerde aramak veya yeni bir tane oluşturmak için bellek kilidinin açılmasını beklemesi gerekir.
Bir **parça tahsis edildiğinde**, eğer **Tcache'te ihtiyaç duyulan boyutta bir serbest parça varsa**, onu kullanır, yoksa genel bins'lerde bir tane bulmak veya yeni bir tane oluşturmak için bellek kilidinin açılmasını beklemesi gerekir.\
Bu durumda bir optimizasyon da vardır, bellek kilidi açıkken, iş parçacığı **istenen boyutta heap parçalarıyla (7) Tcache'ini dolduracaktır**, böylece daha fazla ihtiyaç duyarsa onları Tcache'te bulacaktır.
### Bins sırası
#### Tahsis için:
1. Eğer istenilen boyutta Tcache'te uygun parça varsa, Tcache'i kullan
2. Çok büyükse, mmap kullan
3. Arena heap kilidini al ve:
1. Yeterli küçük boyutta hızlı bin parçası istenilen boyutta mevcutsa, onu kullan ve tcache'i hızlı bindeki parçalarla doldur
2. Mümkünse, yeterince büyük bir parça bulmak için sırasız listesindeki her girişi kontrol et ve tcache'i doldur
3. Mümkünse küçük veya büyük kutuları (istenilen boyuta göre) kontrol et ve tcache'i doldur
4. Mevcut bellekten yeni bir parça oluştur
1. Eğer uygun bellek yoksa, `sbrk` kullanarak daha fazlasını al
2. Ana heap belleği daha fazla genişleyemezse, mmap kullanarak yeni bir alan oluştur
5. Hiçbiri işe yaramazsa, null değerini döndür
**Serbest bırakma için:**
1. İşaretçi Null ise, işlemi bitir
2. Parçada `free` sağlamlık kontrolleri yaparak geçerli bir parça olup olmadığını doğrulamaya çalış
1. Yeterince küçükse ve tcache dolu değilse, oraya koy
2. M biti ayarlıysa (heap değilse), `munmap` kullan
3. Arena heap kilidini al:
1. Hızlı bin'e sığarsa, oraya koy
2. Parça 64KB'den büyükse, hızlı kutuları hemen birleştir ve ortaya çıkan birleştirilmiş parçaları sırasız kutuya koy
3. Parçayı yanındaki serbest bırakılmış parçalarla küçük, büyük ve sırasız kutularda geriye ve ileriye doğru birleştir
4. Başın üstünde ise, kullanılmayan belleğe birleştir
5. Öncekiler değilse, sırasız listesinde sakla
\
Hızlı heap örneği [https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html) ancak arm64'te:
```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 bilginin 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, bu durumda `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ün.
Ekstra boşluklar ayrılmıştır (0x21-0x10=0x11) **eklenen başlıklardan** (0x10) 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
```
##
## 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/)