JS解密过程
为了不泄漏信息,文章中存在打码,修改参数等脱敏措施,但解密的方法未变,可供参考。
很多app传输会对报文进行加密,并存在防篡改的签名机制,导致不能修改参数进行渗透测试,对于我不熟悉app逆向的人来说逆向app的成本比较高,这里介绍一种比较便捷的解密方式,就是通过js来解密请求。前提是需要这个app存在h5页面,并且h5页面的加密算法和app本身的加密算法一致。
某app的h5页面显示的链接是 https://app.xxx.com/function/#/pages/queryDetails?id=644626 这种类型的,URl中参数在#
之后,这种样式的URL基本都是前后端分离的系统,也就是会通过JS会处理很多事务。
实际上在burp中抓包它的请求链接是 https://app.xxx.com/app/gateway/queryServices/011023?reqno=M4NofxiOtz4SvYpx 这样的。
测试过程中我的第一反应是尝试从js中将加解密方法找出来(虽然这个链接是app的,但是网页能访问,那它就一定是js加解密的,js加解密我个人认为比逆向app简单很多,而且也方便调试)。
但有一点需要注意,前后端分离的系统,会对js压缩和混淆,一方面是减轻js的体量,另一方面能在一定程度上防止他人通过js分析出关键代码。所以在被压缩混淆的js中调试也还是有一定难度的。
所幸网站的js很少,且大部分应用加密传输使用AES对报文进行加密,再使用RSA传输AES的密钥。
随便找找就发现AES加密的js代码,在代码中发现加密方式是CBC Pkcs7
密钥o:^BJSHGZ!@#ZZZDGJ
(密钥并不是这个,真实的密钥需要看变量n,数组arguments如果大于1,则使用arguments中的密钥,这个arguments具体是怎么来的我没搞懂,不过不重要,调试的时候我们能直接得到密钥的值,可以不用具体分析)
偏移量iv:0108489312380708
AES加解密的过程如下图,还是比较清晰的。
下图是调试过程,密钥就直接拿到了:
⚠️ 这里有个js混淆的坑,对于不咋熟悉js的我,1824行 u.default.encrypt
我还以为是另一种加密,在这里找这个是什么加密方法找了好久,结果它就是调用上图AES加密的方法,想太多了……
知道加解密方法,之后就可以尝试对参数进行修改了,同样是在调试过程,把参数取出,或者通过AES解密请求中的request body得到的请求参数,进行修改。
修改完成之后进行AES加密,我使用的是 https://gchq.github.io/CyberChef/ ,加密过程调成如下图:
request body的加密就到这了。response body解密使用的密钥,iv,模式,填充都一样,是逆过程就不多写了。
最后一个重点就是修改签名,修改完request body之后的签名肯定就变化了,就需要跟随请求来修改签名。
签名大概的算法如下图,不咋懂js的我刚看到这时是一脸的懵逼。
不过好在可以调试,通过调试可以看到算出Q所需要的参数,不过不用那么麻烦,直接看Q前一步就行了,Q = (0, g.default) (D).toString()
,也就是查看D是什么
通过调试可以知道,D是:(去除了\)
1 | 9924531585918379141792/queryServices/011023reqno=M4NofxiOtz4SvYpx{"head":{"client":"ABC","transactionno":"72789911122233","transactiontype":"lis","transactionexedate":"2020-04-03","transactionexetime":"01:26:29"},"body":"120001111"} |
D是由M+T+B+S+x组成的,我们修改的只是请求参数,请求参数在x中,也就是说我们修改其他参数我们都不用改。直接在调试过程中得到的D中修改请求参数,再对D进行hash就得到了sign。
⚠️ 确定签名算法中有一步就是因为hash方法弄错了导致浪费了很多时间,我在js代码中某处看到了sha1,我就以为hash方法是sha1,结果hash方法是md5…… Orz 怪不得我之前的加签都和结果对不上,还以为漏了算法中的某一步。
实操环节
访问网页,打开F12开发者工具,选择Debugger,点击index.js,在1522行和1835行下断点,
然后复制n和iv的值
其他配置可参考下图,mode是CBC,padding是pkcs7(如果你的AES加解密没有pkcs7,选pkcs5也是一样的)
点击继续,跳到下一个断点,这里可以复制E的值,E就是request body的值(记得得去掉\
)直接得到请求内容,然后修改它。再复制D(去掉\
),同样在请求参数中修改它。
修改完成之后,将E的值进行AES加密作为新的request body,D的值进行md5,就能得到signature的值。此时就能对报文参数修改测试了。