Memory leak oracle¶
İkili, gözlemlenebilir bir program davranışını (crash mı survive mı, askıda mı kalıyor yanıt mı veriyor, hızlı mı yavaş mı) byte-başına bir teste dönüştür; böylece herhangi bir doğrudan read primitive olmadan gizli belleği — canary'ler, pointer'lar, kod — yeniden inşa et.
Mechanism¶
Suistimal edilen invariant
Bir leak oracle, dolaylı bir sinyali information disclosure'a çevirir. Kanonik örnek, Bittau ve diğerlerinin "Hacking Blind" (IEEE S&P / Oakland 2014, BROP saldırısı) çalışmasındaki stack-reading crash oracle'ıdır. Her connection için taze bir worker fork'layan bir network servisi, child process'ler arasında aynı stack canary'yi ve aynı kod/library layout'unu korur. Bir gizli değere kadar (örn. stack canary) overflow yapabilen bir saldırgan, onu her seferinde bir byte overwrite eder ve oracle'ı gözlemler:
- tahmin edilen byte doğru → değer eşleşir, function normal döner, servis ayakta kalır;
- tahmin edilen byte yanlış →
__stack_chk_fail/ corruption → worker crash olur, connection düşer.
Her pozisyonun yalnızca 256 olasılığı olduğu ve yanlış bir tahmin doğru olandan ayırt edilebildiği için, b-byte'lık bir değer için secret beklenen 128 × b request'te kurtarılır (üstel değil, lineer). Aynı oracle saklı return adreslerini ve frame pointer'ları okur; 64-bit hedeflerde hiçbir information-leak bug'ı ve binary'nin bir kopyası olmadan ASLR'ı ve stack canary'leri etkisiz bırakır.
Walkthrough¶
Bilinen bir overflow'a sahip fork'layan bir servise karşı stack-reading loop'u:
def leak_byte(known_prefix):
for guess in range(256):
payload = b"A"*PAD + known_prefix + bytes([guess])
conn = connect(target)
conn.send(payload)
if survives(conn): # oracle: still responsive == correct
return guess
# crash (connection reset) == wrong guess, try next
raise RuntimeError("no byte survived")
secret = b""
for _ in range(SECRET_LEN): # e.g. 8 bytes of canary
secret += bytes([leak_byte(secret)])
survives() predicate'i oracle'dır. BROP'ta bu "TCP connection açık kaldı mı?" demektir; başka ortamlarda bir timing farkı, bir error string'i, bir exception tipi ya da farklı bir yanıt boyutu olabilir.
Oracle sinyal biçimleri
Tuzaklar / önkoşullar
- Hedef, yanlış bir tahminden sonra deterministik olarak toparlanmalı ve denemeler boyunca secret'ı korumalı — tipik olarak request başına
fork()yapan bir sunucu (child, parent'ın canary/layout'unu miras alır). Request başınaexec()yapan ya da yeniden randomize eden bir sunucu oracle'ı kırar. - Sinyal temiz olmalı: gürültülü ağlar, rate limit'ler ya da crash-restart gecikmeleri request sayılarını şişirir ve predicate'i ters çevirebilir. Belirsiz byte'larda tekrarla-ve-oyla.
- Saklı RIP'ye ulaşmadan önce canary'yi ilk okumak zorunludur — canary'nin ötesini yanlış değerle overwrite edersen return pointer'ına ulaşmadan crash olursun.
- Byte sırası önemlidir: bilinen prefix'i overflow'un büyüdüğü yönde uzatırsın.
Detection¶
Crash-loop izleme en yüksek sinyalli savunmadır: tek bir peer'dan yüzlerce kez __stack_chk_fail abort'u ya da SIGSEGV saçan fork'layan bir servis anormaldir. Canary başarısızlıklarının connection başına loglanması, rate limiting ve anormal child-crash oranlarında alarm verilmesi brute force'u açığa çıkarır.
Mitigation¶
Fork'lar arası kalıtım olmadan secret'ları process başına yeniden randomize et (re-exec ya da request başına canary/ASLR yeniden seed'leme), yalnızca worker yerine corruption'da tüm-servisi-sonlandır ve crash throttling ekle ki oracle'ın request bütçesi patlasın. Altta yatan overflow'u kaldırmak oracle'ı tümüyle ortadan kaldırır.