Extending Burp with Python
description
Transcript of Extending Burp with Python
Extending Burp with Python
Defeating web application idiosyncrasies with common-sense, Python and minimal
knowledge of Java GUIs
What is Burp?
Purpose of this Talk
• Quick tour of Burp APIs with examples to show what can be achieved
• Demonstrate that Web app assessment hurdles overcome with minimal coding effort
Why would you need a custom extn?1. Decode custom encoding/serialization
2. Handle anti-tamper or signed requests
3. Provide a new “view” into an application
4. Automate a manual task with a new scanner check
Setup to run a Python Burp Extn.1 Download Jython standalone binary2 Tell Burp where find Jython3 Load a Python extension
Path to Jython binary goes here
The helloworld of Burp extensionsfrom burp import IBurpExtender
class BurpExtender(IBurpExtender):
# required
def registerExtenderCallbacks(self, callbacks):
# set our extension name
callbacks.setExtensionName("Hello world extension")
# write a message to the Burp alerts tab
callbacks.issueAlert("Hello alerts")
Just writes “Hello alerts” out to alerts tab
1. Problem: Unsupported encoding Application uses an encoding not understood by Burp
Examples:Serialised Java, SAP’s weird URLenc variant, SAML, Websphere Portlet
Burp APIs: IMessageEditorTab to display decoded content
Solution: new encoder/decoder 1. Tell Burp about your new message editor
tab
class CustomDecoderTab(IMessageEditorTab):
def __init__(self, extender, controller, editable):
...
def getTabCaption(self):
return "Custom Decoder"
Solution: new decoder/encoder2. Use setMessage to display decode
def setMessage(self, content, isRequest):
...
if '!ut' in path:
# actual decoding magic omitted
content = response.read()
content = xml.dom.minidom.parseString(content).toprettyxml()
if content:
self._txtInput.setText(content)
self._currentMessage = content
Websphere portlet state decoder
Source: https://github.com/faffi/WebSphere-Portlet-State-Decoder
Encoded content on URL
Gets decoded in new tab
2. Problem: Signed requestsApplication requires signature thats generated client side.
examples
1. Seen in thick client apps as anti-tamper mechanism
2. AWS API calls are signed for authentication
http://rajasaur.blogspot.co.nz/2009/10/hmac-sha-signatures-using-python-for.html
Burp API: processHTTPMessage allows us to re-write traffic
Solution: automate request signing
1. Catch an outbound request
from burp import IBurpExtender# this function catches requests and
responses
def processHttpMessage(self, toolFlag, messageIsRequest,
currentRequest):
# only process requests
if not messageIsRequest:
return
...
Solution: automate request signing 2. Grab the request body and headers
# requestInfo object allows us to easily spit body and headers
requestInfo = self._helpers.analyzeRequest(currentRequest)
bodyBytes = currentRequest.getRequest()[requestInfo.getBodyOffset():]
bodyStr = self._helpers.bytesToString(bodyBytes)
headers = requestInfo.getHeaders()
newHeaders = list(headers) #it's a Java arraylist; get a python list
Solution: automate request signing3. Append signature as HTTP Header
# Do custom signing shenanigans
secret = "SuperSecret123"
h = hmac.new(secret, bodyStr, hashlib.sha256)
newHeaders.append("Authorization: " + base64.b64encode(h.digest()))
Solution: automate request signing4. Create and send request newMessage = self._helpers.buildHttpMessage(newHeaders, bodyStr)
currentRequest.setRequest(newMessage)
Here’s the new Authorization header being sent out
3. Problem: Big apps, lotsa headersLarge applications may emit different headers from various locations within the app.
Headers can reveal useful info. Eg. Reverse proxy may hand off from backend A to backend B.
Burp APIs: processHTTPMessage and ITab to display result
Solution: View of unique headersKeep track of unique headers, filter out uninteresting headers.
# insert an entry if the header is 'interesting’
if header_name.lower() not in boring_headers:
# and we haven't seen this name/value pair before, log it
if header not in self.headers_seen:
self.headers_seen.append(header)
self._log.add(LogEntry(header, …, … )
Solution: View of unique headersCreate a new tab and display collected headers in the new tab.
# Give the new tab a name
def getTabCaption(self):
return "Response Headers”
# This adds all the Java UI unpleasantness
def getUiComponent(self):
return self._splitpane
Solution: View of unique headers
List of unique headersdisplayed in new “Response Headers” tab
Clicking item in list showsrequest/response
4. Problem: Automate a manual taskLocate and decode F5 cookies, display as a passive scan result
Burp API: doPassiveScan to trigger check code
Solution: create new check
1. doPassiveScan catches requestdef doPassiveScan(self, baseRequestResponse):
# Returns IResponseInfo
analyzedResponse =
self.helpers.analyzeResponse(baseRequestResponse.getResponse())
analyzedRequest = self.helpers.analyzeRequest(baseRequestResponse)
# Get Cookies from IResponseInfo Instance cookieList =
analyzedResponse.getCookies()
Solution: create new check2. Locate BIGIP cookies and decode them# Loop though list of cookies
for cookie in cookieList:
cookieName = cookie.getName()
# Look for BIGIP Cookies
if cookieName.lower().startswith("bigip"):
f5CookieName = cookieName
f5RawCookieValue = cookie.getValue()
# Decode and check for RFC 1918 address
f5info = decode(f5RawCookieValue)
Solution: create new check3. Create Issue class to return useful info
class PassiveScanIssue(IScanIssue):
...
def getIssueName(self):
return "Encoded IP Address Discovered in F5 Cookie Value"
...
def getIssueDetail(self):
msg = "The URL <b>" + str(self.findingurl) + "</b> sets the F5 load
balancer cookie <b>"
F5-BigIP Cookie Checker
Source: http://blog.secureideas.com/2013/08/burp-extension-for-f5-cookie-detection.html
Internal IP address retrieved from encoded cookie
Summary1. Decode custom encoding/serialization
Use IMessageEditorTab interface to display decoded content
2. Handle anti-tamper or signed requests Use processHTTPMessage to catch and rewrite requests
3. Provide a new “view” into an application
Use ITab interface to display custom view
4. Automate a manual task with a new scanner check
Use doPassiveScan to trigger a check