0


【JSrpc破解前端加密问题】

一、背景

解决日常渗透测试、红蓝对抗中的前端密码加密问题,让你的爆破更加丝滑;降低js逆向加密的难度,降低前端加密逻辑分析工作量和难度。

二、项目介绍

运行服务器程序和js脚本 即可让它们通信,实现调用接口执行js获取想要的值;

实现原理:在网站的控制台新建一个WebScoket客户端链接到服务器通信,调用服务器的接口 服务器会发送信息给客户端 客户端接收到要执行的方法执行完js代码后把获得想要的内容发回给服务器 服务器接收到后再显示出来。具体项目地址和食用细节参考:https://github.com/jxhczhl/JsRpc

三、JSrpc 处理前端加密步骤

第一步 构建RPC通信环境

浏览器中访问目标网站,注入rpc服务端代码到浏览器中:

服务端代码如下:

  1. function Hlclient(wsURL) {
  2. this.wsURL = wsURL;
  3. this.handlers = {
  4. _execjs: function (resolve, param) {
  5. var res = eval(param)
  6. if (!res) {
  7. resolve("没有返回值")
  8. } else {
  9. resolve(res)
  10. }
  11. }
  12. };
  13. this.socket = undefined;
  14. if (!wsURL) {
  15. throw new Error('wsURL can not be empty!!')
  16. }
  17. this.connect()
  18. }
  19. Hlclient.prototype.connect = function () {
  20. console.log('begin of connect to wsURL: ' + this.wsURL);
  21. var _this = this;
  22. try {
  23. this.socket = new WebSocket(this.wsURL);
  24. this.socket.onmessage = function (e) {
  25. _this.handlerRequest(e.data)
  26. }
  27. } catch (e) {
  28. console.log("connection failed,reconnect after 10s");
  29. setTimeout(function () {
  30. _this.connect()
  31. }, 10000)
  32. }
  33. this.socket.onclose = function () {
  34. console.log('rpc已关闭');
  35. setTimeout(function () {
  36. _this.connect()
  37. }, 10000)
  38. }
  39. this.socket.addEventListener('open', (event) => {
  40. console.log("rpc连接成功");
  41. });
  42. this.socket.addEventListener('error', (event) => {
  43. console.error('rpc连接出错,请检查是否打开服务端:', event.error);
  44. });
  45. };
  46. Hlclient.prototype.send = function (msg) {
  47. this.socket.send(msg)
  48. }
  49. Hlclient.prototype.regAction = function (func_name, func) {
  50. if (typeof func_name !== 'string') {
  51. throw new Error("an func_name must be string");
  52. }
  53. if (typeof func !== 'function') {
  54. throw new Error("must be function");
  55. }
  56. console.log("register func_name: " + func_name);
  57. this.handlers[func_name] = func;
  58. return true
  59. }
  60. //收到消息后这里处理,
  61. Hlclient.prototype.handlerRequest = function (requestJson) {
  62. var _this = this;
  63. try {
  64. var result = JSON.parse(requestJson)
  65. } catch (error) {
  66. console.log("catch error", requestJson);
  67. result = transjson(requestJson)
  68. }
  69. //console.log(result)
  70. if (!result['action']) {
  71. this.sendResult('', 'need request param {action}');
  72. return
  73. }
  74. var action = result["action"]
  75. var theHandler = this.handlers[action];
  76. if (!theHandler) {
  77. this.sendResult(action, 'action not found');
  78. return
  79. }
  80. try {
  81. if (!result["param"]) {
  82. theHandler(function (response) {
  83. _this.sendResult(action, response);
  84. })
  85. return
  86. }
  87. var param = result["param"]
  88. try {
  89. param = JSON.parse(param)
  90. } catch (e) {}
  91. theHandler(function (response) {
  92. _this.sendResult(action, response);
  93. }, param)
  94. } catch (e) {
  95. console.log("error: " + e);
  96. _this.sendResult(action, e);
  97. }
  98. }
  99. Hlclient.prototype.sendResult = function (action, e) {
  100. if (typeof e === 'object' && e !== null) {
  101. try {
  102. e = JSON.stringify(e)
  103. } catch (v) {
  104. console.log(v)//不是json无需操作
  105. }
  106. }
  107. this.send(action + atob("aGxeX14") + e);
  108. }
  109. function transjson(formdata) {
  110. var regex = /"action":(?<actionName>.*?),/g
  111. var actionName = regex.exec(formdata).groups.actionName
  112. stringfystring = formdata.match(/{..data..:.*..\w+..:\s...*?..}/g).pop()
  113. stringfystring = stringfystring.replace(/\\"/g, '"')
  114. paramstring = JSON.parse(stringfystring)
  115. tens = `{"action":` + actionName + `,"param":{}}`
  116. tjson = JSON.parse(tens)
  117. tjson.param = paramstring
  118. return tjson
  119. }

如下注入至浏览器中,并连接通信环境

  1. // 注入环境后连接通信
  2. var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz");
  3. // 可选
  4. //var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz&clientId=hliang/"+new Date().getTime())

启动我们的中间监听器,可以看到有上线:

接口调用说明:

  • /list :查看当前连接的ws服务 (get)
  • /ws :浏览器注入ws连接的接口 (ws | wss)
  • /wst :ws测试使用-发啥回啥 (ws | wss)
  • /go :获取数据的接口 (get | post)
  • /execjs :传递jscode给浏览器执行 (get | post)
  • /page/cookie :直接获取当前页面的cookie (get)
  • /page/html :获取当前页面的html (get)

尝试调用浏览器ws接口并传入js代码

  1. import requests
  2. js_code = """
  3. (function(){
  4. console.log("test")
  5. return "执行成功"
  6. })()
  7. """
  8. url = "http://localhost:12080/execjs"
  9. data = {
  10. "group": "zzz",
  11. "code": js_code
  12. }
  13. res = requests.post(url, data=data)
  14. print(res.text)

如下就证明成功实现了rpc通信和接口调用:

第二步处理加密

加密函数寻找:

定位加密函数,抓包分析,加密登录接口位于/api/sys_yonghua/login_web,全局搜索接口login_web

断点分析后,hook插桩函数和方法为:

  1. const processedParam = v()(param);
  2. const encryptedValue = n["default"].prototype.$AesDesHelper.AesOrDes_Encrypt(processedParam);

v()进行md5加密,模块n["default"].prototype.$AesDesHelper中的AesOrDes_Encrypt(l)方法对md5后的值进行加密,加密方法知道之后,接下来就是注册函数方法了。

注册函数方法:

1、浏览器控制台注册无参数方法

  1. // 注册一个方法 第一个参数hello为方法名,
  2. // 第二个参数为函数,resolve里面的值是想要的值(发送到服务器的)
  3. demo.regAction("hello", function (resolve) {
  4. //这样每次调用就会返回“yesyesyesyes+随机整数”
  5. var Js_sjz = "好困啊"+parseInt(Math.random()*1000);
  6. resolve(Js_sjz);
  7. })

无参接口调用:

2、浏览器控制台注册带参数方法

  1. demo.regAction("md5", function (resolve, param) {
  2. // 确保 v() 可以访问并返回一个处理后的值
  3. const processedParam = v()(param);
  4. const encryptedValue = n["default"].prototype.$AesDesHelper.AesOrDes_Encrypt(processedParam);
  5. resolve(encryptedValue);
  6. });

带参param接口调用,即可实现本地浏览器前端加密:

第三步python脚本批量处理

导入密码字典:

python脚本调用接口进行批量处理加密:

  1. import requests
  2. import threading
  3. path = "http://127.0.0.1:12080/go?group=zzz&action=md5&param="
  4. encrypt_list = []
  5. def GetEncrypt(password):
  6. url = path+'"'+password+'"'
  7. response = requests.get(url=url)
  8. if response.status_code == 200:
  9. encrypt_list.append(response.json()["data"])
  10. print(response.json()["data"])
  11. else:
  12. return {"status": response.status_code, "error": "Request failed"}
  13. def MultProcess():
  14. threads = []
  15. with open("password.txt",'r') as file:
  16. for password in file:
  17. thread = threading.Thread(target=GetEncrypt,args=(password,))
  18. threads.append(thread)
  19. thread.start()
  20. for i in threads:
  21. i.join()
  22. if __name__ == '__main__':
  23. print("开始加密处理")
  24. MultProcess()
  25. with open("after_encrypt.txt",'w') as file:
  26. for i in encrypt_list:
  27. file.write(i.strip()+"\n")
  28. print("加密处理结束")

加密后的字典:

最后配合burpsuite实现爆破:

标签: 前端 安全 web安全

本文转载自: https://blog.csdn.net/qq_55213436/article/details/142369081
版权归原作者 网安第一深禽 所有, 如有侵权,请联系我们删除。

“【JSrpc破解前端加密问题】”的评论:

还没有评论