行业新闻

记一次反编译小程序寻找签名函数并联动bp插件自动化加签

记一次反编译小程序寻找签名函数并联动bp插件自动化加签

0x00 前言

日常渗透测试中,在进行数据包的重放或者是篡改数据包时,会碰到一些存在数据加密或加签的站点,这时我们就得寻找加签或者加密的算法,而这寻找过程往往有一定难度。

总的来讲,对于数据解密或者加签破解的难度:app>web≥wxapp,同时api接口都是相同的,为降低不必要的挖洞难度,可将目光放到微信小程序上。本次就是以一个微信小程序站点开展的测试。

0x01 拖取微信小程序包

这里简单说下,目前微信小程序在pc端貌似已经有加密了,Mac(/Users/{系统用户名}/Library/Containers/com.tencent.xinWeChat/Data/Library/Containers/com.tencent.xinWeChat/Data/Library/Caches/com.tencent.xinWeChat/{微信版本号}/{用户ID}/WeApp/LocalCache/release/{小程序ID}/)、Windows(C:\Users\{系统用户名}\Documents\WeChat Files\Applet\{小程序ID}\),而我们这边可以去拖安卓端的小程序包。

这里需要提前准备好一个已经root过的安卓手机或者是一个安卓模拟器,先去/data/data/com.tencent.mm/MicroMsg/{一串16进制字符}/appbrand/pkg 这个目录下将其他小程序包都删除掉,然后再打开微信加载我们需要测试的目标小程序。

此处注意,一定要等小程序完全打开并且再点几个功能,确保将所有包都运行,由于目前的小程序体量逐渐变大,可能会有多个子包的存在。


然后将相关子包拖出来。

0x02 反编译小程序拿源码

在将相关子包拖出来并放在我们指定的目录,然后用wxappUnpacker工具将包反编译出来。

node wuWxapkg.js ../20220323/debug_607957350_2_511127914.wxapkg

在原本存放小程序的目录下会出现一个以小程序包名的子文件夹,反编译出来的源码就在里面。

用微信官方开发工具打开源码项目:

1、选择“导入项目”,“AppID”选择测试号并导入

2、到“本地设置”模块,勾选上“不校验合法域名”功能



0x03 寻找签名加密函数

案例背景环境

介绍一下本次示例案例的背景环境。

在这⾥通过抓包发现站点有使⽤签名来鉴定提交数据的完整性, 经⼿⼯测试,发现修改任意带有值的参数,都会导致服务器端报错提示"签名错误”

这里简单介绍一种快速定位JavaScript中关键加密函数的方法--关键字寻找

关键字寻找

1.1、在项目中全局搜索关键字

常见的通用关键字例如keyencryptivsignpasswordrsaaes

1.2、搜索加签加密接口名

例如此处接口名为/xxxxxxing1/f**dinfo/getfundranklist/1.0,可以搜其拆分的路由名称:xxxxxxing1 f**dinfo getfundranklist

1.3、搜索相关涉及到加签加密的参数名

例如此处则可以搜索oftype openapi_sign paramsDigest ordercol

在介绍完背景和方法后,可以开始寻找加签函数了。

定位加签函数

在相关开发者工具中,全局搜索openapi

发现有两个js存在,进入这两个js继续定位关键的位置。

发现openapi关键字都存在于同一个关键函数(说明:这里后面经过对比两个js文件,发现内容大致相同而app-service.js不存在乱码情况,故后面都以此js进行跟踪分析)

openapi_sign参数存在于getSecretSign方法中,同时另外⼀个请求体里的参数paramsDigest也 在⾥⾯,这根据这个命名⼤概推测该⽅法可能是⽤于签名。

继续搜索此方法名getSecretSign,看看该方法是否有被调用到,发现了关键形参:t.data、 r.secretkey。

继续上下⽂搜索t.data,发现⼀个关键点,阅读相关js代码,发现⾥⾯的 json字符串就是从数据包参数 ⾥⾯获取的,然后调⽤Object.assign⽅法将json串复制到t.data当中。

由于r.secretkey未能搜索到,故尝试搜索secretkey关键字看看能不能找到些啥,发现刚好存在 ⼀个secretkey,至此可以⼤致判定我们最初找的getSecretSign为加签⽅法。

0x04 编写加签函数

本地起一个js脚本,将0x03中找到的加签函数写入,提供必要的参数值,运行测试下。


结果报错提示r对象未被定义,阅读代码发现,r对象只是用于提供它的hex()方法,返回项目源码当中寻找hex()方法。

然后往上面跟代码发现此处是引用了github上的一个MD5加密算法github。

这里直接将src目录下的md5代码复制下来,贴到我们测试的js文件当中。

