在挖src中如何利用mitmproxy代理实现自动化加解密,我们通过编写2个脚本一个上游,一个下游。
如图所示,图中的实现步骤如下:浏览器发送加密数据-->下游(do.py)代理实现请求解密-->burp接收明文请求体-->上游(up.py)代理加密请求体-->服务器接收加密请求体-->服务器返回加密响应体-->上游(up.py)代理解密响应体-->burp接收明文响应体-->下游(do.py)代理加密响应体-->浏览器接收加密响应体
下面开始实战
查看请求内容发现加密数据包,加密值为encryptdata
通过断点确认加密函数new p.a(e).encryptData_ECB(o()(t.data)),跳转js查看加密过程
把获取加密函数和解密函数把函数趴下来保存
运行发现缺少h()函数在js搜索
在js中添加h()
接着找m()函数,记得要看函数调用的参数脚本中m(t.sk, e)调用了2个参数,而且这个m函数也需要传两个参数,所以可以确认就是调用的这个函数
添加到本地js脚本中
接着添加u()函数
在把脚本中encryptData_ECB函数里面Object(a.b)补全
通过断点获取调用的参数
获取到e.b函数
添加到本地js脚本中改调用参数名称
在修改加密的调用方式
decryptData_ECB参数也是一样,后面的参数也是一样在js里面搜索然后慢慢补全即可,这里在不赘述
完整js脚本des.js如下
const base64js = require('base64-js');
aa = function aa(t) {
this.seckey = t;
this.encryptData_ECB = function(t) {
var e, i = new h;
i.isPadding = !0,
i.mode = 1;
try {
if (null == this.seckey)
throw new Error("key 不规范");
e = a1(this.seckey)
} catch (t) {
throw new Error(t.message)
}
(function(t, e) {
if (void 0 == t) throw new Error("ctx is null!");
if (void 0 == e || 16 !== e.length) throw new Error("key error!");
t.mode = 1,
m(t.sk, e)
})(i, e);
var r = B(i, a1(t));
var n = base64js.fromByteArray(r);
if (n) {
n = n.replace(/(\s*|\t|\r|\n)/g, "")
.replace(/=/g, "!")
.replace(/\+/g, "@");
}
return n;
};
this.decryptData_ECB = function(t) {
try {
var e = new h;
e.isPadding = !0,
e.mode = 0;
t = t.replace(/!/g, "=").replace(/@/g, "+");
var i = a1(this.seckey);
(function(t, e) {
if (null == t) throw new Error("ctx is null!");
if (null == e || 16 !== e.length) throw new Error("key error!");
t.mode = 0,
m(t.sk, e),
t.sk = t.sk.reverse();
})(e, i);
var r = B(e, base64js.toByteArray(t));
return a1(r); // 修复:直接调用d2处理结果
} catch (t) {
console.error("Decryption error:", t);
return null;
}
};
}
;
function h() {
this.mode = 1,
this.sk = new Array(32),
this.isPadding = !0
}
function u(t, e) {
return (255 & t[e]) << 24 | (255 & t[e + 1]) << 16 | (255 & t[e + 2]) << 8 | 255 & t[e + 3]
}
function c(t, e, i) {
e[i] = 255 & t >> 24,
e[i + 1] = 255 & t >> 16,
e[i + 2] = 255 & t >> 8,
e[i + 3] = 255 & t
}
function p(t, e) {
return function(t, e) {
return t << e
}(t, e) | t >> 32 - e
}
var F = [214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 20, 194, 40, 251, 44, 5, 43, 103, 154, 118, 42, 190, 4, 195, 170, 68, 19, 38, 73, 134, 6, 153, 156, 66, 80, 244, 145, 239, 152, 122, 51, 84, 11, 67, 237, 207, 172, 98, 228, 179, 28, 169, 201, 8, 232, 149, 128, 223, 148, 250, 117, 143, 63, 166, 71, 7, 167, 252, 243, 115, 23, 186, 131, 89, 60, 25, 230, 133, 79, 168, 104, 107, 129, 178, 113, 100, 218, 139, 248, 235, 15, 75, 112, 86, 157, 53, 30, 36, 14, 94, 99, 88, 209, 162, 37, 34, 124, 59, 1, 33, 120, 135, 212, 0, 70, 87, 159, 211, 39, 82, 76, 54, 2, 231, 160, 196, 200, 158, 234, 191, 138, 210, 64, 199, 56, 181, 163, 247, 242, 206, 249, 97, 21, 161, 224, 174, 93, 164, 155, 52, 26, 85, 173, 147, 50, 48, 245, 140, 177, 227, 29, 246, 226, 46, 130, 102, 202, 96, 192, 41, 35, 171, 13, 83, 78, 111, 213, 219, 55, 69, 222, 253, 142, 47, 3, 255, 106, 114, 109, 108, 91, 81, 141, 27, 175, 146, 187, 221, 188, 127, 17, 217, 92, 65, 31, 16, 90, 216, 10, 193, 49, 136, 165, 205, 123, 189, 45, 116, 208, 18, 184, 229, 180, 176, 137, 105, 151, 74, 12, 150, 119, 126, 101, 185, 241, 9, 197, 110, 198, 132, 24, 240, 125, 236, 58, 220, 77, 32, 121, 238, 95, 62, 215, 203, 57, 72]
, f = [462357, 472066609, 943670861, 1415275113, 1886879365, 2358483617, 2830087869, 3301692121, 3773296373, 4228057617, 404694573, 876298825, 1347903077, 1819507329, 2291111581, 2762715833, 3234320085, 3705924337, 4177462797, 337322537, 808926789, 1280531041, 1752135293, 2223739545, 2695343797, 3166948049, 3638552301, 4110090761, 269950501, 741554753, 1213159005, 1684763257]
, l = [2746333894, 1453994832, 1736282519, 2993693404];
function g(t) {
return F[255 & t]
}
function d(t, e, i, r, n) {
return t ^ (s = e ^ i ^ r ^ n,
a = new Array(4),
h = new Array(4),
c(s, a, 0),
h[0] = g(a[0]),
h[1] = g(a[1]),
h[2] = g(a[2]),
h[3] = g(a[3]),
(o = u(h, 0)) ^ p(o, 2) ^ p(o, 10) ^ p(o, 18) ^ p(o, 24));
var s, o, a, h
}
function m(t, e) {
var i, r, n, s, o = new Array(4), a = new Array(36), h = 0;
for (o[0] = u(e, 0),
o[1] = u(e, 4),
o[2] = u(e, 8),
o[3] = u(e, 12),
a[0] = o[0] ^ l[0],
a[1] = o[1] ^ l[1],
a[2] = o[2] ^ l[2],
a[3] = o[3] ^ l[3]; h < 32; h++)
a[h + 4] = a[h] ^ (i = a[h + 1] ^ a[h + 2] ^ a[h + 3] ^ f[h],
r = void 0,
void 0,
s = void 0,
n = new Array(4),
s = new Array(4),
c(i, n, 0),
s[0] = g(n[0]),
s[1] = g(n[1]),
s[2] = g(n[2]),
s[3] = g(n[3]),
(r = u(s, 0)) ^ p(r, 13) ^ p(r, 23)),
t[h] = a[h + 4]
}
function y(t, e, i) {
var r = 0
, n = new Array(36);
for (n[0] = u(e, 0),
n[1] = u(e, 4),
n[2] = u(e, 8),
n[3] = u(e, 12); r < 32; )
n[r + 4] = d(n[r], n[r + 1], n[r + 2], n[r + 3], t[r]),
r++;
c(n[35], i, 0),
c(n[34], i, 4),
c(n[33], i, 8),
c(n[32], i, 12)
}
function v(t, e) {
if (void 0 == t) return null;
var i = [];
if ((i = i.concat(t)), 1 == e) {
// 加密时填充
var r = 16 - (t.length % 16);
for (var n = 0; n < r; n++) i.push(r);
} else {
// 解密时移除填充
var r = t[t.length - 1];
for (var n = 0; n < r; n++) i.pop();
}
return i;
}
function B(t, e) {
null == e | "" == e && Error("input is null!"),
t.isPadding && 1 == t.mode && (e = v(e, 1));
for (var i = e.length, r = [], n = 0; n < i; n += 16) {
var s = []
, o = [];
s.push(e[n + 0], e[n + 1], e[n + 2], e[n + 3], e[n + 4], e[n + 5], e[n + 6], e[n + 7], e[n + 8], e[n + 9], e[n + 10], e[n + 11], e[n + 12], e[n + 13], e[n + 14], e[n + 15]),
y(t.sk, s, o),
r = r.concat(o)
}
return t.isPadding && 0 == t.mode && (r = v(r, 0)),
r
}
a1 = function(t) {
if (typeof t === "string") return d2(t);
if (!t || typeof t.length === 'undefined') throw new Error("Invalid input");
let e = "";
for (let r = 0; r < t.length; r++) {
let n = t[r].toString(2).padStart(8, '0');
let s = n.match(/^1+?(?=0)/);
if (s && n.length === 8) {
let o = s[0].length;
let a = n.slice(o + 1);
for (let h = 1; h < o; h++) {
a += t[r + h].toString(2).padStart(8, '0').slice(2);
}
e += String.fromCharCode(parseInt(a, 2));
r += o - 1;
} else {
e += String.fromCharCode(t[r]);
}
}
return e;
};
d2 = function(t) {
var e, i, r = new Array;
e = t.length;
for (var n = 0; n < e; n++)
(i = t.charCodeAt(n)) >= 65536 && i <= 1114111 ? (r.push(i >> 18 & 7 | 240),
r.push(i >> 12 & 63 | 128),
r.push(i >> 6 & 63 | 128),
r.push(63 & i | 128)) : i >= 2048 && i <= 65535 ? (r.push(i >> 12 & 15 | 224),
r.push(i >> 6 & 63 | 128),
r.push(63 & i | 128)) : i >= 128 && i <= 2047 ? (r.push(i >> 6 & 31 | 192),
r.push(63 & i | 128)) : r.push(255 & i);
return r
}
module.exports = {
aa: aa,
enc: function(t) {
var a = new aa("43pejo2xwy9h3pse");
return a.encryptData_ECB(t);
},
dec: function(t) {
var a = new aa("43pejo2xwy9h3pse");
return a.decryptData_ECB(t);
}
};
在通过test.js加载des.js尝试加密和解密
test.js代码如下
const dec1 = require('./dec.js');
function dec(t){
return dec1.dec(t);
}
function enc(t){
return dec1.enc(t);
}
console.log(enc("aaa"))
console.log(dec("T527tpbYYkHQKDuQFSvDFw!!"))
回过头来发现this.seckey是随机生成的
通过l()函数随机生成16位
这里我们直接修改js固定key值方便后面的脚本调用,点击替换内容选择任意目录
输入16位固定key
之后在dec.js脚本中固定key即可
接下就是编写up.py上游脚本代码如下
import json
import execjs
from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
with open("dec.js","r",encoding="utf-8") as f:
js =f.read()
js =execjs.compile(js)
#请求体加密
def request(flow: HTTPFlow):
if "/gateway/" in flow.request.url:
data = json.loads(flow.request.get_text())
ctx.log.info(data)
encrypt_text = data['encryptdata'] # 直接获取字符串值
decrypt_text = js.call('enc', encrypt_text) # 假设应为解密,可能函数名应改为'dec'
ctx.log.info(decrypt_text)
data['encryptdata'] = decrypt_text
flow.request.content = json.dumps(data).encode()
#响应体解密
def response(flow: HTTPFlow):
if "/gateway/" in flow.request.url:
# 注意:响应处理应使用flow.response而非flow.request
data = json.loads(flow.response.get_text())
encrypt_text = data['encryptdata'] # 直接获取字符串值
ctx.log.info(encrypt_text)
decrypt_text = js.call('dec', encrypt_text)
data['encryptdata'] = decrypt_text
flow.response.content = json.dumps(data, ensure_ascii=False).encode()
通过mitmdump执行上游脚本mitmdump -p 9090 -s up.py --ssl-insecure
接着就是编写下游脚本do.py代码如下
import json
import execjs
from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
with open("test.js","r",encoding="utf-8") as f:
js =f.read()
js =execjs.compile(js)
#请求体解密
def request(flow: HTTPFlow):
if "/gateway/" in flow.request.url:
data = json.loads(flow.request.get_text())
encrypt_text = data['encryptdata'] # 直接获取字符串值
decrypt_text = js.call('dec', encrypt_text) # 假设应为解密,可能函数名应改为'dec'
data['encryptdata'] = decrypt_text
flow.request.content = json.dumps(data).encode()
#响应体加密
def response(flow: HTTPFlow):
if "/gateway/" in flow.request.url:
data = json.loads(flow.response.get_text())
encrypt_text = data['encryptdata'] # 直接获取字符串值
decrypt_text = js.call('enc', encrypt_text)
data['encryptdata'] = decrypt_text
flow.response.content = json.dumps(data, ensure_ascii=False).encode()
通过mitmdump执行下游脚本mitmdump -q -p 9091 -s do.py --mode upstream:http://127.0.0.1:8080/ --ssl-insecure
在浏览器中挂着下游代理
在burp中挂着上游代理
解密前
解密后