【web逆向】全报文加密流量的去加密测试方案

aHR0cHM6Ly90ZGx6LmNjYi5jb20vIy9sb2dpbg 国密混合

WEB JS逆向篇

先看报文:请求和响应都是全加密,这种情况就不像参数加密可以方便全文搜索定位加密代码,但因为前端必须解密响应的密文,因此万能的方法就是搜索拦截器,从第一行下断点分析,以找到加密的位置。

在这里插入图片描述

通常vue前端会使用axios配置拦截器,如下图,在搜索到的api.js的134、187行下断点,然后任意请求即可。

在这里插入图片描述

实际操作的时候断点建议打在第一个箭头函数和第二个箭头函数的第一行,避免因参数差异越过需要分析的逻辑。

在这里插入图片描述

做一下简单审计和判断,由于参数保存在config里,所以重点关注对config操作的代码,步入173行的函数进一步分析。

在这里插入图片描述

84、93行和96行看到加密方法了,分别是在post和get情况下对参数加密处理的逻辑。调试时由于是post方法,故步入84行函数调用。
在这里插入图片描述

步入该方法才实际调用加密函数本身,对应的猜测29行是解密函数,顺便下个断点。
在这里插入图片描述

该金融公司用的名为microAppSafety的js文件是个加解密库,且做了如上形式的混淆(本例涉及国密,该公司其它站点下使用类似文件名的js加解密库或均采用了国密)
混淆严重影响了源码的分析和阅读,但由于目的不是了解其加密逻辑的具体实现,到此该节就结束了,刚才解密的断点待服务器响应后也会停住,同理分析即可。
后记:该站点实际于测试环境进行,与生产环境的代码略有不同(源码形式不同,非代码实现不同),起初分析的时候由于种种原因都没有找到加密的函数,但在生产环境下找到,反推测试环境:找到的加密函数的关键字"encryptData"在测试环境中同文件里搜索并下断点,才得以成功完成测试环境的分析。

加密/验签策略定位技巧总结

前端加解密通常涉及两个开源库:CryptoJS和JSEncrypt,两个库的代码分别形如:

//CryptoJS
var wordArray = CryptoJS.enc.Utf8.parse('𤭢');
var utf8  = CryptoJS.enc.Utf8.stringify(wordArray);//JSEncrypt
var crypt = new JSEncrypt();
crypt.setKey(__YOUR_OPENSSL_PRIVATE_OR_PUBLIC_KEY__); 
var text = 'test';
var enc = crypt.encrypt(text);

单个参数加密

全局搜索加密的参数名,并跟踪从取值到请求过程值的变化(处理)
加密位置常见于:

  1. 赋值处(从组件取值时)
var pwd = $('#pwd').val();
var pwd = encrypt(pwd);
  1. 拦截器处理当中和ajax之前;
    在这里插入图片描述

全报文加密

  1. 全局搜索interceptors.request.use并对其下断点单步分析
  2. 调用栈分析
    无法确认哪一帧调用的加密时,从较早的帧开始分析传入的参数是明文还是密文,并在数据为密文的第一帧的上一帧下断点,基本就可以分析处加密的位置了。
    2.1. 从“网络“(浏览器开发者工具栏)中定位某个全报文加密的XHR请求(图示使用firefox,chrome中在启动器一栏中查看调用栈)
    在这里插入图片描述

2.2. 对全报文加密的请求设置XHR断点,查看调用栈

加密形式判断

  1. 数字信封:随机数生成对称密钥加密数据(一次一密)-》公钥加密对称密钥-》传输:
    两个值:jsonData,key或一个值:一个公钥加密的值包含对称密钥和数据密文
  2. 单一形式的加密
    仅使用对称或非对称密码进行加密,复杂加密机制的通常会有密钥协商(交换)的过程或其他一些密钥安全的机制,如:每个请求前先请求getPubkey获取公钥(非对称)、使用两对密钥,前端硬编码用于加密的公钥A和用于解密的私钥B,后端使用私钥A解密,使用公钥B加密,(非对称,因此前端如果发现PRIVATE_KEY和PUBLIC_KEY实际是两对密钥)等;简单加密机制通常可以直接在js中找到硬编码的key(对称,利用burp插件就可以直接完成自动化加解密)
    2.1. 对称加密:aes/des/3des/国密(如常见sm4)-》传输
    全部参数名:仅对某个值加密或全报文
    2.2. 非对称密钥:RSA/国密(常见sm2)-》传输
    全部参数名:仅对某个值加密或全报文

签名机制分析定位

全局搜索保存签名的字段(通常包含sign)

  1. url参数签名+签名参数如:
parm=1&sign=md5(parm=1)
  1. 参数值签名+签名参数如:
pwd=a&name=b&sign=md5(a|b)
  1. 请求头如
    x-passwd:123
    x-timestamp:169
    x-sign:md5(123+169)

请求改造篇

基于RPC技术的自动化去加密测试。
本地替换js修改加密调用

在这里插入图片描述

在这里插入图片描述

前端拦截器里最后通过方法g()实现对参数处理的逻辑,但不是加密方法本身,其中实现了request method的判断和超时参数的添加(方法p)。
所以改造p方法来去掉加密的调用,使burp接收明文。
代码如下:

function p(e) {return JSON.stringify({data: Object(u["a"])({}, e),dataExpireTime: 1689999999999 

//使用一个较大的固定时间戳而非实时生成,以绕过服务器的时间戳超时校验机制
})
}

验证码获取请求(GET)
在这里插入图片描述

请求(POST)

在这里插入图片描述

GET方法和POST方法经过处理后的流量在burp里已经是明文。

编写RPC客户端通讯脚本

首先定义RPC调用的加解密对象:
在这里插入图片描述

调试过程将加密对象设置为全局对象,第二个打印的变量是加密密钥(源码硬编码值)。
Q&A:
为什么是d?
因为调试的当前页面里指向加密对象的变量是d;
为什么不定义p方法或是d.encryptData方法?
因为如果全局变量指向p方法会导致其运行加密方法时找不到某些定义在加解密库js文件中的方法而报undefined异常(破坏了作用域链的顺序);直接指向这个加密对象便于加解密时RPC使用同一个全局对象。

将RPC客户端加载到浏览器环境里,注入方法如油猴插件hook,本地覆盖到页面js和运行代码段等,建议在代码段里运行(实测注入到页面js中ws的通讯不稳定)
使用sekiro框架提供的服务端与客户端demo即可,并按实际情况修改通讯代码

//省略未变动的代码,将在参考链接中给出
var client = new SekiroClient("ws://127.0.0.1:5612/business-demo/register?group=rpc-test&clientId="+guid());client.registerAction("enc",function(request, resolve, reject){resolve(secApp.encryptData(request["params"],'04337449135FE6BD62D0683CE30AEA1BD178B879A392162D9F87A2FF0EC819A…'));
})

编写中间处理脚本

编写用于处理加密调用和密文流量转发的脚本mitm.py:

#rpc加密
def encrypt(params):# print("request params in enc func:::{}".format(params))api = "http://127.0.0.1:5612/business-demo/invoke?group=rpc-test&action=enc&jsonData={}".format(params)res = requests.get(api).json()# print("res:::{}:::{}".format(str(res),str(res['data'])) ) json()转换响应为json对象便于访问data字段return json.dumps({'data':res['data'],'responseCode':res['responseCode'],'responseDesc':res['responseDesc']})#修改请求
def request(flow):#获取请求方法,返回字符串:POST GETmethod = flow.request.methodif method == "GET":#获取查询参数# :MultiDictView[('{"data":{},"dataExpireTime":1689999999999}', '')]:::type is::: <class 'mitmproxy.coretypes.multidict.MultiDictView'># params = flow.request.query 目标对整个查询字串加密,query.get("param_name")针对参数加密的情况使用params = flow.request.url.split("?", 1)[1]elif method == "POST":#获取请求bodyparams = flow.request.textelse:params = None# print("request params:::{}:::type is:::{}".format(params,type(params)))encryptedData = encrypt(params)print("encData:::{}".format(encryptedData) )if method == "GET":flow.request.url = flow.request.url.split("?",1)[0]+ "?" + encryptedData# print("request url:::{}".format(flow.request.url))elif method == "POST":flow.request.text = encryptedData

Tips:这里可以利用burp的repeater模块进行脚本的测试,不必在浏览器里操作站点功能。

响应改造

