目录
encrypt-labs这种简单的场景本身用cloudx这些插件是很容易过的,但jsrpc会更通用,演示一下
首先注册全局函数
https://github.com/jxhczhl/JsRpc/blob/main/resouces/JsEnv_Dev.js
var rpc_client_id, Hlclient = function (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 () {
if (this.wsURL.indexOf("clientId=") === -1 && rpc_client_id) {
this.wsURL += "&clientId=" + rpc_client_id
}
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("请求信息解析错误", requestJson);
return
}
if (result["registerId"]) {
rpc_client_id = result['registerId']
return
}
if (!result['action'] || !result["message_id"]) {
console.warn('没有方法或者消息id,不处理');
return
}
var action = result["action"], message_id = result["message_id"]
var theHandler = this.handlers[action];
if (!theHandler) {
this.sendResult(action, message_id, 'action没找到');
return
}
try {
if (!result["param"]) {
const async_result = theHandler(function (response) {
_this.sendResult(action, message_id, response);
})
if (async_result && typeof async_result.then === "function") {
async_result.catch(e => {
_this.sendResult(action, message_id, "" + e);
});
}
return
}
var param = result["param"]
try {
param = JSON.parse(param)
} catch (e) {
}
theHandler(function (response) {
_this.sendResult(action, message_id, response);
}, param)
} catch (e) {
console.log("error: " + e);
_this.sendResult(action, message_id, "" + e);
}
}
Hlclient.prototype.sendResult = function (action, message_id, e) {
if (typeof e === 'object' && e !== null) {
try {
e = JSON.stringify(e)
} catch (v) {
console.log(v)//不是json无需操作
}
}
this.send(JSON.stringify({"action": action, "message_id": message_id, "response_data": e}));
}

启动jsrpc服务端

【第一关】AES固定key

