Burp Suite User Forum

Create new post

Design new extension - Problem with buildRequest and URL Encode

Antoni | Last updated: Mar 23, 2018 12:11PM UTC

Hi! I'm new to extending Burp and I wanted to add an active scanner plugin for some injections. When I making the requests with a payload with special characters, for example <script>alert(1)</script>, the request encoded my payload with "URL encode". My code is as follows: for(String payload: payloads){ IHttpRequestResponse test = this.callbacks.makeHttpRequest(httpService,insertionPoint.buildRequest(helpers.stringToBytes(payload))); } when I make "insertionPoint.buildRequest(helpers.stringToBytes(payload))" my payload is encoded in" URL encode", I think is because according to the documentation: https://portswigger.net/burp/extender/api/burp/IScannerInsertionPoint.html#buildRequest(byte[]) "Note: Scan checks should submit raw non-encoded payloads to insertion points, and the insertion point has responsibility for performing any data encoding that is necessary given the nature and location of the insertion point." How could I send the request without encoding anything? For example, if I send <script>alert(1)</script>, the request should be: GET / ... .... param=<script>alert(1)</script> and not: GET / ... .... param=%3cscript%3ealert(1)%3c%2fscript%3e Thanks a lot!

PortSwigger Agent | Last updated: Mar 23, 2018 12:12PM UTC

Hi Antoni, Thanks for your message. You're the second person this week who's asked for this, so I've written you a little snippet: - https://gist.github.com/pajswigger/c1fff3ce6e5637126ff92bf57fba54e1 This should get you going for now, and I'd be interested to hear how you get on. We'll have a discussion internally about making something like this part of the API. Please let us know if you need any further assistance.

PortSwigger Agent | Last updated: Mar 23, 2018 04:03PM UTC

Hi Antoni, Thanks for following up. I understand what you want to do and it seems sensible. If you try out the snippet I sent, you can replace: insertionPoint.buildRequest(helpers.stringToBytes(payload)) With: new BuildUnencodedRequest(helpers).buildUnencodedRequest(insertionPoint, helpers.stringToBytes(payload)) This is something we'd like to support in the core API. I've captured your requirement in a user story. We'll probably not act on this in the short term, but in future when we revise the extender API, we'll try to incorporate this. Do let me know how you get on with the snippet.

Burp User | Last updated: Mar 27, 2018 07:45AM UTC

