某金融app的加解密hook+rpc+绕过SSLPinning抓包

2023-11-22 11:30

本文主要是介绍某金融app的加解密hook+rpc+绕过SSLPinning抓包,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首发于土司论坛:

https://www.t00ls.com/thread-68689-1-1.html

0x01 抓包

1.1 burp抓包测试(抓不到)

1.2 httpcanary

HttpCanary可以抓到包,可以看到有请求包有加密。可以看到报文有显著的特征:params

0x02 代码分析

直接将app拖到Jadx-gui中,可以看到没有加壳:

然后搜索报文中的:“params”,然后定位到了加解密的地方,有报文的参数进行搜索,找加解密还是比较快的。

下面是加解密的核心代码:

小tips:jadx-gui中,可以在类或方法名称上右键——复制为frida片段,便可以自动生成frida hook代码了。

使用objection对加密和解密的方法进行验证:

android hooking watch class_methon [方法的完整路径] --dump-args --dump-backtrace --dump-return

通过hook的结果,可以判断该处代码就是报文的加解密代码。

0x03 编写hook+rpc代码

aaa.js

function main(){

Java.perform(function(){

console.log("正在注入")

var data = Java.use('com.xxxx.http.HttpEncrypt');

data.encryptParams.implementation = function(json,signdata){

console.log("===========================加密算法==========================");

send(json.toString());//因为是json类型数据,所以需要转换为string类型,否则转发不到burp

var tmp;

var op = recv('send',function (value) {

tmp = value.payload;

console.log("请求篡改后----->: ", tmp);

return tmp;

});

op.wait();

return this.encryptParams(tmp,signdata);

}

var shuju = Java.use('com.xxxx.http.HttpEncrypt');

data.decryptReponse.implementation = function(content,i){

console.log("==========================解密算法==============================");

var ret = this.decryptReponse(content,i);

send(ret);

var tmp;

var op = recv('send',function (value) {

tmp = value.payload;

console.log("请求篡改后----->: ", tmp);

return tmp;

});

op.wait();

return tmp;

}

});

}

setTimeout(main,5000);

启动handle_server.py

from http.server import HTTPServer, BaseHTTPRequestHandler​class RequestHandler(BaseHTTPRequestHandler):    def do_GET(self):        print('Recving request connction...')        request_headers = self.headers        content_length = request_headers.get('content-length')        length = int(content_length[0]) if content_length else 0        print(self.headers)        self.send_response(200)        self.end_headers()        self._send_cors_headers()        self.wfile.write(self.rfile.read(length))    def do_POST(self):        print('Recving request connction...')        req_datas = self.rfile.read(int(self.headers['content-length']))        # print(self.headers)        # print(req_datas)        self.send_response(200)        self._send_cors_headers()        self.end_headers()        self.wfile.write(req_datas)    def _send_cors_headers(self):        self.send_header('Content-type', 'application/json')        self.send_header("Access-Control-Allow-Origin", "*")        self.send_header("Access-Control-Allow-Methods", "*")        self.send_header("Access-Control-Allow-Headers", "Authorization, Content-Type")    def do_OPTIONS(self):        self.send_response(200)        self._send_cors_headers()        self.end_headers()def main(ECHO_PORT):    print('Listening on localhost: %d' % ECHO_PORT)    server = HTTPServer(('127.0.0.1', ECHO_PORT), RequestHandler)    server.serve_forever()if __name__ == '__main__':    main(8889)

burp监听127.0.0.1:8888端口

然后使用adb转发端口:

adb forward tcp:27042 tcp:27042

启动toBurp.py

启动前需要修改里面的一些内容:

