ProxyLogon漏洞分析
组件架构
Exchange不同版本的组件架构并不相同,但总体上可以将其分为核心的邮箱服务器角色(Mailbox Role)和可选的边缘传输角色(Edge Transport Role)。
- Exchange作为边缘传输角色时部署在内外网交界处,充当邮件安全网关
Exchange作为邮箱服务器角色时分为客户端访问服务(Client Access Services)和后端服务(Backend Services)部分,CAS负责校验用户身份并将请求反代至具体的后端服务。
CAS对应IIS中的Default Web Site
监听在80和443端口,BS对应IIS中的Exchange Back End
监听在81和444端口。
出于解耦和兼容考虑,各个功能被封装为多个模块,有如下常用功能(缩写名对应URL访问路径):
- OWA(Outlook Web App)
- ECP(Exchange Control Panel)
- EWS(Exchange Web Service)
- Autodiscover
- MAPI(Messaging Application Programming Interface)
- EAS(Exchange ActiveSync)
- OAB(Offline Address Books)
- PowerShell
影响版本
- Exchange Server 2013 < Mar21SU
- Exchange Server 2016 < Mar21SU < CU20
- Exchange Server 2019 < Mar21SU < CU9
补丁分析
根据微软官方通告可以知道ProxyLogon漏洞的补丁编号为KB5000871,也可以看到此补丁的前置补丁编号为KB4602269,将两个msp补丁文件下载下来并通过7z解压得到多个dll。
- 也可以在Microsoft Update Catalog中搜索补丁编号下载cab文件并解压
下载dnSpy用于反编译和调试C#的dll文件。由于我们并不是要调试二进制洞,为了避免干扰需要取消勾选View->Options->Decompiler->ILSpy->Show tokens, RVAs and file offsets
。将解压出的dll拖入dnSpy并选中高亮,通过File->Export to Project
就可以得到反编译后的工程文件。
拿到补丁前后两份反编译的源码后,在低版本源码文件夹建立git目录,再将高版本源码文件覆盖过来:
1 | cd kb4602269 |
这样就能在任意支持git管理的IDE中方便地进行补丁对比了(比如VSCode),小缺点就是有的整个文件就一点无关紧要的字符变化而已(之前对比vCenter时也是),而我们显然只是想关注一些函数和流程的变动,所以之后也许可以结合页面相似度之类的算法再筛一遍,现阶段可以用批量替换的办法凑合。
CVE-2021-26855
Microsoft.Exchange.FrontEndHttpProxy
未有效校验Cookie中用户可控的X-BEResource
值,后续处理中结合.NET的UriBuilder
类特性造成SSRF。
漏洞分析
CVE-2021-26855 is a server-side request forgery (SSRF) vulnerability in Exchange which allowed the attacker to send arbitrary HTTP requests and authenticate as the Exchange server.
微软通告说这是一个以Exchange服务器作为身份认证的SSRF漏洞,说明肯定涉及到了NTLM/Kerberos认证,再结合Volexity捕获到的相关访问路径来看,定位到Microsoft.Exchange.FrontEndHttpProxy
相关的代码变动:
ProxyRequestHandler
类是CAS反代过程中,负责处理用户请求与后端响应的一个承前启后的组件。因为函数调用关系比较复杂,为了避免看上去一团乱麻,所以在具体分析某个方法作用前,先从广度上列出从收到用户请求开始几个主线的方法调用栈。
1 | // Microsoft.Exchange.FrontEndHttpProxy |
当请求路径为/ecp/
时,会通过IsResourceRequest
方法判断文件后缀名:
1 | // Microsoft.Exchange.FrontEndHttpProxy |
通过判断后由BeginProcessRequest
方法继续处理后续流程:
1 | public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) |
BackEndServer.FromString
方法获取Cookie的X-BEResource
值中,以~
波浪线分隔开的FQDN和version,而且涉及一处补丁变更:
这里的值可以由Cookie控制,调用FromString
的ResolveAnchorMailbox
方法也有补丁变更,基本可以说明漏洞点就在这附近了。果然随后的GetTargetBackEndServerUrl
方法就把Fqdn赋值给了UriBuilder对象Host属性:
1 | protected virtual UriBuilder GetClientUrlForProxy() |
UriBuilder是一个.NET类,在微软的Reference Source找到源码。如果传入的Host中存在:
冒号,并且不是[
开头,就用一对中括号将值包裹起来。:
1 | public string Host { |
根据传入的version是否大于Server.E15MinVersion(1941962752),将Port赋值为444或443。最后由Uri属性的get访问器(accessor)调用ToString将各部分拼接还原:
1 | public Uri Uri { |
得到后端URL之后继续处理请求头,将GenerateKerberosAuthHeader
方法生成的Kerberos票据放入Authorization请求头。CopyHeadersToServerRequest
方法会筛选出后端需要的请求头,其中ShouldCopyHeaderToServerRequest
方法用来过滤一些自定义请求头:
最后AddProtocolSpecificHeadersToServerRequest
方法会将序列化得到的用于标识用户身份的Token,放入X-CommonAccessToken
请求头中:
相应的,后端模块会由AllowsTokenSerializationBy
方法校验通常机器用户才有的ms-Exch-EPI-Token-Serialization
扩展权限(验证请求由CAS发出),随后反序列化还原X-CommonAccessToken
请求头的身份标识。
1 | // Microsoft.Exchange.Security.Authentication |
小结一下,Cookie的X-BEResource
值可以控制CAS请求的Host,结合UriBuilder类特性可以构造出可控的完整URL,因为采用Kerberos认证所以不能向任意站点发起请求:
X-FEServer
响应头的值就是计算机名,可以用它构造URL请求后端服务:
- Exchange2013需要将Version设置为大于1941962752的值
CVE-2021-27065
Microsoft.Exchange.Management.DDIService.WriteFileActivity
未校验写文件后缀,可由文件内容部分可控的相关功能写入WebShell。
利用流程
Microsoft.Exchange.Management.DDIService.WriteFileActivity
中有一处明显的补丁变动,使得文件后缀名只能为txt。
1 | private static readonly string textExtension = ".txt"; |
以ResetOABVirtualDirectory
触发点为例,利用流程如下(均通过SSRF发起):
- 请求EWS,从
X-CalculatedBETarget
响应头获取后端域名
- 爆破邮箱用户名,请求Autodiscover获取配置中的LegacyDN
- 由
MAPI over HTTP
请求引发Microsoft.Exchange.RpcClientAccess.Server.LoginPermException
,获取SID
- 替换尾部RID为500,伪造管理员SID,由ProxyLogonHandler获取管理员身份
ASP.NET_SessionId
与msExchEcpCanary
:
- 通过DDI组件Getlist接口获取RawIdentity(GetObject接口有时候返回NULL)
- 利用外部URL虚拟路径属性引入WebShell
- 最后触发重置时的备份功能,将文件写入指定的UNC目录
- WebShell的内容需要规避会被URL编码的特殊字符,且字符长度不能超过255
下一篇我们将一起讨论ProxyOracle~
参考链接
Web services reference for Exchange
HAFNIUM targeting Exchange Servers with 0-day exploits
Reproducing the Microsoft Exchange Proxylogon Exploit Chain