同理对系统解密的流程分析并编写相关的脚本。
在这里插入图片描述

如果请求未通过,服务器将响应200以外的代码,此时拦截器进入reject部分,该部分的处理是没有解密过程的,响应包也可看到是明文形式的,因此编写中间脚本时需要判断返回码以决定是否进入RPC解密的调用。
一般情况使用GET方法便于浏览器API调用,但受限于URL长度,当对响应解密时,响应过长会导致GET方法无法正常请求,因此API调用改换POST方式。

#RPC解密
def decrypt(params):api = "http://127.0.0.1:5612/business-demo/invoke"jsonObj = {"group": "rpc-test","action": "dec","param": str(params)}res = requests.post(api, json=jsonObj).json()print("res:::{}:::".format(str(res['data'])) )return json.dumps(res['data'])#修改响应
def response(flow):body = flow.response.content.decode('utf-8')print("response body:::{}".format(body))#判断响应是否为密文if flow.response.status_code == 200:decryptedBody = decrypt(body)flow.response.text = decryptedBody

重写本地JS时对方法f改造,即“直接调用解密方法“的方法。
在这里插入图片描述

function f(e) {return e
}

RPC client加上解密的action:

client.registerAction("dec", function(request, resolve, reject){resolve(secApp.decryptDataOneWay(request["param"], 'DA7668FAx7'));
});

开启RPC(先服务端、再客户端)和mitmdump
在这里插入图片描述

(图示上窗运行RPC server,下窗运行mitmdump)
在这里插入图片描述
(运行RPC client)

burp进行测试中的流量:
在这里插入图片描述

原本加密的响应数据已呈明文。

通讯图示

红色箭头发起第一个请求,RPC Server和RPC Clinet之间通过websocket通讯,mitmdump和RPC Server间通过http通讯(API),其余箭头都是代理流量转发的过程。
在这里插入图片描述

注: 可以联动自动化工具,把流量用脚本加密代理出去。

参考文档

mitmproxy
https://docs.mitmproxy.org/stable/api/mitmproxy/http.html#Request
sekiroAPI:
https://sekiro.iinti.cn/sekiro-doc/01_user_manual/3.restful_api.html#get%E5%92%8Cpost
sekiro客户端:
https://sekiro.virjar.com/sekiro-doc/assets/sekiro_web_client.js
完整通讯代码:

function guid() {function S4() {return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);}return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}var client = new SekiroClient("ws://127.0.0.1:5612/business-demo/register?group=rpc-test&clientId=" + guid());// var secApp = new microAppSafety;client.registerAction("enc", function (request, resolve, reject) {resolve(secApp.encryptData(request["param"],enckey));})client.registerAction("dec", function (request, resolve, reject) {resolve(secApp.decryptDataOneWay(request["param"],deckey));})//站点请求一次后在控制台中执行window.secApp = new microAppSafety;注册全局对象

续:脚本优化

import json
import requests
import urllib.parsejava_server = 'http://127.0.0.1:5612/business-demo/invoke'# RPC
def rpc(action, params, group='rpc-test'):url = java_serverdata = {'group': group,'action': action,'param': params}count = 0  # 计数器while 1:count += 1if count > 10:# TODO:处理超时逻辑breakres = requests.post(url, data=data).json()if 'data' in res:return resreturn ''# 解密
def decrypt(params: str):res = rpc('dec', params)print("dec:::res:::{}:::".format(str(res)))return json.dumps({'data': res['data'], 'responseCode': res['responseCode'], 'responseDesc': res['responseDesc']})# 加密
def encrypt(params: str):res = rpc('enc', params)return res['data']# 修改请求
def request(flow):method = flow.request.methodif method == "GET":flow.request.url = flow.request.url.split("?", 1)[0] + "?" + encrypt(urllib.parse.unquote(flow.request.url.split("?", 1)[1]))print('GET')elif method == "POST":flow.request.text = encrypt(flow.request.text)# 修改响应
def response(flow):body = flow.response.content.decode('utf-8')if flow.response.status_code == 200:flow.response.text = decrypt(body)

埋坑(框架bug):

  1. 实际操作时会出现RPC handler undefined异常,暂未探究具体原因,个人解决方法是在中间脚本里轮询RPC,判断是否正常调用:
count = 0
while 1:count += 1res = requests.post(api, json=jsonObj).json()print(count)if 'data' in res:break
  1. 解密RPC的响应长这样:
    {‘clientId’: ‘5af6b925-aa77-7184-dae5-1bfe289b7b21’, ‘data’: {‘verifyCode’: ‘/9w/UUAf/9k=’, ‘verifyId’: ‘654054282479276032’}, ‘responseCode’: ‘success’, ‘responseDesc’: ‘success’, ‘status’: 0}
    这就导致起初直接拿data无法正常进入前端逻辑(序列化结果与原字串存在差异,嵌套json被提出来了),因此中间脚本返回时需要加上后面两个字段:‘responseCode’和’responseDesc’。(进分析是由于客户端处理时的偏差,没有把响应的数据正确的全部作为data属性的值,可以修改客户端代码,这里处理方法是把加解密的结果b64打包了一下)

古早文档,代码部分已全量改进,先不放了,没时间改了,马上要去看电影了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/28286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

0基础学习VR全景平台篇 第78篇:全景相机-拍摄VR全景

新手入门圆周率科技&#xff0c;成立于2012年&#xff0c;是中国最早投身嵌入式全景算法研发的团队之一&#xff0c;亦是全球市场占有率最大的全景算法供应商。相继推出一体化智能屏、支持一键高清全景直播的智慧全景相机--Pilot Era和Pilot One&#xff0c;为用户带来实时畅享…

【个人记录】CentOS7 编译安装最新版本Git

说明 使用yum install git安装的git版本是1.8&#xff0c;并不是最新版本&#xff0c;使用gitlab-runner托管时候会拉项目失败&#xff0c;这里使用编译源码方式安装最新版本的git。 基础环境安装 echo "nameserver 8.8.8.8" >> /etc/resolv.conf curl -o /…

算法基础之插入排序

1、插入排序基本思想 插入排序的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常采用in-place排序&#xff08;即只需用到O(1)的额外空间的排序&#xff09;&a…

【论文阅读】UNICORN:基于运行时来源的高级持续威胁检测器(NDSS-2020)

UNICORN: Runtime Provenance-Based Detector for Advanced Persistent Threats NDSS-2020 哈佛大学 Han X, Pasquier T, Bates A, et al. Unicorn: Runtime provenance-based detector for advanced persistent threats[J]. arXiv preprint arXiv:2001.01525, 2020. 源码&…

vue3 excel 导出功能