'''python toBurp.py中转至burp,动态修改请求'''import osimport timeimport sysimport fridaimport requestsimport json​def on_message(message, data):    if isinstance(message, dict):         if message['type'] == 'send':            payload = message['payload']            if '{' in payload:                data = toburp(message["payload"].encode('utf-8'))                data = {'type': 'send', 'payload': data}                script.post(data)                #script.post({'type': 'send', 'payload': json.loads(data)})                       elif message['type'] == 'error':            print(message['stack'])    else:        if message.has_key("payload"):            print(message["payload"])​​#获取设备应用名def get_application_name(device, identifier):    for p in device.enumerate_applications():        if p.identifier == identifier:            return p.name​# 中转到burpdef toburp(data):    proxies = {'http':'http://127.0.0.1:8888'}    url = 'http://127.0.0.1:8889/Hook'    response=requests.post(url,data=data,proxies=proxies)    return(response.text)def main():    #连接设备    device = frida.get_remote_device()    #需要attach的apk包名    pid = device.spawn('com.xxxx.xxxx') #修改为包名    try:        #attach目标进程        session = device.attach(pid)        device.resume(pid)        #加载javaScript脚本        # 修改此处: aaa.js为hook脚本        script_content = open("aaa.js",encoding='utf-8').read()        global script        script = session.create_script(script_content)        script.on("message", on_message)        script.load()        sys.stdin.read()    except KeyboardInterrupt as e:        if session is not None:            session.detach()            device.kill(pid)        sys.exit(0)        if __name__ == "__main__":    main()

这是burp可以接收到参数,但是提交的时候会失败,就是提交到服务器,服务器并不认识。

通过下图可以看到,参数是被正常打印出来了,但是提示重载,后来我写了重载也是不行。

仔细分析了一波后得出结论:

加密代码没有其他参数类型的方法了,只有

public final String encryptParams(JSONObject json, String signData)这一个。

而我们在将JSONObject json发送到burp的时候,将JSONObject json类型转换为了String,导致调用encryptParams方法进行加密的时候,JSONObject json这个参数转换为了string类型的,所以匹配不到,故提示要重载。

所以我们还需要将String类型的数据转换为Json类型。

我自己尝试了几种方法,都不行:

第一种:

var ret = JSON.stringify(tmp);

第二种:

function strToJson(str){​var json = eval('(' + str + ')');​return json;​}

后来找了许多资料没有找到好办法,于是乎~~~~人工智能

在这里我就不得不表扬一下ai同学了:

最終修改后的js代码:

function main(){Java.perform(function(){console.log("正在注入")var data = Java.use('com.xxxx.http.HttpEncrypt');data.encryptParams.implementation = function(json,signdata){console.log("===========================加密算法==========================");send(json.toString());//因为是json类型数据,所以需要转换为string类型,否则转发不到burpvar tmp;var op = recv('send',function (value) {tmp = value.payload;console.log("请求篡改后----->: ", tmp);return tmp;               });op.wait();return this.encryptParams(tmp,signdata);}
​var shuju = Java.use('com.xxxx.HttpEncrypt');data.decryptReponse.implementation = function(content,i){console.log("==========================解密算法==============================");var ret = this.decryptReponse(content,i);send(ret);var tmp;var op = recv('send',function (value) {tmp = value.payload;console.log("请求篡改后----->: ", tmp);return tmp;});op.wait();return tmp;}});
}
setTimeout(main,5000);

修改好代码后,重新运行,burp也能够抓到包了。

通过测试发现,加解密的报文只是针对登录、点击功能按钮跳转时生成token等生效,经过测试,没发现什么漏洞,而内部页面其实还是h5,还是需要用传统的抓包方式进行测试。

0x04 app内部H5抓包

由于刚开始测试了burp是抓不到包的,而httpcanary使用起来又不方便,所以尝试使用charles。charles抓包的时候app显示无法连接到服务器,charles提示证书的问题,怀疑可能是SSLPinning,使用抓包工具抓包时,抓包工具拦截了服务端返回的内容并重新发给客户端的时候的证书不是服务器端原来的证书了,抓包工具将原本服务器的证书替换成自己的证书,于是就构成了中间人攻击,触发SSL Pinning导致连接中断,所以就抓不到包了。尝试使用objection的SSL Pinning disable进行绕过。

启动objection并注入app,输入命令:

android sslpinning disable

运行命令后,charles也成功抓到包了,而且没有加密,就很nice。

但是问题来了,charles改包、重放啥的不是很方便,所以联动一下burp。

0x05 charles联动burp

5.1 charles设置

Proxy-——External Proxy Settings

将Web Proxy和Secure Web Proxy均设置为127.0.0.1:8080

5.2 burp设置

5.3 成功转发

这样手机代理连接charles,charles转发到burp,就实现使用burp的抓包改包操作了。

这个app权限限制的很死,没找到越权类的漏洞,代码也很规范,最后只找到几个中低危的洞。放一个文件上传的洞吧:

通过修改MIME类型,可以突破文件上传。

转载请注明:Adminxe's Blog » 某金融app的加解密hook+rpc+绕过SSLPinning抓包

这篇关于某金融app的加解密hook+rpc+绕过SSLPinning抓包的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/409832

相关文章

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

关于rpc长连接与短连接的思考记录

《关于rpc长连接与短连接的思考记录》文章总结了RPC项目中长连接和短连接的处理方式,包括RPC和HTTP的长连接与短连接的区别、TCP的保活机制、客户端与服务器的连接模式及其利弊分析,文章强调了在实... 目录rpc项目中的长连接与短连接的思考什么是rpc项目中的长连接和短连接与tcp和http的长连接短

macOS怎么轻松更换App图标? Mac电脑图标更换指南

《macOS怎么轻松更换App图标?Mac电脑图标更换指南》想要给你的Mac电脑按照自己的喜好来更换App图标?其实非常简单,只需要两步就能搞定,下面我来详细讲解一下... 虽然 MACOS 的个性化定制选项已经「缩水」,不如早期版本那么丰富,www.chinasem.cn但我们仍然可以按照自己的喜好来更换

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

小技巧绕过Sina Visitor System(新浪访客系统)

0x00 前言 一直以来,爬虫与反爬虫技术都时刻进行着博弈,而新浪微博作为一个数据大户更是在反爬虫上不遗余力。常规手段如验证码、封IP等等相信很多人都见识过…… 当然确实有需要的话可以通过新浪开放平台提供的API进行数据采集,但是普通开发者的权限比较低,限制也比较多。所以如果只是做一些简单的功能还是爬虫比较方便~ 应该是今年的早些时候,新浪引入了一个Sina Visitor Syst

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD

网络故障排查和tcpdump抓包

网络故障排查: ping一台服务器不通,你如何排查 检查本机ip地址设置  网关和dns服务器是否设置正确 或者ip地址冲突能否上网 看路由器是否有问题 ping服务器是否运行服务器禁止ping   防火墙设置 iptables -A INPUT -P ICMP -j DROPiptables -D INPUT -P ICMP -j DROP用户不能访问服务器 怎么排查 检查用户网络连接检查服

ConstraintLayout布局里的一个属性app:layout_constraintDimensionRatio

ConstraintLayout 这是一个约束布局,可以尽可能的减少布局的嵌套。有一个属性特别好用,可以用来动态限制宽或者高app:layout_constraintDimensionRatio 关于app:layout_constraintDimensionRatio参数 app:layout_constraintDimensionRatio=“h,1:1” 表示高度height是动态变化

frida检测绕过-libmsaoaidsec.so

libmsaoaidsec.so 部分检测手段 检测机制在native层实现一般在init_proc()函数中触发使用 pthread_create 创建2个检测线程 绕过: nop pthread_create 的调用 eg: 在 bilibil1 - v7.26.1版本中, 在got表导入了pthread_create 绕过: 替换dlsym(xx, "pthread_create ")的返

App Store最低版本要求汇总

1,自此日期起: 2024 年 4 月 29 日 自 2024 年 4 月 29 日起,上传到 App Store Connect 的 App 必须是使用 Xcode 15 为 iOS 17、iPadOS 17、Apple tvOS 17 或 watchOS 10 构建的 App。将 iOS App 提交至 App Store - Apple Developer 2,最低XCode版本 Xcod