Cedric’s Cruft

  • Blog
  • Tools
Browse: Home > Tracing API calls in Burp with Frida

Tracing API calls in Burp with Frida

A few weeks ago I was performing a security test on a mobile banking application. The application was using a framework that provided additional obfuscation and encryption on top of the TLS connection it used to communicate with the remote server. I used Frida to intercept and dump the plaintext requests/responses before the encryption took place. I wanted to modify intercepted API calls and see how the remote server responded, but this required me to modify the Frida script each time.

Burp is really my tool of choice for (web) backend testing, and a mobile backend should not be that much different. I wanted to make Burp work together with Frida, and intercept/modify API calls in Burp. I did not go as far as creating a Burp plugin, but using a small script we can already get started with intercepting API calls. This spared me the trouble of modifying the frida-trace handler script each time I wanted to modify an API parameter.

Intercepting API requests with Burp does not require a lot of work:

  1. Set up a Burp listener (e.g. listen port 26080) redirecting traffic to an echo server (e.g. port 27080) in invisible proxy mode
  2. Have an echo server listening on port 27080 (which just echoes back the request)
  3. Use Frida to synchronously send an HTTP request to the Burp listener with as payload the API call data

Burp will receive the API request sent by Frida. The user can then modify the call in transit in Burp, which then forwards the data to the echo server. The echo server will simply reflect the (modified) request in the response, which is received back by the Frida code.

Set up Burp listener

Let’s start with setting up a Burp listener. Here, I’ve used listener port 26080 in invisible proxy mode:

Setting up a Burp listener redirecting to the echo server.

Python tracer code

I opted to extend (or rather monkey patch) the existing frida-trace code, in order to have the same flexibility of the tracing tool.

The following Python code extends the frida-trace code to work together with a server you forward the API call to. It does this by sending an HTTP request to the local Burp listener we created. You could also add metadata in the HTTP headers about the API call, or specify a URL path to distinguish between different API calls, which will be visible in Burp.

The current code might be version dependent: I don’t know what will change in future versions, though it currently works with Frida 8.2.2.

burp-tracer.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from frida import tracer
import requests
 
BURP_HOST = "localhost"
BURP_PORT = 26080
 
def frida_process_message(self, message, data, ui):
    handled = False
 
    if message['type'] == 'input':
        handled = True
    elif message['type'] == 'send':
        stanza = message['payload']
 
        if stanza['from'] == '/http':
            req = requests.request('FRIDA', 'http://%s:%d/' % (BURP_HOST, BURP_PORT), headers={'content-type':'text/plain'}, data=stanza['payload'])
            self._script.post({ 'type': 'input', 'payload': req.content })
            handled = True
 
    if not handled:
        self.__process_message(message, data, ui)
 
tracer.Tracer.__process_message = tracer.Tracer._process_message
tracer.Tracer._process_message = frida_process_message
 
if __name__ == '__main__':
    print("[x] To intercept in Burp, set up an invisible proxy listening on port %d, forwarding to the echo server." % BURP_PORT)
    tracer.main()

Trace handler script

The following example could be used to intercept read() calls in the onLeave function. This should be easily adaptable for your own usecase. We only need to forward/intercept the arguments that we want to tamper with.

I’ve implemented this by using the Frida send() API. This call is received by the Python code, which then responds back to the handler script. The script waits synchronously for a response (while we are performing modifications in Burp), and then executes the callback function.

__handlers__/libc_2.19.so/read.js
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
    onEnter: function (log, args, state) {
        log("read(" + "fd=" + args[0]+ ", buf=" + args[1]+ ", count=" + args[2] + ")");
        state.buf = args[1]
    },
 
    onLeave: function (log, retval, state) {
        send({from: '/http', payload: Memory.readUtf8String(state.buf)})
        var op = recv('input', function(value) { // callback function
            log("Forwarding mitm'ed content: " + value.payload)
            Memory.writeUtf8String(state.buf, value.payload)
        });
        op.wait();
    }
}

Echo server

The following script is a small implementation of an echo server that responds to “FRIDA” requests and echoes back the request payload. This could be extended as well with your own logic to modify requests on-the-fly (although you could just as well implement that directly in your Frida scripts).

echo.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from optparse import OptionParser
 
ECHO_PORT = 27080
 
class RequestHandler(BaseHTTPRequestHandler):
 
    def do_FRIDA(self):
        request_path = self.path
 
        request_headers = self.headers
        content_length = request_headers.getheaders('content-length')
        length = int(content_length[0]) if content_length else 0
 
        self.send_response(200)
        self.end_headers()
 
        self.wfile.write(self.rfile.read(length))
 
def main():
    print('Listening on localhost:%d' % ECHO_PORT)
    server = HTTPServer(('', ECHO_PORT), RequestHandler)
    server.serve_forever()
 
if __name__ == "__main__":
    print("[x] Starting echo server on port %d" % ECHO_PORT)
    main()

Demo

Here’s the code in action:

Frida tracing with Burp interception

SANS Holiday Hack Challenge 2015 writeup
Comments: 2
  1. Nino
    1057 days ago

    Hi

    For some reason, I cant modify my proxy and send my iOS requests via my Mac to internet. Can I apply the same on a mobile application (iOS)?

    As I understand, I dont need to setup proxy on my iPhone. Instead, Frida would intercept the request, send it to Burp.

    But I am not able to make it work. Where should i use the 'Trace handler script'?

    Thanks

    ------------
    Setup invisible proxy on Burp

    Run an echo server
    ```
    $ python echo.py
    ```

    ```
    $ python burp-tracer.py -U -m "-[NSURL *]"
    ```

    ReplyCancel
  2. h4niz
    500 days ago

    Thank you! It's very useful. But I use frida lastest version, there are any ways to do this without downgrade version?

    ReplyCancel
Pingbacks: 1
  1. ??Frida??Burp Suite??API?? - ????
    1462 days ago

Leave a Reply Cancel reply

cedric

Uncategorized

1469 days ago

51,080
Recent Posts
  • Tracing API calls in Burp with Frida
  • SANS Holiday Hack Challenge 2015 writeup
  • SECCON 2015 – Reverse engineering Android APK 2 – 400 writeup
  • WordPress < 4.1.2 Stored XSS vulnerability
  • Reverse engineering the HITB binary 100 CTF challenge
Recent Comments
  • Tech En bref : une faille critique découverte dans WordPress | KANO on WordPress < 4.1.2 Stored XSS vulnerability
  • New Security Flaw Allows Attackers to Hijack WordPress Sites – My WordPress Website on WordPress < 4.1.2 Stored XSS vulnerability
  • Millions at risk with Critical WordPress Zero-day Vulnerability on WordPress < 4.1.2 Stored XSS vulnerability
  • h4niz on Tracing API calls in Burp with Frida
  • Millions at risk with Critical Wordpress Zero-day Vulnerability | MageShield | Secure & simple magento maintenance on WordPress < 4.1.2 Stored XSS vulnerability
Archives
  • January 2017
  • January 2016
  • December 2015
  • April 2015
  • June 2014
  • December 2013
© 2013-2017 Cedric Van Bockhaven