本文最初发表于:
火区社区 ()
0x00 简介
在日常的渗透测试中,在重放或者篡改数据包的时候,会碰到一些对数据进行加密或者签名的站点,这时候我们就需要去寻找签名或者加密的算法,而这个寻找的过程往往是比较困难的。
一般情况下,数据解密或者签名破解难度为:app>web≥,且API接口相同。为了减少不必要挖坑的难度,可以重点关注微信小程序。本次测试在某微信小程序站点进行。
0x01 拖拽微信小程序包
这里简单解释一下,微信小程序好像在PC、Mac上都加密了(//{系统用户名}///com../Data///com../Data///com../{微信版本号}/{用户ID}////{小程序ID}/),(C:\\{系统用户名}\\ \\{小程序ID}\),安卓端我们可以拖拽小程序包进去。
这里需要提前准备一部已经root过的安卓手机或者一个安卓模拟器,先进入目录/data/data/com..mm//{一串十六进制字符}//pkg删除其他小程序包,然后打开微信加载我们需要测试的目标小程序。
请注意,必须等到小程序完全打开后再点击几个功能,以确保所有包都在运行。随着当前小程序的规模逐渐增大,可能会有多个子包。
然后拖出相关的子包。
0x02 反编译小程序获取源代码
把相关的子包拖出来放到我们指定的目录中,然后使用工具对包进行反编译。
node wuWxapkg.js ../20220323/debug_607957350_2_511127914.wxapkg
在小程序原来存放的目录中会出现一个与小程序包同名的子文件夹,反编译后的源代码就在里面。
使用微信官方开发工具打开源代码项目:
1.选择“导入项目”,选择测试编号并导入
2.进入“本地设置”模块,勾选“不验证合法域名”功能
0x03 查找签名加密函数
案件背景
我先介绍一下这个示例案例的背景环境。
通过抓包我们发现该站点使用签名来验证提交数据的完整性,经过人工测试发现修改任意一个有值的参数都会导致服务器报错“签名错误”
这里简单介绍一种快速定位关键加密函数的方法——关键字搜索
关键词搜索
1.1. 项目中全局搜索关键词
常见的通用关键字如key、iv、sign、rsa、aes等。
1.2. 搜索加密接口名称
例如此处的接口名称为//f**//1.0,可以搜索其拆分路由名称:**
1.3. 搜索签名加密相关的参数名称
例如,您可以在这里搜索
介绍完背景和方法之后,我们就可以开始寻找签名功能了。
定位签名功能
在相关的开发者工具中,全局搜索
发现有两个js文件,输入这两个js文件继续定位关键位置。
发现关键字均存在于同一个关键函数中(注:对比两个js文件后发现内容大致相同且app-.js中没有乱码,所以后面就用这个js进行跟踪分析)
该参数存在于方法中,而另一个请求体中的参数也在其中,根据这个命名可以粗略推断该方法可能是用于签名的。
继续搜索这个方法名,看这个方法是否被调用过,发现关键参数:t.data,r。
继续在上下文中搜索t.data,发现一个关键点,阅读相关js代码发现里面的json字符串是从数据包参数中获取的,然后调用.方法将json字符串复制到t.data中。
因为找不到r.,所以我们就试着搜索关键词,看看能不能找到什么。结果发现确实有关键词。所以大致可以确定,我们原本要找的是签名方法。
0x04 编写签名函数
本地启动一个js脚本,写入0x03中找到的签名函数,提供必要的参数值,运行测试。
结果提示错误信息:r对象未定义。阅读代码后,我发现r对象只是用来提供其hex()方法。我回到项目源代码中,找到了hex()方法。
然后我跟着代码走,发现这里引用了MD5加密算法。
这里我们直接把src目录下的md5码复制粘贴到我们测试的js文件中。
执行js脚本文件,没有报错。同时发现签名是一致的。至此,已经找到相关签名函数,并可以成功调用运行。
0x05 链接 burp 插件
签名算法已经被破解,为了提高实际渗透测试过程中的效率,可以联动burp插件,这样当我们篡改数据的时候,就可以自动运行签名算法,直接获取相关签名。
这里先尝试了插件,但是发现在调试js阶段总是出错,同时在插件上也没有找到详细的错误信息,而将错误信息直接抛在命令行页面,更利于代码调试,所以这里选择了插件。
插件简单介绍:
使用前端加密函数对数据进行加密,方便对加密数据输入点进行模糊测试,例如可用于前端加密传输爆破等场景。工具本身提供了几种常见的加密算法可以直接参考。当加密和签名算法非常规时,也可以参考我们自定义的算法进行破解。
是一款已停产的无头浏览器,用于自动执行网页交互。它提供了可实现自动导航、屏幕截图、用户行为和断言的 API,使其成为在无头系统(如持续集成环境)中运行基于浏览器的单元测试的流行工具。
使用
我根据插件说明,复制了原来的调用模板,并根据文档注释修改了引用的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 js1.js[*] load js successful[!] ^_^[*] jsEncrypterJS start![+] address: http://127.0.0.1:1664
然后点击bp上的测试,发送数据,可以看到相关的符号值完全正确。(这里的符号值和上图对应)
自动化改进
原来的js脚本只是回显了标志,但在实际过程中我们还需要cv方法把gest和修改后的数据字符串值扔回去,其实我们完全可以使用js正则表达式来修改输出,省去这个步骤。
首先定义一个方法,将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;
查看实际效果
可以直接在插件上篡改参数值然后复制结果进行安全测试。
自动化改进 2
但是我们还是需要将数据转换成非标准的json字符串,我尝试在插件的js中修改,但是相关数据本身包含xxx&xxx1&xxx2,而HTTP请求中又以&作为参数分隔符,这样会导致参数传到客户端时只剩下一个xxx参数,其余的都被丢弃了。
本来想先把数据库编码后再传输,但是想了想,其实没必要,需要在调用插件之前编码,在加密之前解码,这样比较复杂,还不如直接写个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 涉及工具的下载方法
以上工具原文可以下载:
包含以下工具:
这是我第一次写文章,如果有错误,还请大家指正。
【火线地带云安全社区群】
加入群与技术大牛交流
加入群组,有机会获得免费节日礼物