Windows ALPC漏洞复现

说明

如题所示,为了加深理解ALPC机制以及该类错误模式所以我决定复现一下历史上关于ALPC的漏洞,并在这里留下我的笔记

关于ALPC的知识:

https://csandker.io/2022/05/24/Offensive-Windows-IPC-3-ALPC.html

http://publications.alex-ionescu.com/SyScan/SyScan%202014%20-%20All%20about%20the%20ALPC,%20RPC,%20LPC,%20LRPC%20in%20your%20PC.pdf

错误类型

利用WinObjEx64可以查看所有的ALPC端口名称,这些名称有相当多是RPC服务器创建的,只有一小部分是通过NtAlpcCreatePort创建,并且它们大部分是在用户进程下创建的
在这里插入图片描述
虽然有几个用户模式下的system进程创建的ALPC端口名可以连接,历史上也有通过此模式触发的漏洞,比如错误报告服务漏洞,由于个人原因,我想专注于内核,操作系统默认情况运行下只有pdc.sys创建了\PdcPort提供连接,但是该端口具有ALPC_PORTFLG_SYSTEM_PROCESS属性,这不是一个EOP的条件
在这里插入图片描述
不仅可以从ALPC客户端和ALPC服务端通信下手,还可以关注ALPC API本身的错误,因为它们是在ntoskrnl.exe实现的NT API

CVE-2021-34514

该CVE在2021年7月发布,下图为ntoskrnl.exe补丁情况
在这里插入图片描述

我们知道只需要关注AlpcpCompleteDispatchMessage,其中RtlpCreateServerAcl修补的是整数溢出问题,且调用链处于SeSetSecurityDescriptorInfo,这里不做深入分析,只关注AlpcpCompleteDispatchMessage

AlpcpCompleteDispatchMessage补丁前从直接从用户态映射到内核内存地址也就是v47里读取长度理论知识参考:

Windows驱动中通过MDL实现用户态与核心态共享内存
https://www.cnblogs.com/kuangke/p/9397676.html
mdl
https://blog.csdn.net/weixin_43742894/article/details/104870641

为什么我知道这v47是用户态映射,其实这个漏洞已经有一些细节公开,虽然只有理论知识,但是这对于探索该漏洞非常有用

演讲视频

https://www.youtube.com/watch?v=1CjQ1_QWssI

pdf

conference.hitb.org/hitbsecconf2014kul/materials/D2T1%20-%20Ben%20Nagy%20-%20ALPC%20Fuzzing%20Toolkit.pdf

在这里插入图片描述

在这里插入图片描述
补丁后虽然还是会读取共享内存中的长度,但是在读到长度后立刻保存到局部变量v25中而不是直接从共享内存中读取长度,这样做是为了消除红框内中的可以用来竞争时间的代码端

在这里插入图片描述

附上调试验证共享内存过程

0: kd> !process 0n9632 0      //查看服务端DirBase
Searching for Process with Cid == 25a0
PROCESS ffff8e8637f0d080
    SessionId: 1  Cid: 25a0    Peb: 862f445000  ParentCid: 1a58
    DirBase: 10234e000  ObjectTable: ffffdb0aa2eb1680  HandleCount:  40.
    Image: test3.exe

0: kd> !vtop 10234e000 304000  
//WINDBG 命令 虚拟地址转换物理地址https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/converting-virtual-addresses-to-physical-addresses
//x64分页查找手动物理内存  https://bbs.pediy.com/thread-203391.htm
//10234e000 为服务端进程DirBase  0x304000 为消息缓冲区部分 这块内存属于手动申请的
Amd64VtoP: Virt 0000000000304000, pagedir 000000010234e000
Amd64VtoP: PML4E 000000010234e000
Amd64VtoP: PDPE 000000002e048000
Amd64VtoP: PDE 0000000062bae008
Amd64VtoP: PTE 000000008b6af820
Amd64VtoP: Mapped phys 000000010afbb000
Virtual address 304000 translates to physical address 10afbb000.   //虚拟地址转换后的物理地址
0: kd> !dq 10afbb000  //此时没有接受消息 所以为空  记住10afbb000这个物理地址
#10afbb000 00000000`00000000 00000000`00000000
#10afbb010 00000000`00000000 00000000`00000000
#10afbb020 00000000`00000000 00000000`00000000
#10afbb030 00000000`00000000 00000000`00000000
#10afbb040 00000000`00000000 00000000`00000000
#10afbb050 00000000`00000000 00000000`00000000
#10afbb060 00000000`00000000 00000000`00000000
#10afbb070 00000000`00000000 00000000`00000000
0: kd> bp nt!AlpcpCompleteDispatchMessage+0x155d0c  //对漏洞代码段下断点
0: kd> g
Breakpoint 0 hit
nt!AlpcpCompleteDispatchMessage+0x155d0c:
fffff801`df8448bc 410fb74602      movzx   eax,word ptr [r14+2]
windbg> q r14
Too many arguments specified.
1: kd> dq r14   //查看消息内存映射内容
ffffb801`c510d000  00002001`040003d8 00000000`00002408
ffffb801`c510d010  00000000`000025c4 00000000`00151e38
ffffb801`c510d020  00000000`0042a490 43434343`43434343
ffffb801`c510d030  43434343`43434343 43434343`43434343
ffffb801`c510d040  43434343`43434343 43434343`43434343
ffffb801`c510d050  43434343`43434343 43434343`43434343
ffffb801`c510d060  43434343`43434343 43434343`43434343
ffffb801`c510d070  43434343`43434343 43434343`43434343
1: kd> !pte ffffb801`c510d000   //查看消息内存映射内容的物理地址
                                           VA ffffb801c510d000
