BROP - Blind Return Oriented Programming
Temel Bilgiler
Bu saldırının amacı, zararlı bir ikili hakkında hiçbir bilgi olmadan bir ROP'yi 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ı 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 kaba kuvvetle çözme sızdırmak için
3. Depolanmış RBP ve RIP'yi kaba kuvvetle çözme adreslerini yığında sızdırmak için
Bu işlemler 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 ilginç bir şekilde yürütüldüğünü onaylamaya izin verir çünkü yürütme çökmemiştir. Genellikle, bu cihaz yürütümü durduran bir şey olacak 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ılacaktır.
5. BROP cihazını bulma
Bu teknik, ret2csu cihazını kullanır. Ve bu, eğer bu cihaza bir talimatları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ündür.
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 mümkündür:
'A' * ofset + canary + rbp + ADRES + 0xdead * 6 + DURAK
Eğer DURAK yürütülürse, bu temelde yığından 6 kaydı çıkaran bir adresin kullanıldığı anlamına gelir. Veya kullanılan adres aynı zamanda bir DURAK adresiydi.
Bu son seçeneği kaldırmak için önceki birinin 6 kaydı çıkardığını doğrulamak için aşağıdaki gibi yeni bir zincir yürütülür ve DURAK cihazını yürütmemesi gerekir:
'A' * ofset + canary + rbp + ADRES
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, argümanlar doğru olmasa bile çökmeyecektir. Ayrıca, PLT + 6B'deki bir giriş adresini kontrol etmek de çökmeyecektir çü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 + ADRES + DURAK
-> çökme olmaz'A' * ofset + canary + rbp + (ADRES + 0x6) + DURAK
-> çökme olmaz'A' * ofset + canary + rbp + (ADRES + 0x10) + DURAK
-> çökme olmaz
7. strcmp'i bulma
strcmp
işlevi, karşılaştırılan dize uzunluğunu belirlemek için rdx
kaydını ayarlar. rdx
'in üçüncü argüman olduğunu ve daha sonra programı sızdırmak için write
'ı kullanabilmek için bunun 0'dan büyük olması gerektiğini unutmayın.
Şimdi, artık fonksiyonların ilk 2 argümanını kontrol edebildiğimiz gerçeğini kullanarak, PLT'deki strcmp'in 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(GİRİŞ) + DURAK
-> Çökecekstrcmp(<okunan adres>, <okunmayan adres>) -> çökme
b'A' * ofset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(GİRİŞ) + DURAK
strcmp(<okunan adres>, <okunan adres>) -> çökme olmaz
b'A' * ofset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(GİRİŞ) + DURAK
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 bilmiyoruz ve verileri soketimize göndermek için bir fd numarası bilmiyoruz.
Ancak, PLT tablosunun nerede olduğunu biliyoruz ve davranışına dayanarak write'ı bulmak mümkündür. Ve sunucuyla birkaç bağlantı oluşturabiliriz ve yüksek bir FD kullanabiliriz umarak bağlantılarımızdan bazılarıyla eşleştiğini 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
-> Eğer veri yazdırılıyorsa, puts bulundu'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Eğer veri yazdırılıyorsa, 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
-> Eğer veri yazdırılıyorsa, write bulundu
Otomatik Sömürü
Referanslar
Orijinal makale: https://www.scs.stanford.edu/brop/bittau-brop.pdf
Last updated