0x01 序言
前端的加解密一直是很多师傅经常遇到过的问题,一个加解密传输,签名,防篡改,导致很多时候没有办法对参数的值进行更改,代码中存在的web漏洞也没办法测试出来,当然这也是一种符合所有场景的防御办法,增加攻击成本,是一个很棒的防御方案。
有的师傅测试遇到时无非会有几种想法:
-
这个还需要研究js,emm,不太会,以后再学习(然后鸽鸽鸽
-
这个研究一段时间应该也能尝试一下,以前貌似看到过这种文章,照着文章研究一天应该也可以试试,但是好浪费时间,最后也不一定弄好,弄好也不一定有洞,下次有机会在测吧(然后鸽鸽鸽
-
好麻烦,还要把用到的js弄下来本地运行,有的是打包的js还不能用,有的还要修改里面的js代码,为什么要这么麻烦,这次测试差不多就得了,摸鱼才是真理(然后摸摸摸
ps: 有的师傅确实时间紧任务重,可以理解,毕竟如果是半吊子去安排任务大部分都会觉得时间给的很充足~
0x02 JSRPC理解
对于我们来说,jsrpc就是将本地和浏览器,看做是服务端和客户端,二者之间通过 WebSocket 协议进行 RPC 通信,在浏览器中将加密函数暴露出来,在本地直接调用浏览器中对应的加密函数,从而得到加密结果,不必去在意函数具体的执行逻辑,也省去了扣代码、补环境等操作,可以省去大量的逆向调试时间。
0x03 一次完整的某银行网站利用jsrpc解决js加密传输的笔记
1.下载jsrpc,同样用jsrpc技术的项目还有sekiro,我的目标为https站点,注释掉main.go的197行和198行,解除194行的注释,进行编译生成运行
2.打开网站f12的控制台,打开工具里面的jsenv.js,内容全部复制,复制到控制台直接运行,这样这个代码就注入了
3.控制台继续添加js代码,作用是使用js的websocket协议连接上面工具运行开放的12080端口,group和name的值随意,后面使用链接的时候值一样就行,可以当做一句话木马的密码逻辑理解
4.发现网站会每次生成sign放入header中,修改参数及值会导致访问网站失败,所以每次改值就需要生成对应的签名
5.根据sign关键字去js代码中寻找加密点
6.给这个函数末尾添加断点,网站正常运行,发现目标网站存在js反调试,如果网站没有反调试的这步忽略即可,这里利用burp的匹配并替换的功能替换网站2处反调试的js代码,具体原理不多说了,这个不是今天主角
7.网站正常调试,运行至断点处,此时回到控制台,对js中的函数和值进行输出,验证是否满足加密要求,console.log(r),u("aaaa"),发现r变量确实是sign的值,u函数确实是加密函数,根据传入的值生成加密结果存入r
8.断点,yyds,此时控制台能正常调用加密函数了,需要把u函数改为全局函数,意思就是以后不需要断点也能够调用这个函数的意思,使用代码window.test = u,控制台输入即可,关闭调试功能,发现控制台直接调用test函数,就相等于调用u函数了
9.继续控制台注入js代码,hacker2就是action参数的值,看了远程调用的url就明白了,http://127.0.0.1:12080/go?group=zzz&name=hlg&action=hacker2¶m=xxxxxxxxxx
demo.regAction("hacker2", function (resolve,param) {
console.log(param);
var base666 = test(param); //test就是上面那个加密函数
resolve(base666);
})
比如想对字符串sven加密,这样就可以直接远程调用浏览器的加密函数了,加密api +1,之后随意你怎么使用都可以了,各显神通,任意发挥即可,或许等autoDecode这个bp插件以后功能更全面了,没准直接能对接上
10.我这里是用mitmdump弄了个py中转,burp的包转到这个代理上,对请求进行一个加工后转发。自动获得我需要的参数和值当做字符串,然后请求调用控制台的api获得加密后的sign值,替换到burp发来的请求包里,再将请求发出去,这样什么工具只要通过burp发送请求,就都会是签名正确的请求了
#encrypt.js
import requests
import json
from urllib.parse import unquote
from urllib.parse import quote
def request(flow):
print('request url is %s' % flow.request.url)
/*
随意对flow的值进行修改即可,同时要注意url编码问题
sign = json.loads(requests.get("http://127.0.0.1:12080/go?group=zzz&name=hlg&action=hacker2¶m={}".format("想要加密的字符串")).text)
flow.request.headers['Sign'] = sign['data']
*/
0x04 总结
1.无需太高的js代码水平
2.步骤大多都是机械可重复步骤
3.无论js什么格式,都不影响操作
4.当然也会有一些知识会影响使用理解,比如浏览器调试水平,阅读理解水平,burp使用水平,漏洞逻辑理解水平
5.内卷驱动器