几周前我对某个手机银行应用进行测试。这个app用了一个框架,这个框架能够混淆、加密app与服务器进行的TLS连接。我用Frida截获了加密环节之前的明文请求/响应。我希望能够修改截获的API调用,然后看看远程服务器是如何响应的,但这样的话我每次都得修改Frida脚本。
Burp是用来进行web测试的工具,而对于移动应用的测试应该也大致相同。我想要让burp跟frida配合起来,截获/修改burp中的API调用。尽管我没做Burp的插件,但是用一个小脚本我们就可以截获API调用了,这省去了修改脚本中API参数的大量时间。
截获API请求并不麻烦:
1. 建立Burp监听端口(如26080端口)将流量转发到回显服务器(如27080端口)
2. 回显服务器在27080端口监听
3. 用Frida同步发送HTTP请求到Burp监听端口
Burp就会接收到Frida发送的API请求。我们就可以修改Burp中收到的调用,然后把数据转发到回显服务器。回显服务器会将修改请求后收到的响应发还给Frida。
设置Burp监听端口
我们先开始设置Burp的监听端口。我已经在隐匿代理模式中启用了26080作为监听端口:
我选择对已有的frida-trace代码进行修改和拓展,让其拥有trace工具那样的灵活性。
以下的这段Python代码能够让frida-trace代码与你转发API调用的服务器配合。它能够将HTTP请求发送到我们本地的Burp监听端口。你也可以在HTTP头部加入API调用的元数据,或者加入URL路径加以区分。
现在的代码可能依赖版本号,我不知道未来的版本会不会有变化,至少现在它能兼容Frida 8.2.2。
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()
下面的脚本可以用来截获onLeave 函数中的read()调用。你可以根据自己需求修改。我们只需要转发/截取你想要修改的那些参数。
我通过Frida的send() API实现了功能。这个调用被Python脚本接收,然后发送到handler脚本,然后当我们在BurpSuite中修改请求时,脚本会等待响应,然后执行回调函数。
{ 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(); } }
以下脚本实现的功能是对Frida发出的请求做出响应,会先request payload。你也可以根据自己的需求进行修改。
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()
以下为实际演示:
* 参考来源: cedricvb.be ,Freebuf小编vulture编译,文章有修改,转载请注明来自FreeBuf.COM