Featured image of post JSRPC学习

JSRPC学习

JSRPC实现网站加解密

参考资料:

https://mp.weixin.qq.com/s/vHoVPINf4GKhR36LSQlDXw

使用JSRPC实现前端加密破解,自动化加密

https://mp.weixin.qq.com/s/JnHHq1g1e_cZ2tMdyufEoA

1.JSRPC有什么用

在渗透测试项目中,或者是大家挖掘SRC的时候,有一些场景比如登录、查询或者是一些接口调用当中,经常会见到加密字段的身影,比如登录的password、查询的时候的sign、一些接口的cookie字段,这些其实都是通过前端加密之后发到后端的,还有一些后端传递过来的数据本身就是加密的,然后放到前端来解密成明文,这样加密的数据我们直接通过burp几乎是不可能进行顺利的测试的,所以这时候就需要对加密数据进行逆向来辅助我们渗透,但是很多师傅并不是很想花时间去进行**扣代码、补环境或者是还原算法来达到逆向效果这时候JSRPC可以快速的帮我们实现直接调用网站环境当中的加密或者解密函数的效果,免去扣代码和补环境,简直就是一大神器**

2.案例实战

2.1.利用JSRPC还原请求包加密

这里不说理论基础,直接上案例怎么用

https://passport.meituan.com/account/unitivelogin

由于网站是RSA加密,直接全局搜索setPublicKey,在加密函数出打上断点,进行调试,看是否定位准确

定位到加密函数,那就可以直接使用JSRpc进行逆向了

1.开启JSRpc服务端

下载编译好的工具直接运行即可

在控制台运行JS_Env_Dev.js这个脚本文件,文件在项目的资源目录中有

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

将代码放到控制台运行后,右键替换内容

1
2
3
4
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=mt");
demo.regAction("pass", function(resolve, param) {
    resolve(encrypt.encrypt(param))
});

再次点击登录,如果出现JSRPC服务端出现该界面,表示注册成功

访问:http://127.0.0.1:12080/go?group=mt&action=pass&param=123456

2.2.利用JSRPC还原响应包加密

蝉妈妈 - 短视频内容营销与直播电商洞察平台

对于响应包加密的数据包,直接全局搜索解密函数decrypt

注册

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
a = s.AES.decrypt(e, n, {
    mode: s.mode.ECB,
    padding: s.pad.Pkcs7
}),
o = l(a),
r = c.ungzip(o, {
    to: "string"
}),

//这个加密分3个步骤从a--->o--->r ,r是明文,如何将他变为1块呢

a = s.AES.decrypt(e, n, {
    mode: s.mode.ECB,
    padding: s.pad.Pkcs7
}),
o = l(s.AES.decrypt(e, n, {
    mode: s.mode.ECB,
    padding: s.pad.Pkcs7
})),

//先将这几个合并起来,由于是函数,还需要有头和传入的参数,由于传入的参数是param,参数是加密
的密文但是源代码中e就是加密的字符串所以只需要将e变为我们传入的参数并且函数需要返回值

function getdate(param){
r = c.ungzip(l(s.AES.decrypt(e, n, {
    mode: s.mode.ECB,
    padding: s.pad.Pkcs7
})), {
    to: "string"
}),
}


window.getdate = function getdate(param){
    return c.ungzip(l(s.AES.decrypt(param, n, {
        mode: s.mode.ECB,
        padding: s.pad.Pkcs7
    })), {
        to: "string"
    })
}

建立连接

这几个脚本都是直接放控制台运行即可,无需替换内容

1
2
3
4
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=cmm");
demo.regAction("getdata", function(resolve, param) {
    resolve(window.getdate(param))
});

http://127.0.0.1:12080/go?group=cmm&action=getdata&param=网站返回包加密内容

image-20250913235832715

By Lsec
最后更新于 Sep 14, 2025 00:03 +0800
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计
¹鵵ҳ