BROP - Blind Return Oriented Programming
Temel Bilgiler
Bu saldırının amacı, zararlı bir ikili hakkında hiçbir bilgi olmadan bir ROP'u bir tampon taşması aracılığıyla kötüye kullanabilmektir. Bu saldırı aşağıdaki senaryoya dayanmaktadır:
Bir yığın güvenlik açığı ve nasıl tetikleneceği hakkında bilgi.
Bir çökme sonrasında yeniden başlatan bir sunucu uygulaması.
Saldırı
1. Hassas ofseti bulma sunucunun bir arıza tespit edilene kadar bir karakter daha gönderilmesi
2. Canary'yi zorla sızdırmak için
3. Depolanmış RBP ve RIP'yi zorla sızdırmak için yığında adresleri zorla
Bu süreçler hakkında daha fazla bilgiyi burada (BF Forked & Threaded Stack Canaries) ve burada (BF Addresses in the Stack) bulabilirsiniz.
4. Durak cihazını bulma
Bu cihaz temelde, ROP cihazı tarafından bir şeyin yürütüldüğünü onaylamaya izin verir çünkü yürütme çökmüyor. Genellikle, bu cihaz yürütmenin durmasına izin verir ve belirli bir ROP cihazının yürütüldüğünü doğrulamak için ROP cihazlarını ararken ROP zincirinin sonunda konumlandırılır.
5. BROP cihazını bulma
Bu teknik ret2csu cihazını kullanır. Ve bu, eğer bu cihaza birkaç talimatın ortasında erişirseniz, rsi
ve rdi
'yi kontrol etmek için cihazlar elde edersiniz:
Bu cihazlar şunlar olacaktır:
pop rsi; pop r15; ret
pop rdi; ret
Bu cihazlarla bir işlevin 2 argümanını kontrol etmek mümkün olduğuna dikkat edin.
Ayrıca, ret2csu cihazının çok benzersiz bir imzası olduğuna dikkat edin çünkü yığından 6 kaydı çıkaracak. Bu nedenle, aşağıdaki gibi bir zincir göndermek:
'A' * ofset + canary + rbp + ADDR + 0xdead * 6 + STOP
Eğer STOP yürütülürse, bu temelde yığından 6 kaydı çıkaran bir adresin kullanıldığı anlamına gelir. Veya kullanılan adresin aynı zamanda bir DURAK adresi olduğu anlamına gelir.
Bu son seçeneği kaldırmak için önceki birinin 6 kaydı çıkardığını doğrulamak için STOP cihazını yürütmeyecek yeni bir zincir yürütülür:
'A' * ofset + canary + rbp + ADDR
ret2csu cihazının adresini bildiğinizde, rsi
ve rdi
'yi kontrol etmek için cihazların adresini çıkarabilirsiniz.
6. PLT'yi bulma
PLT tablosu, 0x400000'den veya yığın üzerindeki sızdırılan RIP adresinden (eğer PIE kullanılıyorsa) aranabilir. Tablonun girişleri 16B (0x10B) ile ayrılmıştır ve bir işlev çağrıldığında sunucu çökmez, hatta argümanlar doğru değilse. Ayrıca, PLT + 6B'deki bir giriş adresini kontrol etmek de çökmez çünkü bu ilk olarak yürütülen kod olacaktır.
Bu nedenle, PLT tablosunu bulmak için aşağıdaki davranışları kontrol etmek mümkündür:
'A' * ofset + canary + rbp + ADDR + STOP
-> çökme olmaz'A' * ofset + canary + rbp + (ADDR + 0x6) + STOP
-> çökme olmaz'A' * ofset + canary + rbp + (ADDR + 0x10) + STOP
-> çökme olmaz
7. strcmp'i bulma
strcmp
işlevi, karşılaştırılan dize uzunluğunu belirten rdx
kaydını ayarlar. rdx
'in üçüncü argüman olduğunu ve daha sonra programı sızdırmak için write
'ı kullanabilmek için bu değerin 0'dan büyük olması gerektiğini unutmayın.
Şimdi, artık işlevlerin ilk 2 argümanını kontrol edebildiğimiz gerçeğini kullanarak, strcmp
'in PLT'deki konumunu bulmak mümkündür:
strcmp(<okunmayan adres>, <okunmayan adres>) -> çökme
strcmp(<okunmayan adres>, <okunan adres>) -> çökme
strcmp(<okunan adres>, <okunmayan adres>) -> çökme
strcmp(<okunan adres>, <okunan adres>) -> çökme olmaz
Bunu kontrol etmek için PLT tablosunun her girişini çağırarak veya PLT yavaş yolu'nu kullanarak yapılabilir. Bu, temelde PLT tablosundaki bir girişi + 0xb (ki bu dlresolve
'a çağrı yapar) çağırmayı ve yığında taramak istediğiniz giriş numarasını (sıfırdan başlayarak) takip etmeyi içerir:
strcmp(<okunmayan adres>, <okunan adres>) -> çökme
b'A' * ofset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
-> Çökecekstrcmp(<okunan adres>, <okunmayan adres>) -> çökme
b'A' * ofset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
strcmp(<okunan adres>, <okunan adres>) -> çökme olmaz
b'A' * ofset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
Unutmayın ki:
BROP + 0x7
pop RSI; pop R15; ret;
'e işaret ederBROP + 0x9
pop RDI; ret;
'e işaret ederPLT + 0xb dl_resolve'a bir çağrı yapar.
strcmp
bulunduğunda, rdx
'i 0'dan büyük bir değere ayarlamak mümkün olacaktır.
Genellikle rdx
zaten 0'dan büyük bir değere sahip olacaktır, bu nedenle bu adım gereksiz olabilir.
### 8. Write Veya Eşdeğeri Bulma
Son olarak, ikili dosyayı dışa aktarmak için veri dışa aktaran bir araca ihtiyaç duyulmaktadır. Ve bu noktada 2 argümanı kontrol etmek ve rdx
'i 0'dan büyük ayarlamak mümkündür.
Bunu gerçekleştirmek için kötüye kullanılabilecek 3 yaygın fonksiyon bulunmaktadır:
puts(data)
dprintf(fd, data)
write(fd, data, len(data)
Ancak, orijinal makale sadece write
'ı belirtir, bu yüzden ondan bahsedelim:
Mevcut sorun, write fonksiyonunun PLT içinde nerede olduğunu bilmiyor olmamız ve verileri soketimize göndermek için bir fd numarasının olmamasıdır.
Ancak, PLT tablosunun nerede olduğunu biliyoruz ve write'ı davranışına göre bulmak mümkündür. Ve sunucuyla birkaç bağlantı oluşturabiliriz ve yüksek bir FD kullanarak bağlantılarımızdan bazılarıyla eşleşmesini umabiliriz.
Bu fonksiyonları bulmak için davranış imzaları:
'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Veri yazdırıldıysa, puts bulundu'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Veri yazdırıldıysa, dprintf bulundu'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Veri yazdırıldıysa, write bulundu
Otomatik Sömürü
Referanslar
Orijinal makale: https://www.scs.stanford.edu/brop/bittau-brop.pdf
Last updated