从一次前端 js 加密再到 mitm 中间人脚本

0X00 前端 JS 加密的加解密

1、前因

  • 在一次渗透测试中,项目经理给了一批小程序的资产,在挖洞的过程中,发现了一个流量加密的点,因为以前看过很多文章通过分析 js 文件来实现加解密数据,自己也想来实战一下通过分析 js 文件来实现加解密
  • 在 Burpsuite 中可以发现数据包中 POST 的 body 字段和响应包的 body 字段数据都是加密的,想到公司大佬的一句话“只要是前端加密,我都能给你解密”

image-20201207132142502

2、拖下小程序源码

  • 思路过程:adb 连接模拟器 -> 找到小程序的源码包 wxapkg -> 使用 adb pull 进行拉取到本地 -> 通过 unpack 工具来解出源码,具体的小程序脱包教程以及工具文章,感兴趣的大哥可以从雷神众测上查看Poc Sir的文章
    • xuedingmiaojun 大佬的不带 GUI 界面:wxappUnpacker
    • xuedingmiaojun 大佬的带 GUI 界面:mp-unpack(实测此工具能较完善解析 wxapkg 包)

image-20201207132433238

image-20201207132822003

3、快速分析源码

  • 使用 Sublime 打开压缩包的文件,来进行源码的查看

image-20201207133009652

  • 从刚才抓取的 Burpsuite 的数据包中的请求连接,全局匹配对应的句子,发现了在/pages/myInfo 目录下的 A.api.js 文件进行了 POST 请求

image-20201207133237727

  • 跟进对应的 js 文件,发现通过 t.request 方法来发送一个 POST 请求

image-20201207133443596

  • 跟进 t.request 方法,发现是导入/utils 目录下的 request 模块

image-20201207133615515

  • 跟进 request.js 文件,发现默认导出为 a,a 又通过函数 p 来进行赋值,在这个过程中,又通过引入 o.default 来进行传参

image-20201207134041254

  • 跟进 o.default,发现是通过导入/miniprogram_npm/wx-weapp-tool/index 下的 index 模块来实现的

image-20201207134147765

  • 跟进 index.js 文件,发现默认导出为 y,y 又通过 g 去赋值,搜索包含 g 的参数或者函数,发现 g 函数,g 函数中有对 o 的处理,通过 c.default.encrypt 来进行加密

image-20201207134453778

  • 搜索 c 的相关函数或者其他变量,发现是导入 d2jk-share-templates 目录下的 aes 模块

image-20201207141754540

  • 跟进 aes.js 文件,发现此文件就是最后的加密函数,以及加解密方法为 AES 加密结合 Base64 加密,可以通过导入 crypto-js 库来实现

image-20201207141849011

  • 将此文件进行导出,重新定义为 ase.js 文件,在终端进行加解密尝试,发现解密成功

image-20201207142451440

  • 对响应包的内容进行解密,发现了身份证以及手机号

image-20201207142919931

  • 在 lo 出数据后,发现通过黏贴密文,再输入 key 的方式效率实在是太低了,准备打算写一个自动化的中间人脚本来实现此过程

0X01 mitm 中间人脚本编写

1、需求前提

  • 实现原理图

image-20201208001317260

2、实现过程

  • js 文件的模板函数导出,方便外部的调用
1
2
3
4
5
6
module.exports.enc = function (data) {
console.log(i.encrypt(data, i.key))
}
module.exports.dec = function (data) {
console.log(i.decrypt(data, i.key))
}
  • 加解密函数的编写
    • cmd 为要执行的命令,使用 node 的-e 参数,require 调用模块以及模块里面的参数
    • pipeline 获得 os.popen 后的内容
    • 最后返回 result