执行js脚本文件,无报错。同时对⽐发现签名⼀致。⾄此相关加签函数已找到并能成功调⽤运⾏。

0x05 联动burp插件

加签算法已破解,为了能更提高实际渗透测试过程中的效率,可以联动burp插件,使得当我们篡改数据时能自动化的运行加签算法,直接得到相关签名。

在这里我首先尝试了burpCrypto插件,但调试js阶段发现一直有报错,同时在插件上未找到详细错误信息,而jsencrypter会将错误信息直接地抛出在命令行页面上,更有利于代码调试,故此处选择的是jsencrypter插件。

简单介绍一下jsencrypter插件:

jsencrypter使用phantomjs启动前端加密函数对数据进行加密,方便对加密数据输入点进行fuzz,比如可以使用于前端加密传输爆破等场景。工具本身提供了几种常见加密算法,可以直接引用,当加密加签算法为非常规时,也可以引用我们自定义算法进行破解。

phantomjs是已停产的无头浏览器,用于自动进行网页交互。PhantomJS提供了一个JavaScript API,可实现自动导航,屏幕截图,用户行为和断言,使其成为在无头系统(如持续集成环境)中运行基于浏览器的单元测试的常用工具。

Jsencrypter的使用

按照插件的说明,复制了一份原来的phantomJS调用模板,按照文档注释说明,修改了引用的js文件,以及后续调用的方法。

在⽤于加签的js中,将在0x04章节中成功加签的js代码复制过来,并在后面给其设置一个get方法,用于返回签名。

function get(pass){     var pass1 = eval("("+pass+")");     var call = test(pass1,t);     var str = 'paramsDigest:'+call.paramsDigest+'-------'+'openapi_sign:'+call.openapi_sign;     return str;     }

命令行中敲入命令,运行phantomjs

>phantomjs js1.js[*] load js successful[!] ^_^[*] jsEncrypterJS start![+] address: http://127.0.0.1:1664

然后bp上点击test发送数据,可以看到相关的sign值完全正确。(此处sign值与前面图对应)

自动化改进

原先js脚本,只是回显了sign,但实际过程中,我们还是需要cv⼤法将openapi_sign paramsDigest以及我们篡改后的数据串值重新丢⼊repeater中,其实可以通过js正则,进⾏修改输出,省去这⼀步。

首先定义一个unchange方法,用于将json串转成参数串。

function unchange(b){  var str = b,p1;  p1 = str.split(':"').join('=');  p1 = p1.split('",').join('&');  p1 = p1.replace('{','');  p1 = p1.replace('"}','');  return p1;}

然后连接符+缝合起来

     var str = unchange(pass)+'¶msDigest='+call.paramsDigest+'&openapi_sign='+call.openapi_sign;     return str;

看看实际效果

可以直接在插件上篡改参数值,然后复制结果到repeater中进行安全测试。

自动化改进2

但是这个地方,我们还是需要将数据先转化成非标准的json字符串。这里我尝试了在插件里面的js中进行修改,但是由于相关数据本身就包括了xxx&xxx1&xxx2,而&在HTTP请求中会当做一个分割参数符,这会导致参数传到server端中时,只剩下一个xxx参数,其余的都被丢弃了。

这里本想先将数据base编码,再传输过去,但思考下其实多此一举,在调用插件前还需要编码,加密前还需要先解码,这更复杂,还不如直接写个js,将数据转成json字符串后再丢给插件。

故使用曲线救国的方式,写了一个js,用于自动化生成json串。

function change(b){  var str = b,p1;  p1 = str.split('=').join(':"');  p1 = p1.split('&').join('",');  p1 = p1.replace(/^/,'{');  p1 = p1.replace(/$/,'"}');  return p1;}
var str = 'secuid=JY208740&udid=&sysVer=5.7.7&appName=&systemInfo=%2C%2C%2C&softName=WXIN_O&tradeClient=H5Trade&device_model=&deviceVers=&hwID=&conn_style=2.460.01.0.0&mip=&mac=&imsi=&iccid=&rNetAddr=&packtm=&reqtime=&operway=W&operorg=&netAddr=13888888888&session=12f4530351a3********7b6d8dec3c36f60dce1e83e03329d42fc269&userCode=334507******1792&pkg=H_117292&fundid=';  console.log(change(str));


至此,除了需要手动执行转化数据串为json串外,勉强实现了自动化修改数据(不是

0x06 涉及到的工具下载方式

以上工具可到原文中下载:https://zone.huoxian.cn/d/1052-bp

包含以下工具:

  • wxappUnpacker(模块已经安装好直接用)

  • wxappUnpacker(github版)

  • jsencrypter

第一次写文章,有什么不对的地方还请各位师傅斧正。

关闭