1、前言

现在越来越多的网站采用全报文加密,测试的时候需要逆向提取加密算法以及密钥,过程十分繁琐和复杂。本文提供一种更为简单快捷的方法来解决此问题。

原理大致如下:使用浏览器的Override Hook加密前的数据,配置代理地址发送给中转服务器,中转服务器将修改后的内容传给Hook函数,最后再传给后端。

2、环境

Echo Server:Python3实现的一个中转服务器

Chrome:Sources->Overrides Hook线上js

BurpSuite:HTTP抓包工具

目标地址:id.oppo.com

3、调试

首先要找到加密前数据位置。打开的Chrome的XMLHTTPRequest的日志记录,并对后端发起请求。

post body数据被加密了。
https://id.oppo.com/apis/login/validate-passwordjava接口安全加密签名_数据

下面来定位加密前数据位置,找到刚刚那个请求的调用栈

java接口安全加密签名_java接口安全加密签名_02


然后使用XHR断点来查看输入的数据。

java接口安全加密签名_开发语言_03


然后点击登录

java接口安全加密签名_java接口安全加密签名_04

跟到w.post,很明显是一个封装的后的post请求函数。

java接口安全加密签名_前端_05


将整个js保存到Overrides窗口下。

右键点击js文件,保存并覆盖。

(https://id.oppo.com/new/js/vendors_business~9326b498.1c00dd58484efe3187d8.js)

java接口安全加密签名_开发语言_06

从上述代码得知,url的值为t,data值为e。调用js方法打印t的看看。(修改完需ctri+s保存并刷新网页才能生效)

console.log(“调试打印数据”,e)

java接口安全加密签名_javascript_07

再次点击密码登录查看刚刚hook效果。

java接口安全加密签名_数据_08

如上图,明文内容已经被我们hook到。

但是现在只是能获取到明文内容,如果需要动态修改内容就需要与抓包工具交互。用一个中转服务器(Echo Server)将post body的内容作为响应内容返回给hook函数即可。

4、数据发送与修改

通过javascript将明文内容经过抓包工具发送给Echo Server。查看以下代码示例:

W.post = function(t, e, n) {
        console.log("调试打印数据",e)
        // 构造发包
       	var xhr = new XMLHttpRequest();
        // 同步
        xhr.open('post', 'http://127.0.0.1:27001/oppo/req', false);
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhr.send(JSON.stringify(e));
        // 获取到修改后的数据传给原来流程
        //  转回对象
        let modifyData = JSON.parse(xhr.responseText);
        // 重新赋值
        e = modifyData;
        return W(Object.assign({
        url: t,
        data: e,
        method: "post"
            }, n))
        }

java接口安全加密签名_前端_09


burp配置监听端口27001,js发送请求会经过burp代理

java接口安全加密签名_javascript_10


将流量重定向至Echo Server

java接口安全加密签名_java接口安全加密签名_11


Echo Server代码:

from http.server import HTTPServer, BaseHTTPRequestHandler


class RequestHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        print('Recving request connction...')
        request_headers = self.headers
        content_length = request_headers.get('content-length')
        length = int(content_length[0]) if content_length else 0

        print(self.headers)
        self.send_response(200)
        self.end_headers()
        self._send_cors_headers()
        self.wfile.write(self.rfile.read(length))

    def do_POST(self):
        print('Recving request connction...')
        req_datas = self.rfile.read(int(self.headers['content-length']))
        # print(self.headers)
        # print(req_datas)

        self.send_response(200)
        self._send_cors_headers()
        self.end_headers()
        self.wfile.write(req_datas)

    def _send_cors_headers(self):
        self.send_header('Content-type', 'application/json')
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Access-Control-Allow-Methods", "*")
        self.send_header("Access-Control-Allow-Headers", "Authorization, Content-Type")

    def do_OPTIONS(self):
        self.send_response(200)
        self._send_cors_headers()
        self.end_headers()


def main(ECHO_PORT):
    print('Listening on localhost: %d' % ECHO_PORT)
    server = HTTPServer(('127.0.0.1', ECHO_PORT), RequestHandler)
    server.serve_forever()


if __name__ == '__main__':
    main(27002)

效果如下:

java接口安全加密签名_开发语言_12


java接口安全加密签名_前端_13

5、引用

基于浏览器Override对抗前端加密 由于这篇文章写的和网站有实际出入,所以我复现完才出了一篇文章