BROP - Blind Return Oriented Programming

AWS hackleme konusunda sıfırdan kahraman olmaya kadar öğrenin htARTE (HackTricks AWS Kırmızı Takım Uzmanı) ile!

HackTricks'i desteklemenin diğer yolları:

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

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

Last updated