文章导读
声明:文中涉及到的技术和工具,仅供学习使用,禁止从事任何非法活动,如因此造成的直接或间接损失,均由使用者自行承担责任。
众亦信安,中意你啊!
点不了吃亏,点不了上当,设置星标,方能无恙!
日子一天比一天难熬啊,如图所示老板给渗透的站点数据包全加密了。
前车之鉴,生怕让我卷铺盖走人,没办法头发掉点就掉点吧。
找到关键字CipherText,直接F12全局搜索打上断点,1分钟定位(实际60秒)
加密函数: (0, u.getSm2DataHexByObject)
解密函数: (0, u.getSm2DataByString)
由于加解密函数无法全局调用,所以要先把它们通过window变量代理到全局,以便全局调用。
debug到加密或解密函数的时候,在控制台分别输入下面的代码
这里有个小重点,由于加密函数的入参是一个object,也就是json对象,但是json对象不利于写代码传输,所以这里的mysm2enc函数的入参我改成了base64编码后的字符串,然后通过atob和JSON.parse对字符串进行解析(类比反序列化)
window.mysm2enc = function(encodedStr) {
try {
console.log("+++加密+++ ",encodedStr)
// 解码 base64 加密后的字符串
var decodedStr = decodeURIComponent(atob(encodedStr));
var jsonObj = JSON.parse(decodedStr);
// 调用 getSm2DataHexByObject 函数并返回结果
var result = (0,u.getSm2DataHexByObject)(jsonObj);
console.log("---加密--- ",result)
return result;
} catch (error) {
console.error("Error encrypt or parsing:", error);
return null;
}
};
window.mysm2dec = function(encodedStr) {
try {
console.log("+++解密+++ ",encodedStr)
var result = (0,u.getSm2DataByString)(encodedStr);
console.log("---解密--- ",result)
return result;
} catch (error) {
console.error("Error decrypt :", error);
return null;
}
};
然后在非debug情况下,测试一下函数的可用性。
加解密函数准备好后,通过在控制台执行以下代码,配置并连接jsrpc。
jsrpc项目地址:https://github.com/jxhczhl/JsRpc
function Hlclient(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 () {
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("catch error", requestJson);
result = transjson(requestJson)
}
//console.log(result)
if (!result['action']) {
this.sendResult('', 'need request param {action}');
return
}
var action = result["action"]
var theHandler = this.handlers[action];
if (!theHandler) {
this.sendResult(action, 'action not found');
return
}
try {
if (!result["param"]) {
theHandler(function (response) {
_this.sendResult(action, response);
})
return
}
var param = result["param"]
try {
param = JSON.parse(param)
} catch (e) {}
theHandler(function (response) {
_this.sendResult(action, response);
}, param)
} catch (e) {
console.log("error: " + e);
_this.sendResult(action, e);
}
}
Hlclient.prototype.sendResult = function (action, e) {
if (typeof e === 'object' && e !== null) {
try {
e = JSON.stringify(e)
} catch (v) {
console.log(v)//不是json无需操作
}
}
this.send(action + atob("aGxeX14") + e);
}
function transjson(formdata) {
var regex = /"action":(?<actionName>.*?),/g
var actionName = regex.exec(formdata).groups.actionName
stringfystring = formdata.match(/{..data..:.*..\w+..:\s...*?..}/g).pop()
stringfystring = stringfystring.replace(/\\"/g, '"')
paramstring = JSON.parse(stringfystring)
tens = `{"action":` + actionName + `,"param":{}}`
tjson = JSON.parse(tens)
tjson.param = paramstring
return tjson
}
//连接
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=firefox");
提示连接成功。
这里要写两个MITM代理脚本,
下游代理: 位于浏览器和burp之间,监听端口设置为7070,转发到burp的8080。
负责将密文请求数据包解密,明文发给burp,以及重新加密明文响应,以便浏览器可以正常显示。
上游代理: 位于burp和服务器之间,监听端口设置为9090,设置burp的数据包转发到9090。
负责将明文请求数据包重新加密发给服务器,以及将服务器返回的密文响应解密,明文发给burp。
如图:(图片来源:https://xz.aliyun.com/t/13218)
下游代理,MITM-downstream.py
mitmdump -p 7070 -s MITM-downstream.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure
from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow
import base64
import json
import time
import requests
from urllib.request import quote, unquote
class Mimitdownstream():
flag = 2
TargetHost = ["127.0.0.1"]
group = "new1"
def mysm2enc(self,data):
jscode = """mysm2enc111(\"{}\")""".format(data)
url = "http://localhost:12080/execjs"
data = {
"group": self.group,
"code": jscode
}
res = requests.post(url, data=data)
return json.loads(res.text)['data']
def mysm2dec(self,data):
jscode = "mysm2dec111(\"{}\")".format(data)
url = "http://localhost:12080/execjs"
data = {
"group": self.group,
"code": jscode
}
res = requests.post(url, data=data)
return json.loads(res.text)['data']
def request(self,flow):
if flow.request.host in self.TargetHost:
print("======处理下游请求======")
# 获取请求头 header
req_header = flow.request.headers
# ctx.log.info(req_header)
# 获取请求体 body
req = flow.request.get_text()
print(req)
# 修改请求头
req_json = json.loads(req)
if self.flag == 1:
req_json['new-down'] = "下游请求"
CipherText = req_json['CipherText']
# 进行JsRpc SM2解密
PlaintText = self.mysm2dec(CipherText)
ctx.log.info(PlaintText)
req_json['PlaintText'] = PlaintText
elif self.flag == 2:
# 进行JsRpc SM2解密
CipherText = req_json['CipherText']
PlaintText = self.mysm2dec(CipherText)
ctx.log.info(PlaintText)
req_json = json.loads(PlaintText)
# 处理json.dumps中文问题 ensure_ascii=False
new_req_str = json.dumps(req_json,ensure_ascii=False)
ctx.log.info(new_req_str)
# 设置修改过后的请求体
flow.request.set_text(new_req_str)
def response(self,flow):
# if '{"CipherText"' in flow.response.text:
if 1:
print("======处理下游响应======")
# 获取请求头 header
rep_header = flow.response.headers
ctx.log.info(rep_header)
# 获取请求体 body
rep = flow.response.get_text()
ctx.log.info(rep)
# 修改请求头
rep_json = {}
if self.flag == 1:
rep_json = json.loads(rep)
pass
elif self.flag == 2:
CipherText = self.mysm2enc(base64.b64encode(quote(rep).encode()).decode())
rep_json['CipherText'] = CipherText
ctx.log.info(rep_json)
# 处理json.dumps中文问题 ensure_ascii=False
new_rep_str = json.dumps(rep_json,ensure_ascii=False)
ctx.log.info(new_rep_str)
# 设置修改过后的请求体
flow.response.set_text(new_rep_str)
addons = [Mimitdownstream(),]
上游代理 MITM-upstream.py
mitmweb -p 9090 -s MITM-upstream.py --ssl-insecure
from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow
import base64
import json
import requests
from urllib.request import quote, unquote
class Mimitupstream():
flag = 2
TargetHost = ["222.190.116.142"]
group = "new1"
def mysm2enc(self,data):
jscode = """mysm2enc111(\"{}\")""".format(data)
url = "http://localhost:12080/execjs"
data = {
"group": self.group,
"code": jscode
}
res = requests.post(url, data=data)
return json.loads(res.text)['data']
def mysm2dec(self,data):
jscode = "mysm2dec111(\"{}\")".format(data)
url = "http://localhost:12080/execjs"
data = {
"group": self.group,
"code": jscode
}
res = requests.post(url, data=data)
return json.loads(res.text)['data']
def request(self,flow):
if flow.request.host in self.TargetHost:
print("======处理上游请求======")
# 获取请求头 header
req_header = flow.request.headers
ctx.log.info(req_header)
# 获取请求体 body
req = flow.request.get_text()
ctx.log.info(req)
# 修改请求头
# req_json = json.loads(req)
if self.flag == 1:
pass
elif self.flag == 2:
print("======",req,type(req))
CipherText = self.mysm2enc(base64.b64encode(quote(req).encode()).decode())
req_json = {}
req_json['CipherText'] = CipherText
# req_json['new-up'] = "上游请求"
print(req_json)
print("=======")
ctx.log.info(req_json)
# 处理json.dumps中文问题 ensure_ascii=False
new_req_str = json.dumps(req_json,ensure_ascii=False)
ctx.log.info(new_req_str)
# 设置修改过后的请求体
flow.request.set_text(new_req_str)
def response(self,flow):
if '{"CipherText"' in flow.response.text:
print("======处理上游响应======")
# 获取请求头 header
rep_header = flow.response.headers
ctx.log.info(rep_header)
# 获取请求体 body (str)
rep = flow.response.get_text()
ctx.log.info(rep)
# 修改请求头
rep_json = json.loads(rep)
if self.flag == 1:
rep_json['new-up'] = "上游响应"
pass
elif self.flag == 2:
PlaintText = self.mysm2dec(rep_json['CipherText'])
ctx.log.info(PlaintText)
rep_json = json.loads(PlaintText)
ctx.log.info(rep_json)
# 处理json.dumps中文问题 ensure_ascii=False
new_rep_str = json.dumps(rep_json,ensure_ascii=False)
ctx.log.info(new_rep_str)
# 设置修改过后的请求体
flow.response.set_text(new_rep_str)
addons = [Mimitupstream(),]
代码运行情况:
Burp显示效果:
再和之前的对比一下: