宇宙免责声明!!!
本推文提供的信息、技术和方法仅用于教育目的。文中讨论的所有案例和技术均旨在帮助读者更好地理解相关安全问题,并采取适当的防护措施来保护自身系统免受攻击。
严禁将本文中的任何信息用于非法目的或对任何未经许可的系统进行测试。未经授权尝试访问计算机系统或数据是违法行为,可能会导致法律后果。
作者不对因阅读本文后采取的任何行动所造成的任何形式的损害负责,包括但不限于直接、间接、特殊、附带或后果性的损害。用户应自行承担使用这些信息的风险。
我们鼓励所有读者遵守法律法规,负责任地使用技术知识,共同维护网络空间的安全与和谐。
起因
-
开局学员发来求助
-
打开注册,发现所有请求和回显都是加密过的
逆向小程序包
把小程序脱下来,丢编辑器开始逆向
-
拿到包以后丢到编辑器
开始逆向
第一个坑
-
刚开始拿到源码,开始找加密,定位到此处,以为就这么简单拿下了
-
拿去解密发现解不开。大概路不是此处,继续往下找
第二个坑
-
全局字节搜索key和iv,找到iv
-
打开此js,成功找到加密方式和固定key
-
但是此处的key,是通过手动传入
-
继续深入,找从哪里调用的此加密方法
-
来到request.js,getOpenIdUnionIdTokenFromServer方法,发现key是从
-
然后继续跟踪encryptKey,来到getAesKeyUrl方法
-
大概意思就是从getAeskeyUrl这个api去get请求拿到aeskey,跟进,来到api.js,拿到路由。(其实这里在最开始进入小程序的时候,意见请求过一次,但是在bp抓包历史里是没有的,这也是坑点3)
-
拼接请求访问,拿到key,为了确保不是动态key,刷新了几次发现没有变化。坑点三也随之而来。(记住这里的时间戳和version很重要,后文解释为什么)
坑点三
-
拿到这个key和iv的时候其实有点疑惑,怎么还有一个iv?但是没多想,拿着key和iv去解密。发现还是tm的解不开!!!!
-
这里可能有小伙伴想到了,最开始那个iv。对,最开始有一个固定的iv,那这个iv就是用来迷惑的我们这种脚本小子的。
-
然后拿着最开始的那个iv继续去解包,怎么tm的还是解不开!!!!
那么问题出在哪里呢?
坑点四
继续回过头看js,继续走一遍流程,重新看到从服务器获取aeskey处
-
捏妈,获取到aeskey后,对key进行了反转,看漏掉了,ok那么反转一下key即将拿下
-
到底是哪里不对???
坑点五
反复查看源码,发现,解密出用了hex,那么流程就是
十六进制(Hex)密文 → Base64字符串 → AES 解密 → Utf8原文
-
所以要解密出解密为十六进制,继续解密,为什么????
坑点六
-
还是解不开,那么肯定是哪里有问题。
-
继续看代码,搜索关键字,来到此处
-
继续跟进getAesKey方法,又回到request.js
-
最后来到模块方法getAesKey,继续跟进
-
阅读此方法代码,发现,此代码逻辑为
-
那么逻辑就通了,这么说的话就是aeskey过期掉了,重新回到上面获取aeskey处,发现果然有时间戳跟,版本号
-
发现早已过期,此处获取到的是js毫秒级的时间戳,正常转换要删除掉后面三位
-
重新请求发现key果然变化了,大概是半小时过期一次,这就解释的通为什么一开始我反复请求没有变化,因为还在时间内。但是后面我在调试的时候时间到了,key变化了,但是我依旧拿的是新的加密密文(图方便直接从最新的bp历史数据包复制的)去用旧的key解密,所以解不开。
-
重新请求key后,解密,拿下,可以开始愉快测试了。可惜的是此处不通过加密传参数鉴权,而是通过其他鉴权字段,所以没有越权,但是可以常规测试,sql注入等等。文末附小程序认证流程。
总结下坑点
iv硬编码迷惑->aeskey反转加密->hex进制解密->动态aeskey
附带一下小程序认证流程
文字版
小程序调用wx.login获取临时code;
小程序发送code到服务器;
服务器用code调用微信接口换取用户唯一标识openid;
服务器根据openid创建JWT Token返回给小程序;
小程序存储JWT Token,每次请求服务端时,在header中携带JWT Token;
服务器验证JWT签名及有效期,并从JWT中提取openid;
服务端利用openid从数据库查询出用户对应的个人信息并返回给客户端。
原文始发于微信公众号(Zer0 sec):一次绕来绕去的小程序逆向(含思考过程)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论