PXE at FFFFFB7DBEDF6B80    PPE at FFFFFB7DBED70038    PDE at FFFFFB7DAE007140    PTE at FFFFFB5C00E28868
contains 0A00000002D44863  contains 0A00000002D43863  contains 0A0000010DCEE863  contains 8A0000010AFBB963
pfn 2d44      ---DA--KWEV  pfn 2d43      ---DA--KWEV  pfn 10dcee    ---DA--KWEV  pfn 10afbb    -G-DA--KW-V

1: kd> !dq 10afbb000  //10afbb000  这个物理地址与之前查看服务端申请的那块用户地址所在的物理地址相同
#10afbb000 00002001`040003d8 00000000`00002408
#10afbb010 00000000`000025c4 00000000`00151e38
#10afbb020 00000000`0042a490 43434343`43434343
#10afbb030 43434343`43434343 43434343`43434343
#10afbb040 43434343`43434343 43434343`43434343
#10afbb050 43434343`43434343 43434343`43434343
#10afbb060 43434343`43434343 43434343`43434343
#10afbb070 43434343`43434343 43434343`43434343

AlpcpCompleteDispatchMessage被NtAlpcSendWaitReceivePort调用,如果对它打下断点,几乎每时每刻都会被命中,ALPC真的无处不在

该漏洞与ALPC通信机制中的完成列表机制有关,如果要使用这种方式通信,服务端需要在创建端口之后通过调用NtAlpcSetInformation传入AlpcRegisterCompletionListInformation参数可设置通信机制为ALPC完成列表,该函数的参数还有一个PALPC_COMPLETION_LIST_HEADER结构体,该结构中的AttributeFlags表示消息alpc通信过程中的消息属性,而该结构中的PALPC_COMPLETION_LIST_HEADER结构几乎包含了完成列表的所有信息,但是这些字段是系统分配的,对NtAlpcSetInformation稍微逆向分析即可知道如何成功设置完成列表机制

在这里插入图片描述

这些ALPC结构声明可以通过下面找到,你也可以在上面搜索任何NT API声明

https://sourcegraph.com/search?q=context:global+_ALPC_COMPLETION_LIST_HEADER&patternType=literal

在这里插入图片描述

由于演讲视频中公开细节的人讲的已经足够好,如果观看他的演讲视频并不放过任何可能有用的话去理解,那么就能理解这个漏洞,嗯…为了验证我对这个漏洞的理解正确,我做出了poc:

https://github.com/tianlinlintian/test/blob/main/alpc%20completion%20list

一旦使用完成列表进行通信,那么服务端接受客户端消息时,消息类型以及消息内容等信息不会保存在ReceiveBuffer->u2.s2.Type,而是第一时间保存在完成列表设置的PALPC_COMPLETION_LIST_HEADER+Buffer->DataOffset偏移,最后小小吐槽一下ALPC异步处理消息也就是默认处理消息,这种方式就必须得配上一个类似事件类的机制来控制消息接受和处理,否则相当容易造成混乱

CVE-2022-23283

注意:此漏洞只能在32位操作系统触发,而此文是在64位上实验的

该CVE在2022年3月发布,下图为ntoskrnl.exe x32位补丁前中的AlpcAddHandleTableEntry函数存在整数溢出漏洞

在这里插入图片描述

AlpcAddHandleTableEntry补丁后会判断v4字段的值,防止过大造成整数溢出

AlpcAddHandleTableEntry可以被客户端调用时NtAlpcCreatePortSection被调用,那么这个溢出点变量是什么字段?该字段来源于结构_ALPC_PORT中的CommunicationInfo 中的TotalHandles字段

在这里插入图片描述
在这里插入图片描述

相应声明:

typedef struct _ALPC_HANDLE_TABLE {
	_ALPC_HANDLE_ENTRY Handles;
	UINT TotalHandles;
	UINT Flags;
	_EX_PUSH_LOCK Lock;
} ALPC_HANDLE_TABLE, * PALPC_HANDLE_TABLE;



typedef struct _KALPC_SECURITY_DATA
{
	PALPC_HANDLE_TABLE HandleTable;
	LPVOID ContextHandle;
	LPVOID OwningProcess;
	LPVOID OwnerPort;
	_SECURITY_CLIENT_CONTEXT DynamicSecurity;
} KALPC_SECURITY_DATA, * PKALPC_SECURITY_DATA;

该TotalHandles字段在服务端调用NtAlpcCreatePort时会进而调用AlpcInitializeHandleTable然后将该字段值初始化为0x10

在这里插入图片描述
设置TotalHandles字段可以调用NtAlpcCreateResourceReserve,该字段以0x10>>0x20>>0x40>>0x80>>0x100>>…相乘二的规律依次类记,所以只需要调用足够多次数的NtAlpcCreateResourceReserve就能造成溢出

在运行Poc(https://github.com/tianlinlintian/test/blob/main/NtAlpcCreateResourceReserve)放置了一晚后我放弃了,因为poc只跑到了0x1000000,但在x32上触发此漏洞只是时间问题

在这里插入图片描述

最近的几个月还有一些ALPC api竞争条件漏洞,但是我没有复现成功,因为alpc的不透明性以及它们的调用链比较长我也没有太多时间倒推

关于挖掘此类漏洞的看法:我认为这些漏洞都是通过fuzz出来的,事实证明它们也很适合被fuzz

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值