注入,resolve里的部分照抄原js就行
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=encryptaes");
demo.regAction("encryptest", function (resolve, param) {
// 先加密,然后对结果进行URL编码
const encrypted = CryptoJS.AES.encrypt(param, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
const encodedResult = encodeURIComponent(encrypted);
resolve(encodedResult);
});

注意一下传的参数

对应的去写一下mitmproxy的脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
from urllib.parse import parse_qs
def encrypt(data):
url = "http://127.0.0.1:12080/go"
params = {
"group": "encryptaes",
"action": "encryptest",
"param": data
}
response = requests.get(url, params=params)
enctext = response.json()['data']
return enctext
class dataencrypt:
def request(self, flow: mitmproxy.http.HTTPFlow):
target_path = "/encrypt/aes.php"
if (flow.request.method == "POST" and
flow.request.path == target_path):
try:
if "encryptedData=" in flow.request.text:
body_params = parse_qs(flow.request.text)
encrypted_data_str = body_params.get('encryptedData', [''])[0]
json_with_quotes = json.dumps(encrypted_data_str)
encrypted_result = encrypt(json_with_quotes)
new_body = f"encryptedData={encrypted_result}"
flow.request.text = new_body
except Exception:
pass
addons = [dataencrypt()]
mitmproxy -p 9090 -s test1.py

设置bp上游代理

修改下前端发包逻辑

这样就可以抓到原始数据包

走的是全局的代理,直接赢了

也可以直接走intruder

【第二关】AES服务端获取key
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=encryptaes2");
demo.regAction("encryptest2", function (resolve, param) {
const encrypted = CryptoJS.AES.encrypt(param, aesKey, {
iv: aesIv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
.toString();
resolve(encrypted);
});

稍微改下mitmproxy脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
from urllib.parse import parse_qs
def encrypt(data):
url = "http://127.0.0.1:12080/go"
params = {
"group": "encryptaes2",
"action": "encryptest2",
"param": data
}
response = requests.get(url, params=params)
enctext = response.json()['data']
return enctext
class dataencrypt:
def request(self, flow: mitmproxy.http.HTTPFlow):
target_path = "/encrypt/aesserver.php"
if (flow.request.method == "POST" and
flow.request.path == target_path):
try:
try:
req_json = json.loads(flow.request.text)
except Exception:
req_json = {}
if "encryptedData" in req_json:
encrypted_data_str = req_json.get('encryptedData', '')
json_with_quotes = json.dumps(encrypted_data_str)
encrypted_result = encrypt(json_with_quotes)
req_json['encryptedData'] = encrypted_result
flow.request.text = json.dumps(req_json)
except Exception:
pass
addons = [dataencrypt()]
还是改下前端发包,直接bp拦截到明文


【第三关】RSA加密

var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=encryptrsa");
demo.regAction("encryptrsa", function (resolve, param) {
const encrypted = encryptor.encrypt(param);
resolve(encrypted);
});
改下发包

改下mitmproxy脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
def encrypt(data):
url = "http://127.0.0.1:12080/go"
params = {
"group": "encryptrsa",
"action": "encryptrsa",
"param": data
}
try:
response = requests.get(url, params=params)
if response.status_code == 200:
res_json = response.json()
if 'data' in res_json:
return res_json['data']
except Exception as e:
ctx.log.error(f"Encryption failed: {e}")
return None
class encrypt_rsa:
def request(self, flow: mitmproxy.http.HTTPFlow):
target_path = "/encrypt/rsa.php"
if flow.request.path == target_path and flow.request.method == "POST":
if "data" in flow.request.urlencoded_form:
data_val = flow.request.urlencoded_form["data"]
json_data = json.dumps(data_val)
encrypted = encrypt(json_data)
if encrypted:
flow.request.urlencoded_form["data"] = encrypted
ctx.log.info(f"Encrypted data for {target_path}")
addons = [encrypt_rsa()]

【第四关】AES+Rsa加密
插入hook

var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=encryptaesrsa");
demo.regAction("encryptaesrsa", function (resolve, param) {
const jsonData = param;
const key = CryptoJS.lib.WordArray.random(16);
const iv = CryptoJS.lib.WordArray.random(16);
const encryptedData = CryptoJS.AES.encrypt(jsonData, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
const rsa = new JSEncrypt();
rsa.setPublicKey(`-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
ocDbsNeCwNpRxwjIdQIDAQAB
-----END PUBLIC KEY-----`);
const encryptedKey = rsa.encrypt(key.toString(CryptoJS.enc.Base64));
const encryptedIv = rsa.encrypt(iv.toString(CryptoJS.enc.Base64));
const result = {
encryptedData: encryptedData,
encryptedKey: encryptedKey,
encryptedIv: encryptedIv
};
resolve(JSON.stringify(result));
});

mitmproxy脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
def encrypt_aes_rsa(data_json_str):
url = "http://127.0.0.1:12080/go"
params = {
"group": "encryptaesrsa",
"action": "encryptaesrsa",
"param": data_json_str
}
try:
response = requests.get(url, params=params)
if response.status_code == 200:
res_json = response.json()
if 'data' in res_json:
return json.loads(res_json['data'])
except Exception as e:
ctx.log.error(f"Encryption failed: {e}")
return None
class encrypt_aes_rsa_addon:
def request(self, flow: mitmproxy.http.HTTPFlow):
if flow.request.method == "POST" and "encryptedKey" in flow.request.text:
try:
ctx.log.info("Detected AES+RSA encrypted request")
try:
req_json = json.loads(flow.request.text)
except Exception:
req_json = {}
if "encryptedData" in req_json:
payload_to_encrypt = req_json['encryptedData']
if not isinstance(payload_to_encrypt, str):
payload_to_encrypt = json.dumps(payload_to_encrypt)
payload_with_quotes = json.dumps(payload_to_encrypt)
encrypted_package = encrypt_aes_rsa(payload_with_quotes)
if encrypted_package:
req_json['encryptedData'] = encrypted_package['encryptedData']
req_json['encryptedKey'] = encrypted_package['encryptedKey']
req_json['encryptedIv'] = encrypted_package['encryptedIv']
flow.request.text = json.dumps(req_json)
ctx.log.info(f"Successfully re-encrypted data using payload: {payload_to_encrypt}")
except Exception as e:
ctx.log.error(f"Error processing request: {e}")
addons = [encrypt_aes_rsa_addon()]

【第五关】Des规律Key
hook
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=encryptdes");
demo.regAction("encryptdes", function (resolve, param) {
var data = JSON.parse(param);
var username = data.username;
var password = data.password;
const key = CryptoJS.enc.Utf8.parse(username.slice(0, 8)
.padEnd(8, '6'));
const iv = CryptoJS.enc.Utf8.parse('9999' + username.slice(0, 4)
.padEnd(4, '9'));
const encryptedPassword = CryptoJS.DES.encrypt(password, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
const encryptedHex = encryptedPassword.ciphertext.toString(CryptoJS.enc.Hex);
resolve(encryptedHex);
});

改一下mitmproxy脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
def encrypt_des(username, password):
url = "http://127.0.0.1:12080/go"
data = {
"username": username,
"password": password
}
params = {
"group": "encryptdes",
"action": "encryptdes",
"param": json.dumps(json.dumps(data))
}
try:
response = requests.get(url, params=params)
if response.status_code == 200:
res_json = response.json()
if 'data' in res_json:
return res_json['data']
except Exception as e:
ctx.log.error(f"Encryption failed: {e}")
return None
class encrypt_des_addon:
def request(self, flow: mitmproxy.http.HTTPFlow):
if flow.request.method == "POST":
try:
try:
req_json = json.loads(flow.request.text)
except:
return
if "username" in req_json and "password" in req_json:
username = req_json['username']
password = req_json['password']
ctx.log.info(f"Intercepted plaintext password for user: {username}")
encrypted_password = encrypt_des(username, password)
if encrypted_password:
req_json['password'] = encrypted_password
flow.request.text = json.dumps(req_json)
ctx.log.info(f"Replaced password with DES ciphertext: {encrypted_password}")
except Exception as e:
ctx.log.error(f"Error processing request: {e}")
addons = [encrypt_des_addon()]

【第六关】明文加签
hook
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=encryptsign");
demo.regAction("encryptsign", function (resolve, param) {
var data = JSON.parse(param);
var username = data.username;
var password = data.password;
const nonce = Math.random().toString(36).substring(2);
const timestamp = Math.floor(Date.now() / 1000);
const secretKey = "be56e057f20f883e";
const dataToSign = username + password + nonce + timestamp;
const signature = CryptoJS.HmacSHA256(dataToSign, secretKey).toString(CryptoJS.enc.Hex);
const result = {
username: username,
password: password,
nonce: nonce,
timestamp: timestamp,
signature: signature
};
resolve(JSON.stringify(result));
});

mitmproxy脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
def encrypt_sign(username, password):
url = "http://127.0.0.1:12080/go"
data = {
"username": username,
"password": password
}
params = {
"group": "encryptsign",
"action": "encryptsign",
"param": json.dumps(json.dumps(data))
}
try:
response = requests.get(url, params=params)
if response.status_code == 200:
res_json = response.json()
if 'data' in res_json:
return json.loads(res_json['data'])
except Exception as e:
ctx.log.error(f"Encryption failed: {e}")
return None
class encrypt_sign_addon:
def request(self, flow: mitmproxy.http.HTTPFlow):
target_path = "/encrypt/signdata.php"
if flow.request.path == target_path and flow.request.method == "POST":
try:
try:
req_json = json.loads(flow.request.text)
except:
return
if "username" in req_json and "password" in req_json and "signature" not in req_json:
username = req_json['username']
password = req_json['password']
ctx.log.info(f"Intercepted unsigned request for user: {username}")
signed_data = encrypt_sign(username, password)
if signed_data:
flow.request.text = json.dumps(signed_data)
ctx.log.info(f"Replaced request with signed payload: {signed_data}")
except Exception as e:
ctx.log.error(f"Error processing request: {e}")
addons = [encrypt_sign_addon()]

【第七关】加签key在服务端
hook
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=encryptserver");
demo.regAction("encryptserver", function (resolve, param) {
var data = JSON.parse(param);
var username = data.username;
var password = data.password;
const timestamp = Math.floor(Date.now() / 1000);
const signatureUrl = "/encrypt/get-signature.php";
fetch(signatureUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: username,
password: password,
timestamp: timestamp,
}),
})
.then(response => response.json())
.then(signData => {
if (signData.signature) {
const result = {
username: username,
password: password,
timestamp: timestamp,
signature: signData.signature
};
resolve(JSON.stringify(result));
} else {
resolve(JSON.stringify({ error: "Failed to get signature" }));
}
})
.catch(error => {
console.error("JSRPC signature fetch error:", error);
resolve(JSON.stringify({ error: error.toString() }));
});
});

mitmproxy脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
def encrypt_server_sign(username, password):
url = "http://127.0.0.1:12080/go"
data = {
"username": username,
"password": password
}
params = {
"group": "encryptserver",
"action": "encryptserver",
"param": json.dumps(json.dumps(data))
}
try:
response = requests.get(url, params=params)
if response.status_code == 200:
res_json = response.json()
if 'data' in res_json:
return json.loads(res_json['data'])
except Exception as e:
ctx.log.error(f"Encryption failed: {e}")
return None
class encrypt_server_addon:
def request(self, flow: mitmproxy.http.HTTPFlow):
target_path = "/encrypt/signdataserver.php"
if flow.request.path == target_path and flow.request.method == "POST":
try:
try:
req_json = json.loads(flow.request.text)
except:
return
if "username" in req_json and "password" in req_json and "signature" not in req_json:
username = req_json['username']
password = req_json['password']
ctx.log.info(f"Intercepted unsigned request for user: {username}")
signed_data = encrypt_server_sign(username, password)
if signed_data:
if "error" in signed_data:
ctx.log.error(f"JSRPC Error: {signed_data['error']}")
else:
flow.request.text = json.dumps(signed_data)
ctx.log.info(f"Replaced request with server-side signed payload")
except Exception as e:
ctx.log.error(f"Error processing request: {e}")
addons = [encrypt_server_addon()]

【第八关】禁止重放
hook
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=encryptrandom");
demo.regAction("encryptrandom", function (resolve, param) {
var data = JSON.parse(param);
var username = data.username;
var password = data.password;
const timestamp = Date.now();
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
ocDbsNeCwNpRxwjIdQIDAQAB
-----END PUBLIC KEY-----`;
function rsaEncrypt(data, key) {
const jsEncrypt = new JSEncrypt();
jsEncrypt.setPublicKey(key);
const encrypted = jsEncrypt.encrypt(data.toString());
return encrypted;
}
let encryptedTimestamp;
try {
encryptedTimestamp = rsaEncrypt(timestamp, publicKey);
if (!encryptedTimestamp) {
resolve(JSON.stringify({ error: "RSA encryption failed" }));
return;
}
} catch (error) {
resolve(JSON.stringify({ error: error.toString() }));
return;
}
const result = {
username: username,
password: password,
random: encryptedTimestamp
};
resolve(JSON.stringify(result));
});

mitmproxy脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
def encrypt_random(username, password):
url = "http://127.0.0.1:12080/go"
data = {
"username": username,
"password": password
}
params = {
"group": "encryptrandom",
"action": "encryptrandom",
"param": json.dumps(json.dumps(data))
}
try:
response = requests.get(url, params=params, timeout=10)
if response.status_code == 200:
res_json = response.json()
if 'data' in res_json:
# JS 返回的是一个 JSON 字符串,需要解析为字典
return json.loads(res_json['data'])
except Exception as e:
ctx.log.error(f"Encryption failed: {e}")
return None
class encrypt_random_addon:
def request(self, flow: mitmproxy.http.HTTPFlow):
if flow.request.method == "POST":
ctx.log.info(f"Checking request: {flow.request.path}")
target_path = "/encrypt/norepeater.php"
if flow.request.path == target_path and flow.request.method == "POST":
ctx.log.info(f"Target matched: {target_path}")
try:
try:
req_json = json.loads(flow.request.text)
ctx.log.info(f"JSON parsed successfully: {req_json}")
except Exception as e:
ctx.log.warn(f"JSON parse failed: {e}")
return
has_username = "username" in req_json
has_password = "password" in req_json
no_random = "random" not in req_json
ctx.log.info(f"Conditions - User: {has_username}, Pass: {has_password}, NoRandom: {no_random}")
if has_username and has_password and no_random:
username = req_json['username']
password = req_json['password']
ctx.log.info(f"Intercepted request without random field for user: {username}")
encrypted_data = encrypt_random(username, password)
if encrypted_data:
if "error" in encrypted_data:
ctx.log.error(f"JSRPC Error: {encrypted_data['error']}")
else:
flow.request.text = json.dumps(encrypted_data)
ctx.log.info(f"Replaced request with payload containing encrypted timestamp")
except Exception as e:
ctx.log.error(f"Error processing request: {e}")
addons = [encrypt_random_addon()]
