通过JS解开加密传输

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 这样的。

encrypt-request-data

测试过程中我的第一反应是尝试从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-encrypt-code

下图是调试过程,密钥就直接拿到了:

get-aes-key

⚠️ 这里有个js混淆的坑,对于不咋熟悉js的我,1824行 u.default.encrypt我还以为是另一种加密,在这里找这个是什么加密方法找了好久,结果它就是调用上图AES加密的方法,想太多了……

aes-default-encrypt

知道加解密方法,之后就可以尝试对参数进行修改了,同样是在调试过程,把参数取出,或者通过AES解密请求中的request body得到的请求参数,进行修改。

unencrypt-request-body

修改完成之后进行AES加密,我使用的是 https://gchq.github.io/CyberChef/ ,加密过程调成如下图:

cyberchef-aes-encrypt

request body的加密就到这了。response body解密使用的密钥,iv,模式,填充都一样,是逆过程就不多写了。

最后一个重点就是修改签名,修改完request body之后的签名肯定就变化了,就需要跟随请求来修改签名。

签名大概的算法如下图,不咋懂js的我刚看到这时是一脸的懵逼。

js-add-sign

不过好在可以调试,通过调试可以看到算出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 怪不得我之前的加签都和结果对不上,还以为漏了算法中的某一步。

debug-sign

实操环节

访问网页,打开F12开发者工具,选择Debugger,点击index.js,在1522行和1835行下断点,

然后复制n和iv的值

debug-aes-key

其他配置可参考下图,mode是CBC,padding是pkcs7(如果你的AES加解密没有pkcs7,选pkcs5也是一样的)

cyberchef-set-aes-encrypt

点击继续,跳到下一个断点,这里可以复制E的值,E就是request body的值(记得得去掉\)直接得到请求内容,然后修改它。再复制D(去掉\),同样在请求参数中修改它。

debug-sign-2

修改完成之后,将E的值进行AES加密作为新的request body,D的值进行md5,就能得到signature的值。此时就能对报文参数修改测试了。

burp-request