Hi! I explain a little better my code and what I intend to: Override the doActiveScan function, calling another class: @Override public List<IScanIssue> doActiveScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint){ .... ActiveScan as = new ActiveScan(callbacks,data); return as.doAScan(baseRequestResponse, insertionPoint); .... } In the ActiveScan class, I define the doScan function and call insertionPoint.buildRequest: public List<IScanIssue> doAScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint){ ... for(String payload: payloads){ IHttpRequestResponse response = this.callbacks.makeHttpRequest(httpService,insertionPoint.buildRequest(helpers.stringToBytes(payload))); IScanIssue matches = getMatches(...); ... } The problem, for example to look for XSS, is that if you encode the payload in url encode, you can not try to skip filters, using different techniques. Because according to the documentation: https://portswigger.net/burp/extender/api/burp/IScannerInsertionPoint.html#buildRequest(byte[]) "Note: Scan checks should submit raw non-encoded payloads to insertion points, and the insertion point has responsibility for performing any data encoding that is necessary given the nature and location of the insertion point." The problem is that it is the insertionPoint.buildRequest function that decides whether to encode the payload or not. For example, in the referer field, it does not encode it: POST /a.php HTTP/1.1 Host: 127.0.0.1 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: <script>alert(1)</script> Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 164 gender=aaaa&class=aaa but in the class parameter, it does encode it: POST /a.php HTTP/1.1 Host: 127.0.0.1 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://127.0.0.1/a.php Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 53 gender=aaaa&class=%3cscript%3ealert(1)%3c%2fscript%3e Thanks a lot!

Burp User | Last updated: Apr 03, 2018 06:52AM UTC

Hi Paul, Finally it seems that with the code that you have passed me works for the case that I want. Thank you very much! On the other hand, is there any way to use the encoding methods here? https://portswigger.net/burp/help/intruder_payloads_processing The helpers.urlEncode (String) function does not work for me, I had to use URLEncoder.encode (String, "UTF-8"). Greetings.

PortSwigger Agent | Last updated: Apr 03, 2018 07:21AM UTC

Hi Antoni, Good to hear that is works for you. It's currently not possible to extensions to use Intruder payload encoding. An extension can provide encoding using the IIntruderPayloadProcessor interface, but it's not possible to use existing ones. And yes, helpers.urlEncode assumes the ISO-8859-1 charset, so if you need to use utf-8 you're better using Java encoding functions.

Burp User | Last updated: Apr 05, 2018 07:03AM UTC

Hi Paul, The function of BuildUnencodedRequest can fail when the payload that send has a small length, for example "aa", gives the following error: SEVERE: null java.lang.Exception: Multiple canary found in request Could it be solved by putting a canary of fixed length, for example 24 characters? Thank you, Regards!

PortSwigger Agent | Last updated: Apr 05, 2018 07:04AM UTC

Hi Antoni, That could work. The only issue is you may need to fix up the Content-Length header. Are you ok to have a go at this? Let me know if you want me to tweak the code.

Burp User | Last updated: Apr 05, 2018 08:18AM UTC

Hi Paul! It seems that this works fine without updating the Content-Length header: byte[] buildUnencodedRequest(IScannerInsertionPoint iScannerInsertionPoint) throws Exception { byte[] payload = helpers.stringToBytes("TestStringPayload"); byte[] canary = buildCanary(payload.length); byte[] request = iScannerInsertionPoint.buildRequest(canary); int canaryPos = findCanary(canary, request); System.arraycopy(payload, 0, request, canaryPos, payload.length); return request; } What do you think? Regards!

PortSwigger Agent | Last updated: Apr 05, 2018 08:21AM UTC

Hi Antoni, Yeah, that works because iScannerInsertionPoint.buildRequest updates the content length. But it the payload length doesn't match the canary length, it will set it to the wrong value.

Burp User | Last updated: Apr 05, 2018 09:38AM UTC

Hi Paul!, With more tests it seems that it does not work well, as it not only uses the length of the payload, but also the payload itself ... I do not see how it could work for payloads of length 1, 2 or 3 ... and in some cases with more than 3 could also fail ... Thank you, Regards!

PortSwigger Agent | Last updated: Apr 05, 2018 09:49AM UTC

Hi Antoni, I've updated the gist to use a slightly different technique. Rather than use a random canary, it uses this character § which is unlikely to be in a regular request. This may work a little better for you. Unfortunately, this is just a hacky workaround, so some problems should be expected. I think we will eventually update the API to support this, but that will take a little while.

Burp User | Last updated: Apr 05, 2018 02:11PM UTC

Hi Paul, We will have to use another character, with this it tells me: - incompatible types: possible loss and conversion from char to byte. I think it's because: - char is unsigned (has a range of 0 to 2 ^ 16 - 1), so -1 is not within its range. - byte, on the other hand, is signed, and has a range of -128 to 127. I will use the "$" character On the other hand, I will do: for (String grep: greps) {                     for (String payload: payloads) {                         if (payload.length ()> = 2) {                             IHttpRequestResponse response = this.callbacks.makeHttpRequest (httpService, new BuildUnencodeRequest (helpers) .buildUnencodedRequest (insertionPoint, helpers.stringToBytes (payload)));                             ...                         } else {                             IHttpRequestResponse response = this.callbacks.makeHttpRequest (httpService, insertionPoint.buildRequest (helpers.stringToBytes (payload)));                             ...                         }                     } Thank you so much for everything!! Greetings.

You must be an existing, logged-in customer to reply to a thread. Please email us for additional support.