BROP - Blind Return Oriented Programming

AWS Hacking öğrenin ve pratik yapın:HackTricks Eğitim AWS Kırmızı Takım Uzmanı (ARTE) GCP Hacking öğrenin ve pratik yapın: HackTricks Eğitim GCP Kırmızı Takım Uzmanı (GRTE)

HackTricks'i Destekleyin

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 -> Çökecek

  • strcmp(<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 eder

  • BROP + 0x9 pop RDI; ret;'e işaret eder

  • PLT + 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

Last updated