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

This commit is contained in:
Translator 2024-05-09 18:07:44 +00:00
parent 836bfb990e
commit ce89375958
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
# Hoop
## Heap Begins
Die heap is basies die plek waar 'n program data gaan kan stoor wanneer dit data aanvra deur funksies soos **`malloc`**, `calloc`... Verder, wanneer hierdie geheue nie meer nodig is nie, word dit beskikbaar gestel deur die funksie **`free`** te roep.
Soos dit getoon word, is dit net na waar die binêre lê in die geheue (kyk na die `[heap]` afdeling):
<figure><img src="../../.gitbook/assets/image (1241).png" alt=""><figcaption></figcaption></figure>
### Basiese Stuk Toekenning
Wanneer daar gevra word dat data in die heap gestoor moet word, word 'n deel van die heap daaraan toegewys. Hierdie spasie behoort aan 'n bin en slegs die gevraagde data + die spasie van die bin koppe + minimum bin grootte offset sal vir die stuk gereserveer word. Die doel is om so min moontlik geheue te reserveer sonder om dit moeilik te maak om te vind waar elke stuk is. Hiervoor word die metadata stuk inligting gebruik om te weet waar elke gebruikte/vrye stuk is.
Daar is verskillende maniere om die spasie te reserveer, hoofsaaklik afhangende van die gebruikte bin, maar 'n algemene metodologie is die volgende:
* Die program begin deur 'n sekere hoeveelheid geheue aan te vra.
* As daar in die lys van stukke iemand beskikbaar is wat groot genoeg is om aan die versoek te voldoen, sal dit gebruik word
* Dit kan selfs beteken dat 'n deel van die beskikbare stuk vir hierdie versoek gebruik sal word en die res sal by die stukke lys gevoeg word
* As daar nie enige beskikbare stuk in die lys is nie, maar daar steeds spasie in die toegewysde heap geheue is, skep die heap bestuurder 'n nuwe stuk
* As daar nie genoeg heap spasie is om die nuwe stuk toe te ken nie, vra die heap bestuurder die kernel om die geheue wat aan die heap toegewys is, uit te brei en gebruik dan hierdie geheue om die nuwe stuk te genereer
* As alles misluk, gee `malloc` null terug.
Let daarop dat as die versoekte **geheue 'n drempel oorskry**, sal **`mmap`** gebruik word om die versoekte geheue in te kaart.
### Arenas
In **multidraad** toepassings moet die heap bestuurder **wedren toestande** voorkom wat tot ongelukke kan lei. Aanvanklik is dit gedoen deur 'n **globale grendel** te gebruik om te verseker dat slegs een draad op 'n slag toegang tot die heap kan hê, maar dit het **prestasieprobleme** veroorsaak as gevolg van die grendel-geïnduseerde knelpunt.
Om dit aan te spreek, het die ptmalloc2 heap toewysingsprogram "arenas" ingevoer, waar **elke arena** as 'n **afsonderlike heap** met sy **eie** data **strukture** en **grendel** optree, wat dit vir meerdere drade moontlik maak om heap operasies uit te voer sonder om met mekaar te bots, solank hulle verskillende arenas gebruik.
Die verstek "hoof" arena hanteer heap operasies vir enkel-draad toepassings. Wanneer **nuwe drade** bygevoeg word, ken die heap bestuurder hulle **sekondêre arenas** toe om kontensie te verminder. Dit probeer eers om elke nuwe draad aan 'n ongebruikte arena te koppel, nuwes te skep indien nodig, tot 'n limiet van 2 keer die CPU kerne vir 32-bis stelsels en 8 keer vir 64-bis stelsels. Sodra die limiet bereik is, **moet drade arenas deel**, wat tot potensiële kontensie kan lei.
In teenstelling met die hoof arena, wat uitbrei deur die `brk` stelseloproep te gebruik, skep sekondêre arenas "subheaps" deur `mmap` en `mprotect` te gebruik om die heap gedrag na te boots, wat buigsaamheid bied om geheue vir multidraad operasies te bestuur.
### Subheaps
Subheaps dien as geheue reserwes vir sekondêre arenas in multidraad toepassings, wat hulle in staat stel om te groei en hul eie heap areas apart van die hoof heap te bestuur. Hier is hoe subheaps verskil van die aanvanklike heap en hoe hulle werk:
1. **Aanvanklike Heap vs. Subheaps**:
* Die aanvanklike heap is direk na die program se binêre in die geheue geleë, en dit brei uit deur die `sbrk` stelseloproep te gebruik.
* Subheaps, wat deur sekondêre arenas gebruik word, word geskep deur `mmap`, 'n stelseloproep wat 'n gespesifiseerde geheue area in kaart bring.
2. **Geheue Reservering met `mmap`**:
* Wanneer die heap bestuurder 'n subheap skep, reserver hy 'n groot blok geheue deur `mmap`. Hierdie reservering maak nie dadelik geheue toe nie; dit dui eenvoudig 'n area aan wat ander stelsel prosesse of toekennings nie moet gebruik nie.
* Standaard is die gereserveerde grootte vir 'n subheap 1 MB vir 32-bis prosesse en 64 MB vir 64-bis prosesse.
3. **Gegradueerde Uitbreiding met `mprotect`**:
* Die gereserveerde geheue area word aanvanklik gemerk as `PROT_NONE`, wat aandui dat die kernel nie fisiese geheue aan hierdie spasie hoef toe te ken nie.
* Om die subheap te "groei", gebruik die heap bestuurder `mprotect` om bladsy toestemmings van `PROT_NONE` na `PROT_READ | PROT_WRITE` te verander, wat die kernel aanmoedig om fisiese geheue aan die voorheen gereserveerde adresse toe te ken. Hierdie stap-vir-stap benadering laat die subheap toe om soos nodig uit te brei.
* Sodra die hele subheap uitgeput is, skep die heap bestuurder 'n nuwe subheap om voort te gaan met toekenning.
### Metadata
Soos voorheen opgemerk, het hierdie stukke ook 'n paar metadata, baie goed voorgestel in hierdie beeld:
<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>
Die metadata is gewoonlik 0x08B wat die huidige stuk grootte aandui deur die laaste 3 bits te gebruik om aan te dui:
* `A`: As 1 kom dit van 'n subheap, as 0 is dit in die hoof arena
* `M`: As 1, is hierdie stuk deel van 'n spasie wat toegewys is met mmap en nie deel van 'n heap is nie
* `P`: As 1, is die vorige stuk in gebruik
Dan die spasie vir die gebruikersdata, en uiteindelik 0x08B om die vorige stuk grootte aan te dui wanneer die stuk beskikbaar is (of om gebruikersdata te stoor wanneer dit toegewys is).
Verder, wanneer beskikbaar, word die gebruikersdata ook gebruik om ook 'n paar data te bevat:
* Aanwysing na die volgende stuk
* Aanwysing na die vorige stuk
* Grootte van die volgende stuk in die lys
* Grootte van die vorige stuk in die lys
<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>
Let op hoe die lys op hierdie manier koppel, voorkom die behoefte om 'n array te hê waar elke enkele stuk geregistreer word.
## Vrywaring Beskerming
Om te beskerm teen die toevallige of opsetlike misbruik van die vry funksie, voer dit voor die uitvoering van sy aksies 'n paar kontroles uit:
* Dit kontroleer dat die adres [gealinieer](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4182) is op 'n 8-byte of 16-byte op 'n 64-bis grens (`(address % 16) == 0`), aangesien _malloc_ verseker dat alle toekennings gealinieer is.
* Dit kontroleer dat die stuk se grootte veld nie onmoontlik is nie of omdat dit [te klein](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4318) is, te groot, nie 'n gealinieerde grootte is, of [oor die einde van die proses se adres spasie sou oorvleuel](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4175).
* Dit kontroleer dat die stuk binne die grense van die arena lê.
* Dit kontroleer dat die stuk nie reeds as vry gemerk is nie deur die ooreenstemmende "P" bit te kontroleer wat in die metadata aan die begin van die volgende stuk lê.
## Bins
Om die doeltreffendheid van hoe stukke gestoor word te verbeter, is elke stuk nie net in een gekoppelde lys nie, maar daar is verskeie tipes. Dit is die bakkies en daar is 5 tipes bakkies: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) klein bakkies, 63 groot bakkies, 1 ongesorteerde bak, 10 vinnige bakkies en 64 tcache bakkies per draad.
Die aanvanklike adres vir elke ongesorteerde, klein en groot bakkies is binne dieselfde reeks. Die indeks 0 word nie gebruik nie, 1 is die ongesorteerde bak, bakkies 2-64 is klein bakkies en bakkies 65-127 is groot bakkies.
### Klein Bakkies
Klein bakkies is vinniger as groot bakkies maar stadiger as vinnige bakkies.
Elke bak van die 62 sal **stukke van dieselfde grootte hê**: 16, 24, ... (met 'n maksimum grootte van 504 byte in 32-bits en 1024 in 64-bits). Dit help met die spoed om die bak te vind waar 'n spasie toegewys moet word en om inskrywings op hierdie lyste in te voeg en te verwyder.
### Groot Bakkies
In teenstelling met klein bakkies, wat stukke van vaste groottes bestuur, hanteer elke **groot bak 'n reeks stukgroottes**. Dit is meer buigsaam, wat die stelsel in staat stel om **verskeie groottes** te akkommodeer sonder 'n afsonderlike bak vir elke grootte nodig te hê.
In 'n geheue-toewysingsprogram begin groot bakkies waar klein bakkies eindig. Die reekse vir groot bakkies word progressief groter, wat beteken dat die eerste bak dalk stukke van 512 tot 576 byte dek, terwyl die volgende 576 tot 640 byte dek. Hierdie patroon gaan voort, met die grootste bak wat alle stukke bo 1MB bevat.
Groot bakkies is stadiger om mee te werk in vergelyking met klein bakkies omdat hulle moet **sorteer en deur 'n lys van wisselende stukgroottes soek om die beste pasmaat** vir 'n toewysing te vind. Wanneer 'n stuk in 'n groot bak ingevoeg word, moet dit gesorteer word, en wanneer geheue toegewys word, moet die stelsel die regte stuk vind. Hierdie ekstra werk maak hulle **stadiger**, maar aangesien groot toekenning minder algemeen is as klein eenhede, is dit 'n aanvaarbare afweging.
Daar is:
* 32 bakkies van 64B reeks
* 16 bakkies van 512B reeks
* 8 bakkies van 4096B reeks
* 4 bakkies van 32768B reeks
* 2 bakkies van 262144B reeks
* 1 bak vir oorblywende groottes
### Ongesorteerde bak
Die ongesorteerde bak is 'n **vinnige buffer** wat deur die geheue-bestuurder gebruik word om geheue toewysing vinniger te maak. So werk dit: Wanneer 'n program geheue vrymaak, plaas die geheue-bestuurder dit nie dadelik in 'n spesifieke bak nie. In plaas daarvan probeer dit eers om dit **saam te voeg met enige aangrensende vry stukke** om 'n groter blok vry geheue te skep. Dan plaas dit hierdie nuwe stuk in 'n algemene bak genaamd die "ongesorteerde bak."
Wanneer 'n program **vir geheue vra**, kyk die geheue-bestuurder **eerstens na die ongesorteerde bak** om te sien of daar 'n stuk van die regte grootte is. As dit een vind, gebruik dit dit dadelik, wat vinniger is as om deur ander bakkies te soek. As dit nie 'n geskikte stuk vind nie, skuif dit die vrygemaakte stukke na hul regte bakkies, klein of groot, gebaseer op hul grootte.
Dus, die ongesorteerde bak is 'n manier om geheue toewysing te versnel deur onlangs vrygemaakte geheue vinnig te hergebruik en die behoefte aan tydrowende soektogte en samenvoegings te verminder.
{% hint style="danger" %}
Let daarop dat selfs al is stukke van verskillende kategorieë, van tyd tot tyd, as 'n beskikbare stuk bots met 'n ander beskikbare stuk (selfs al is hulle van verskillende kategorieë), sal hulle saamgevoeg word.
{% endhint %}
### Vinnige bakkies
Vinnige bakkies is ontwerp om **geheue toewysing vir klein stukke te versnel** deur onlangs vrygemaakte stukke in 'n vinnig toeganklike struktuur te hou. Hierdie bakkies gebruik 'n Laaste-In, Eerste-Uit (LIFO) benadering, wat beteken dat die **mees onlangs vrygemaakte stuk eerste** hergebruik word wanneer daar 'n nuwe toekenningsversoek is. Hierdie gedrag is voordelig vir spoed, aangesien dit vinniger is om van die boonste van 'n stok (LIFO) in te voeg en te verwyder in vergelyking met 'n ry (FIFO).
Daarbenewens **gebruik vinnige bakkies enkelgelinkte lyste**, nie dubbelgelinkte nie, wat die spoed verder verbeter. Aangesien stukke in vinnige bakkies nie saamgevoeg word met bure nie, is daar geen behoefte aan 'n komplekse struktuur wat verwydering uit die middel toelaat nie. 'n Enkelgelinkte lys is eenvoudiger en vinniger vir hierdie operasies.
Basies, wat hier gebeur is dat die kop (die aanwyser na die eerste stuk om te kontroleer) altyd na die mees onlangs vrygemaakte stuk van daardie grootte wys. So:
* Wanneer 'n nuwe stuk van daardie grootte toegewys word, wys die kop na 'n vry stuk om te gebruik. Aangesien hierdie vry stuk na die volgende een om te gebruik wys, word hierdie adres in die kop gestoor sodat die volgende toekenning weet waar om 'n beskikbare stuk te kry
* Wanneer 'n stuk vrygemaak word, sal die vrye stuk die adres na die huidige beskikbare stuk stoor en die adres na hierdie nuut vrygestelde stuk sal in die kop geplaas word
{% hint style="danger" %}
Stukke in vinnige bakkies word nie outomaties as beskikbaar ingestel nie, sodat hulle as vinnige bak stukke vir 'n ruk gehou word in plaas daarvan om met ander stukke saamgevoeg te kan word.
{% endhint %}
### Tcache (Per-Draad-Kas) Bakkies
Selfs al probeer drade hul eie geheue hê (sien [Arenas](./#arenas) en [Subheaps](./#subheaps)), is daar die moontlikheid dat 'n proses met baie drade (soos 'n webbediener) **die geheue met ander drade sal deel**. In hierdie geval is die hoofoplossing die gebruik van **slotte**, wat die drade aansienlik **stadiger kan maak**.
Daarom is 'n tcache soortgelyk aan 'n vinnige bak per draad op die manier dat dit 'n **enkelgelinkte lys** is wat nie stukke saamvoeg nie. Elke draad het **64 enkelgelinkte tcache bakkies**. Elke bak kan 'n maksimum van [7 stukke van dieselfde grootte hê](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) wat wissel van [24 tot 1032B op 64-bits stelsels en 12 tot 516B op 32-bits stelsels](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
**Wanneer 'n draad 'n stuk vrymaak**, **as dit nie te groot is** om in die tcache toegewys te word en die betrokke tcache bak **nie vol is** (reeds 7 stukke), **sal dit daar toegewys word**. As dit nie na die tcache kan gaan nie, moet dit wag vir die geheue-slot om die vry operasie globaal uit te voer.
Wanneer 'n **stuk toegewys word**, as daar 'n vry stuk van die benodigde grootte in die **Tcache is, sal dit dit gebruik**, indien nie, moet dit wag vir die geheue-slot om een in die globale bakkies te vind of 'n nuwe een te skep.\
Daar is ook 'n optimisering, in hierdie geval, terwyl die geheue-slot gehou word, **sal die draad sy Tcache met geheue stukke (7) van die gevraagde grootte vul**, sodat as dit meer benodig, dit hulle in die Tcache sal vind.
### Bakkies volgorde
#### Vir toewysing:
1. As daar 'n beskikbare stuk in Tcache van daardie grootte is, gebruik Tcache
2. Dit is baie groot, gebruik mmap
3. Verkryg die arena hoop slot en:
1. As genoeg klein grootte, vinnige bakkie stuk beskikbaar van die versoekte grootte, gebruik dit en vul die tcache vanaf die vinnige bakkie
2. Kontroleer elke inskrywing in die ongesorteerde lys op soek na een stuk groot genoeg, en vul die tcache indien moontlik
3. Kontroleer die klein bakkies of groot bakkies (volgens die versoekte grootte) en vul die tcache indien moontlik
4. Skep 'n nuwe stuk van beskikbare geheue
1. As daar nie beskikbare geheue is nie, kry meer deur `sbrk` te gebruik
2. As die hoof hoopgeheue nie verder kan groei nie, skep 'n nuwe spasie deur mmap te gebruik
5. As niks gewerk het nie, gee null terug
**Vir vrylating:**
1. As die wyser Nul is, voltooi
2. Voer `free` gesondheidskontroles in die stuk uit om te probeer verifieer dit is 'n regte stuk
1. As dit klein genoeg is en die tcache nie vol is nie, sit dit daar
2. As die bit M ingestel is (nie hoop nie), gebruik `munmap`
3. Kry arena hoop slot:
1. As dit in 'n vinnige bakkie pas, sit dit daar
2. As die stuk > 64KB is, konsolideer die vinnige bakkies onmiddellik en sit die resulterende saamgevoegde stukke op die ongesorteerde bakkie.
3. Voeg die stuk agteruit en vorentoe saam met aangrensende vrygestelde stukke in die klein, groot, en ongesorteerde bakkies indien enige.
4. As dit bo-aan die kop is, voeg dit saam in die ongebruikte geheue
5. As dit nie die voriges is nie, stoor dit in die ongesorteerde lys
\
Vinnige hoopvoorbeeld van [https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html) maar in arm64:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(void)
{
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
}
```
Stel 'n breekpunt in aan die einde van die hooffunksie en laat ons uitvind waar die inligting gestoor was:
<figure><img src="../../.gitbook/assets/image (1239).png" alt=""><figcaption></figcaption></figure>
Dit is moontlik om te sien dat die string panda gestoor was by `0xaaaaaaac12a0` (wat die adres was wat as antwoord deur malloc binne `x0` gegee is). Deur 0x10 byte voor dit te ondersoek, is dit moontlik om te sien dat die `0x0` aandui dat die **vorige blok nie gebruik word nie** (lengte 0) en dat die lengte van hierdie blok `0x21` is.
Die ekstra spasies wat voorbehou is (0x21-0x10=0x11) kom van die **bygevoegde koppe** (0x10) en 0x1 beteken nie dat 0x21B voorbehou is nie, maar die laaste 3 bits van die lengte van die huidige kop het 'n paar spesiale betekenisse. Aangesien die lengte altyd 16-byte uitgelyn is (in 64-bits masjiene), gaan hierdie bits eintlik nooit deur die lengtenommer gebruik word nie.
```
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
```
##
## Verwysings
* [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/)