1
2
3
4
5
6
7
8
9
10
def enc(data):
cmd = 'node -e "require(\\"./ase.js\\").enc(\'%s\')"' % (data)
pipeline = os.popen(cmd)
result = pipeline.read()
return result
def dec(data):
cmd = 'node -e "require(\\"./ase.js\\").dec(\'%s\')"' % (data)
pipeline = os.popen(cmd)
result = pipeline.read()
return result
  • mitm 第一层代理的编写

    • 需要接受来自客户端的加密请求,可以通过mitmdump -p 8081去监听端口,客户端设置 8081 端口进行代理流量

    • 接收来自客户端的加密数据,进行解密,然后发送给 Burpsuite

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def request(self, flow: http.HTTPFlow):
    def enc(data):
    cmd = 'node -e "require(\\"./ase.js\\").enc(\'%s\')"' % (data)
    pipeline = os.popen(cmd)
    result = pipeline.read()
    return result
    def dec(data):
    cmd = 'node -e "require(\\"./ase.js\\").dec(\'%s\')"' % (data)
    pipeline = os.popen(cmd)
    result = pipeline.read()
    return result
    req_data = flow.request.get_text()
    if req_data:
    print("req:"+req_data)
    print("解密:"+dec(req_data))
    flow.request.set_text(dec(req_data))
    • 发送来自 Burpsuite 的解密数据,进行加密,然后发送给客户端
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def response(self, flow: http.HTTPFlow):
    def enc(data):
    cmd = 'node -e "require(\\"./ase.js\\").enc(\'%s\')"' % (data)
    print(cmd)
    pipeline = os.popen(cmd)
    result = pipeline.buffer.read().decode(encoding="utf-8") # 因为中文编码问题会报错,这里需要进行utf-8编码
    return result
    def dec(data):
    cmd = 'node -e "require(\\"./ase.js\\").dec(\'%s\')"' % (data)
    pipeline = os.popen(cmd)
    result = pipeline.buffer.read().decode(encoding="utf-8") # 因为中文编码问题会报错,这里需要进行utf-8编码
    return result
    resp_data = flow.response.get_text()
    if resp_data:
    print(resp_data.strip('\n'))
    flow.response.set_text(dec(resp_data.strip('\n')))
    • 设置上游代理为 Burpsuite,进行数据包的转发mitmdump -p 8081 -m upstream:http://127.0.0.1:8080 -s min.py -k

      • -m 为指定上游代理模块,这里为 Burpsuite 监听的端口
      • -k 为忽略证书的错误,同时也需要在客户端中安装 mitm 的证书(安装 mitm 的证书在设置代理的情况下访问https://mitm.it下载即可)
      • -s 为指定使用的脚本

      image-20201208100558530

    • 发现已经可以正常的对请求报进行解密

    image-20201208100941327

  • Burpsuite 的设置

    • 监听 8080 端口,接收来自 mitm 第一层代理的数据
    • 设置上层代理为 mitm 第三层代理,进行数据包的转发

image-20201208101410378

  • mitm 第三层代理的编写

    • 接收来自 Burpsuite 的解密后的数据,可以通过mitmdump -p 8088去监听端口
    • 接收来自 Burpsuite 的解密数据,进行加密,然后发送给服务端
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    def request(self, flow: http.HTTPFlow):
    def enc(data):
    cmd = 'node -e "require(\\"./ase.js\\").enc(\'%s\')"' % (data.strip('\n'))
    print(cmd)
    pipeline = os.popen(cmd)
    result = pipeline.buffer.read().decode(encoding="utf-8")# 因为中文编码问题会报错,这里需要进行utf-8编码
    return result
    def dec(data):
    cmd = 'node -e "require(\\"./ase.js\\").dec(\'%s\')"' % (data)
    pipeline = os.popen(cmd)
    result = pipeline.buffer.read().decode(encoding="utf-8")# 因为中文编码问题会报错,这里需要进行utf-8编码
    return result
    req_data = flow.request.get_text()
    if req_data:
    print(req_data)
    print("sdasdasdasa")
    req_data = req_data.replace('"','\\"')
    print("req:"+req_data)
    print("加密:"+enc(req_data))
    flow.request.set_text(enc(req_data))
    • 发送来自服务端的加密数据,进行解密,然后发送给 Burpsuite
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    def response(self, flow: http.HTTPFlow):
    def enc(data):
    cmd = 'node -e "require(\\"./ase.js\\").enc(\'%s\')"' % (data)
    print(cmd)
    pipeline = os.popen(cmd)
    result = pipeline.buffer.read().decode(encoding="utf-8")# 因为中文编码问题会报错,这里需要进行utf-8编码
    return result
    def dec(data):
    cmd = 'node -e "require(\\"./ase.js\\").dec(\'%s\')"' % (data)
    pipeline = os.popen(cmd)
    result = pipeline.buffer.read().decode(encoding="utf-8")# 因为中文编码问题会报错,这里需要进行utf-8编码
    return result
    resp_data = flow.response.get_text()
    if resp_data:
    print("req:"+resp_data)
    print("解密:"+dec(resp_data))
    print(resp_data.strip('\n'))
    flow.response.set_text(dec(resp_data.strip('\n')))
    • 设置转发给服务器,进行数据包的转发mitmdump -p 8088 -s min.py -k

    image-20201208103439259

    • 使用 Burpsuite 的 Repeater 模块进行测试,发现已经可以正常加解密了

    image-20201208103721232

    image-20201208104630280

0X02 总结

​ 这次的过程中也存在着很多问题,请各位路过的大哥大姐大佬等不吝指导,后续想集成一个 Burpsuite 插件,可以自定义需要加解密的目标地址方便渗透测试加解密,只需要导入加密的 js 文件即可,各个论坛网站上也有各个大佬开发的插件脚本,想后续继续深入学习