|
前言:说一下上一个某MINO永久会员版问题,后台很多人发信息说不可能破解成为永久vip。确实是不可能破解服务器验证的vip。但是可以换另一种思路分析。对于一个新出软件漏洞也是很多的。我们可以从这些漏洞进行入手。 MINO永久会员版实现了下面4个漏洞(软件无法使用)
漏洞1:请求和响应,无加密,有token无验证token,可以越界查库(广告奖励,邀请脚本) 漏洞2:获取管理员账号和密码(复现方法:通过修改libapp.so获取用户id位置,然后回软件,点击换头像,页面的名称和账号,就出现了管理员账号。修改libapp.so,修改验证密码位置,回软件,去修改密码,多点几次,然后去软件的data文件,查看密码) 漏洞3:解析视频,无验证(在发布MINO永久会员版帖子,2小时之后就修复了)
漏洞4:软件data里面的文件,只要不退出登录,软件就会一直获取data文件(软件重新打开也只是获取vip到期时间),只要在文件里面写好重要参数,就可以免登录 正文
声明:分析所用的脚本文件,都在帖子最后的链接里面
App :某MINO,某追忆等等同类型影视壳子
工具:Blutter,IDA Pro,Frida,HttpCanary
涉及加密方式:RSA-OAEP,AES-GCM,HMAC-SHA256
准备工作:
1. 用Blutter解包,flutter应用
2. 去除抓包检测: 搜vpn,复制匿名闭包的地址(0x4ba614),然后去IDA Pro或者其它汇编工具,
第一行修改为 MOV X0,#0 第二行修改为 RET
抓包分析: 这里看见api/sync/push,出现的次数比较多 oss-rg-china-mainland.aliyuncs.com:响应加密 /api/health:无加密,验证软件是否修改 api/captcha/rotate/init:验证码请求,有带头部,响应带一个64位的id加密 api/sync/preferences:带头部,请求数据("data": 密文)和响应加密("data": 密文) api/sync/push:带头部,请求数据("bundle":密文)和响应加密("bundle":密文) 整理验证,主要逆向点:
api/sync/preferences:可以重发多次,响应数据会变(不带头部也可以重发) api/sync/push:不可重发,响应数据出现401非法请求(必须带头部,验证有效token)
按照其它影视壳的手段,大概率是AES加密 分析流程:
so混淆,正常的手段无法用,所以只能用正则搜索偏移,写了一个find_string.py脚本,定位字符串位置 在pp.txt搜索AES,结果有14个,通过筛选发现可疑的
把偏移值填入find_string.py
在IDA PRO运行find_string.py,得到一直地址
AES字符串位置
用blutter_frida.js(修改过的),hook这个函数0x477A00
操作手机,无继续输出日志 查看0x477a00的引用,有三个函数,通过hook三个函数,其中0x98CE90线路加密数据,是oss-rg-china-mainland.aliyuncs.com响应解密的函数,不过无后续输出日志,再往上找 结果:Hook了一圈无任何有用信息
换思路:通过查找api/sync/push字符串地址 这里我手动补上字符串
通过确定hook最终sub_9B8A2C函数是正确位置
返回值有解密之后的数据,同时有输出libnative-crypto.so
调用libnative-crypto.so的函数进行解密
查看libnative-crypto.so
通过hook发现,关键函数有_h9m , _a7x , _d3k , _r2e , _g5b , _p6y 函数分析: _h9m(HMAC-SHA256): 参数:a1 :HMAC_key ,a2 :密文,a3 :数据长度 原理:aes密文拼接13位时间戳和_g5b返回的随机base64(16位),得到data,然后mbedtls_md_hmac计算HMAC(key, data),将 32 字节结果转换为 64 字符小写 hex(x-req-token的值) _a7x(AES-256-GCM加密): 参数:a1 :32 字节 aes密钥, a2 :明文,a3 :明文长度 原理:先Base64 解码 key_b64 得到 32 字节 AES key,再调用 mbedtls_ctr_drbg_random 生成 12 字节 IV,mbedtls_gcm_setkey(v21, MBEDTLS_CIPHER_ID_AES, key, 256) sub_39764 + sub_3992C 对结果做 Base64 编码后返回字符串 _d3k(AES-256-GCM解密): 参数:a1 :32 字节 aes密钥,a2 :密文,a3 :数据长度 原理:取密文hex前面12字节作为IV,取密文后16字节作为Tag
_r2e(RSA-OAEP 加密) 参数:公钥, 明文,长度 原理:调用_p6y函数获取公钥,mbedtls_pk_parse_public_key 解析 PEM 公钥,mbedtls_rsa_set_padding(rsa, 1, 9) ,1 =v21, 9 =MBEDTLS_MD_SHA256,即 RSA-OAEP-SHA256 _p6y(公钥获取位置) 原理:把字符串片段拼接成完整 PEM 公钥
拼接完整之后是
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAum4qpnurnzUExfnum4UY 3fmE2370KvssufETUZCfqf9o5953xAQ3sciU/FrOTQY29LrwbYgBizZUFVBNUgeJ 9hMkdywRUU3qnQlarz2D4FMDIJo3Z7x0G8CD4f47CpQ9c5LsiyWi4GTVEEMrkiDr KHn2/AtJ4sHdC/LsYiuv6tCNrY7Qoy0zrKFk0OcNL+8uNLZyCvEp7I8MoQlxWGmR siCXwQZUIdDjbPpZ92sNt+OH9THi2QcPlZxfoYPgNo5VfJAm4FUpGnr/R7k+2Sy7 JSYGCWcpd8fDCx5GIn/CmhblUQqlYD2+Au+S9SMpL+BTelGebss8/eK2nVHL7Uh5 xwIDAQAB -----END PUBLIC KEY-----
_g5b(随机数生成) 参数:int len(字节长度) 原理:mbedtls_ctr_drbg_random 生成指定长度随机字节,返回 Base64 编码字符串(主要生成aes密钥(32位)和x-req-trace的值(16位))。 hook脚本:hook_all.js
抓包和hook结合分析,得到下面,加解密流程图:
后续的aes的密钥都是从来api/sync/preferences响应数据解密得来的key和hmac的key。
分析验证:rsa_encrypt.py,aes_decrypt.py,hmac_encrypt.py的脚本在帖子最后的链接里面。
注意:
1.每次请求的body都带Authorization":"user_id+JWT+iat",这个jwt签名值,好像是随机生成的,但是有时效(Authorization的值可以用base64直接解密,第一次请求api/sync/preferences的头部带这个给服务器记录,iat是签名值到期时间戳)。
2.请求头部的content-length,这个长度是通过“aes加密数据+x-req-ts(时间戳)+x-req-trace(_g5b(随机数)”的总字节减24字节,得到的值。
总结:对比一代版本,作者也是下功夫了。不过加解密方式放在另一个so文件,脱离dart层,给逆向难度降低少了很多,希望作者继续改进一下。
帖子所用的脚本文件下载链接:
https://wwbkx.lanzoum.com/b02sgpn2xg
密码:bx3e
|