前端加密对抗Part2-通过CDP远程调用Debug断点函数

新闻资讯   2023-06-13 17:42   77   0  

通过CDP远程调用Debug断点函数的作用

大多时候,我们在进行断点调试网页算法的时候,会跟踪到很多莫名其妙的自己写的算法,或者是做了很多混淆的代码,这些我们自己手动转换成其他语言的算法是比较麻烦的,神费力。

这个时候可以通过打一个Debug断点在我们可以调用加密/解密函数的地方,然后通过CDP协议进行调用。

分析CDP协议

1. 在devtools设置中打开Protocol Monitor用于监测cdp协议的调用记录



  • 只看几个关键的cdp协议请求/响应内容。

  • Debugger.paused 官方文档说明 此方法会返回当前Debug触发时,暂停点的callFrame信息。

当我们debug在这个点,并且在console输入命令时,我们是可以调用当前暂停断点位置的所有函数作用域内的函数,此时调用时候的CDP内容为Debugger.evaluateOnCallFrame方法,请求内容包含一个expression为执行的表达式内容。

工具实现

基于以上协议的分析,我们可以自己实现一个基于当前断点位置的函数调用,从而实现一个直接调用加密/解密函数的小工具。

伪代码

onEvents(`Debugger.paused`, function(event) {
for(var callFrame in event.callFrames) {
// 遍历所有的callfram信息
}

// 提取某个callframe调用
var resp = CDPSend(`Debugger.evaluateOnCallFrame`, { callFrameId: event.callFrames[0], expression: 'someEncryptFunction(xx)' })
println(resp)
})


实战

1. 当前数据包的请求和响应包都是加密的状态


2. 查找下断点的地方

通过Networks查看请求触发的函数调用栈

过去下断点并且触发

跟踪几次发现了加密算法的函数调用点,此处虽然用的是SM4加密,不过还有其他函数在处理,手动还原算法的太过于麻烦。

通过旁边的Call Stack调用栈回溯到上一个地方可以看到当前函数的调用方法(图中e.b这个地方是上图所示的地方,点击上一个也就是下图的(anonymous)地方)

可以看到这个函数作用域下的函数加密方法为 Object(ht.b), 第一个参数为待加密的字符串,第二个参数为一个常量。我们在此处打一个debug断点,然后触发到这里

测试加密

3. 工具演示

工具可以自己通过以上介绍的流程来研究并且编写辅助脚本,本质还是通过CDP协议控制。 此工具之后更加完善之后再进行开源

  1.  工具参数


     cmd ./remotejs_darwin_amd64 -h
    NAME:
    remotejs_darwin_amd64 - A new cli application

    USAGE:
    remotejs_darwin_amd64 [global options] command [command options] [arguments...]

    COMMANDS:
    help, h Shows a list of commands or help for one command

    GLOBAL OPTIONS:
    --chromepath value, --cp value browser bin path
    --devtools enable devtools (default: false)
    --remote-debug-port value, --rp value browser remote debug port, like ws://127.0.0.1:9999
    --headless enable headless (default: false)
    --web-port value web api port (default: "8002")
    Request API 0.0.0.0:8002/remote, [POST] eval=


  • 打开浏览器(有内置的chrome也可以通过连接远程remote debug port来进行操作)

  • 在浏览器中找到之前找到的断点并且触发

  • 远程调用, 此处通过eval参数可以传递我们的数据到debug处的console进行调用,这里和我们手动执行console是一样的结果。其中的变量都是我们可以自己改变的。



remotejs工具的日志

4. 结合mitmdump完成整个加密解密流程

  • 加密函数

 def request_remote_js(self, data: str):
data = data.replace(" ", "")
r = requests.post(
"http://127.0.0.1:8002/remote",
data={
"eval": "Object(ht.b)('{}', _dyn$.t(622))".format(data)
}
)
message = r.json().get("message", None)

if message:
return message
return ""
  • 解密函数

 def request_remote_js_decrypt(self, data: str):
data = data.replace(" ", "")
r = requests.post(
"http://127.0.0.1:8002/remote",
data={
"eval": "Object(ht.a)('{}')".format(data)
}
)
message = r.json().get("message", None)

if message:
return message
return ""
  • 调用流程

Burp -> Mitmproxy -- Request ---> 加密(Request Body)
<--- Response -- 解密(Response Body)
  • 完整代码

class RemoteJsDemo(AutoDecoderClass):

def request_remote_js(self, data: str):
data = data.replace(" ", "")
r = requests.post(
"http://127.0.0.1:8002/remote",
data={
"eval": "Object(ht.b)('{}', _dyn$.t(622))".format(data)
}
)
message = r.json().get("message", None)

if message:
return message
return ""

def request_remote_js_decrypt(self, data: str):
data = data.replace(" ", "")
r = requests.post(
"http://127.0.0.1:8002/remote",
data={
"eval": "Object(ht.a)('{}')".format(data)
}
)
message = r.json().get("message", None)

if message:
return message
return ""

def request(self, flow: http.HTTPFlow):
resp = self.request_remote_js(flow.request.content.decode("utf-8"))
flow.request.content = json.dumps({"encryptedData": resp}).encode("utf-8")

def response(self, flow: http.HTTPFlow):
resp = json.loads(flow.response.content.decode("utf-8")).get("data", None)

if resp:
flow.response.content = str(self.request_remote_js_decrypt(resp)).encode("utf-8")

最后的效果, 请求和响应都是解密操作的状态下进行

References

  • Chrome Devtools Protocol

原文连接

https://www.t00ls.com/articles-69054.html

文章引用微信公众号"T00ls安全",如有侵权,请联系管理员删除!

博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。