1.安装 xlsx 库 npm install xlsx2.创建导出函数 src/utils/excelUtils.js import * as XLSX from xlsx;const exportToExcel (fileName, datas, sheetNames) > {// 创建工作簿const wb XLSX.utils.book_new()for (let i 0; i < datas.length; i) {let data datas…

24届近5年上海交通大学自动化考研院校分析

今天给大家带来的是上海交通大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、上海交通大学 学校简介 上海交通大学是我国历史最悠久、享誉海内外的高等学府之一&#xff0c;是教育部直属并与上海市共建的全国重点大学。经过120多年的不懈努力&#xff0c;上海交…

【深度学习注意力机制系列】—— ECANet注意力机制(附pytorch实现)

ECANet&#xff08;Efficient Channel Attention Network&#xff09;是一种用于图像处理任务的神经网络架构&#xff0c;它在保持高效性的同时&#xff0c;有效地捕捉图像中的通道间关系&#xff0c;从而提升了特征表示的能力。ECANet通过引入通道注意力机制&#xff0c;以及在…

使用Pytest集成Allure生成漂亮的图形测试报告

目录 前言 依赖包安装 Pytest Allure Pytest Adaptor 改造基于Pytest的测试用例 生成测试报告 运行测试 生成测试报告 打开测试报告 资料获取方法 前言 之前写过一篇生成测试报告的博客&#xff0c;但是其实Allure首先是一个可以独立运行的测试报告生成框架&#xff…

ChatGPT访问流量下降的原因分析

​自从OpenAI的ChatGPT于11月问世以来&#xff0c;这款聪明的人工智能聊天机器人就席卷了全世界&#xff0c;人们在试用该工具的同时也好奇该技术到底将如何改变我们的工作和生活。 但近期Similarweb表示&#xff0c;自去ChatGPT上线以来&#xff0c;该网站的访问量首次出现下…

Java 代码重试实现方式

Java 代码重试实现方式 一.方法内直接自动重试二.静态代理方式1.启动类2.接口3.实现4.静态代理5.单元测试类 三.JDK 动态代理1.代理类2.单元测试 四.CGLIB 动态代理1.动态代理类2.单元测试 五.手动 AOP1.自定义注解2.重试注解切面3.测试类4.单元测试方法 六.Spring Retry1.测试…

【Linux】深入理解进程概念

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;Linux仓库 个人专栏&#xff1a;Linux专栏 分享一句喜欢的话&#xff1a;热烈的火焰&#xff0c;冰封在最沉默的火山深处 文章目录 前言浅谈进程概念1. 进程和操作系统的联系2.描述进程的对象——PCB …

如何调教让chatgpt读取自己的数据文件(保姆级图文教程)

提示&#xff1a;如何调教让chatgpt读取自己的数据文件(保姆级图文教程) 文章目录 前言一、如何投喂自己的数据&#xff1f;二、调教步骤总结 前言 chatgpt提示不能读取我们提供的数据文件&#xff0c;我们应该对它进行调教。 一、如何投喂自己的数据&#xff1f; 让chatgpt读…

通向架构师的道路之weblogic的集群与配置

一、Weblogic的集群 还记得我们在第五天教程中讲到的关于Tomcat的集群吗? 两个tomcat做node即tomcat1, tomcat2&#xff0c;使用Apache HttpServer做请求派发。 现在看看WebLogic的集群吧&#xff0c;其实也差不多。 区别在于&#xff1a; Tomcat的集群的实现为两个物理上…

网络安全渗透测试之靶场训练

NWES: 7月26号武汉地震检测中心遭受境外具有政府背景的黑客组织和不法分子的网络攻击。 目前网络攻击主要来自以下几种方式: DDOS&#xff1a;分布式拒绝服务攻击。通过制造大量无用的请求向目标服务器发起访问&#xff0c;使其因短时间内无法处理大量请求而陷入瘫痪。主要针对…

oracle容灾备份怎么样Oracle容灾备份

随着科学技术的发展和业务的增长&#xff0c;数据安全问题越来越突出。为了保证数据的完整性、易用性和保密性&#xff0c;公司需要采取一系列措施来防止内容丢失的风险。  Oracle是一个关系数据库管理系统(RDBMS),OracleCorporation是由美国软件公司开发和维护的。该系统功能…

【C语言题解】将一句话的单词进行倒置,标点不倒置。

题目描述&#xff1a;将一句话的单词进行倒置&#xff0c;标点不倒置。比如 “I like beijing.”&#xff0c;经过处理后变为&#xff1a;“beijing. like I”。 文章目录 原题目题目描述&#xff1a;输入描述&#xff1a;输出描述&#xff1a;题目链接&#xff1a; 整体思路分…

【数模】主成分分析PCA

主成分分析(Principal Component Analysis,PCA)&#xff0c;是一种降维算法&#xff0c;它能将多个指标转换为少数几个主成分&#xff0c;这些主成分是原始变量的线性组合&#xff0c;且彼此之间互不相关&#xff0c;其能反映出原始数据的大部分信息。使用场景&#xff1a;一般…

jupyter文档转换成markdown

背景 上一篇文章**《如何优雅地用python生成模拟数据》**我就使用jupyter写的&#xff0c;这个真的是万能的&#xff0c;可以插入markdown格式的内容&#xff0c;也可写代码&#xff0c;关键是像ipython一样&#xff0c;可以分步执行。 我可以这样自由的写我的博客内容&#x…

linux 安装go 1.18版本

首先去官网找到对应的版本 直接下载下来&#xff08;如果服务器可以直接访问到go 官网也可以wget直接下载到服务器&#xff09; 然后把该包上传到linux 的/usr/local 目录下 然后直接解压安装该包&#xff1a; sudo tar -C /usr/local -zxvf go1.18.10.linux-amd64.tar.gz 然…

设计模式行为型——观察者模式

目录 什么是观察者模式 观察者模式的实现 观察者模式角色 观察者模式类图 观察者模式举例 观察者模式代码实现 观察者模式的特点 优点 缺点 使用场景 注意事项 实际应用 什么是观察者模式 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式…