几周前我对某个手机银行应用进行测试。这个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