本次目标网址如下,使用base64解密获得
aHR0cHM6Ly93d3cuamRsLmNvbS9hZ2luZy1wYWdlLw==
本次的目标接口是查询物流信息,具体接口如下图
我们把整个请求curl复制下来查看接口加密参数,看一下本次需要破解哪些参数,如下
经过多次请求比对参数后,发现除一些固定参数外,有两个参数是可变的,headers中的ciphertext和data,初步确定为这两个参数,接下来我们查找参数来源
先用最基础的方法,全局搜索,我们搜索ciphertext字段,发现如下代码非常可疑,重放请求后,断点成功被断住
ciphertext和data都在这里面,data就是encrytedData,这里用到的就是基础加密模块CryptoJs和JSEncrypt,从整体加密代码上来看,秘钥和填充向量分别是h,v,AES和RAS都用到了这两个向量,那么根据逻辑分析出服务器大致解密流程,将h和v经过RAS加密后为ciphertext,服务器接收到后,解密出h和v,用这个h和v去解密由AES加密的data字段,从而解密出所传参数
接下来,用js代码来复现上述加密流程,如下:
const CryptoJS = require('crypto-js');
window = {}
const jsencrypt = require('jsencrypt')
const n = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
function generateRandomString(length) {
let result = "";
for (let i = length; i > 0; i--) {
result += n[Math.floor(Math.random() * n.length)];
}
return result;
}
function encryptRSA(key, N){
let s = new jsencrypt();
s.setPublicKey(key);
const encryptedData = s.encrypt(N)
return encryptedData
}
function get_data(r){
const requestData = r.requestData;
const pubKey = r.pubKey;
let l = "";
let d = "";
let m = "";
let f = "";
const h = generateRandomString(16);
const v = generateRandomString(16);
//h = 'ArgGVFDUAHiM6T4v'
//v = 'BBGGaEaNzP9GP3VP'
l = encryptRSA(pubKey, "".concat(h).concat(v))
m = CryptoJS.enc.Utf8.parse(h);
f = CryptoJS.enc.Utf8.parse(v);
d = CryptoJS.AES.encrypt(JSON.stringify(requestData), m, {
iv: f,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
console.log('l:', l);
console.log('d:', d);
return {l:l, d:d}
}
r = {
"requestData": [
{
"queryType": 1,
"volume": 0,
"weight": 1,
"sendTime": 1704038400000,
"sendDetailAddress": "",
"receiveDetailAddress": "",
"sendProvinceId": "1",
"sendCityId": "72",
"sendCountyId": "2819",
"receiveProvinceId": "1",
"receiveCityId": "72",
"receiveCountyId": "4137"
},
{
"client": "4",
"entrance": "JDWL-GW"
}
],
"pubKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCSp5eYB2FfHSXhzaUuHHbMfeOJp2dJ/oew7EKwzhLYfRa29d2pXm+rtN4c2HdhR+NGwm/5fY8T3entKq/7qrNBagG8R8tGl604vqteU+8Tjl4SRbQRpm0Il64ruz+xjE4NWJFtr8CWW0U6mA8yjSffSDbvqm87bsxTpHIn2frr/QIDAQAB"
}
get_data(r)
最终得到的加密字符串data和加密长度也与网站生成的一致
最后封装成python代码来执行
import requests
import execjs
jsstr = execjs.compile(open("get_data.js", "r", encoding="utf-8").read())
headers = {
'authority': 'api.jdl.com',
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN',
'access': 'JDWL-GW',
'app-key': 'jexpress',
'appparams': '{"appid":"158","ticket_type":"pc"}',
'biz-type': 'service-monitor',
'cache-control': 'no-cache',
#'ciphertext': 'Kj1wJOKfF0NHYdXWgv5jm4wQ2W1PJGF5EOQQu5pFa9EQht6ukkHu9JgFtAsmN8JH+z3BBNvBkZVhgepNBLSIss6i1WblgT1slk70HbWNICSUdu0fMO3xs8ZQksfpT4EZ6qESLdPeXd9Pseap6M2MWpKRInjkyYJwP1wEiFe6Mwc=',
'clientinfo': '{"appName":"c2c","client":"m"}',
'content-type': 'application/x-www-form-urlencoded',
# 'cookie': '__jda=236194567.1705312518399252614106.1705312518.1705312518.1705312518.1; __jdc=236194567; __jdv=236194567|baidu|-|organic|notset|1705312518400; 3AB9D23F7A4B3C9B=45GKA54BSFE7L5LKVCD6FHMHRCTWWZ3P44HGEQHRD4PBXTECCOF43V5AWYKPBZCHIUKXSUPIKICHF5NQCUIO63GORA; __jdb=236194567.2.1705312518399252614106|1.1705312518; logistics_site_lang=zh-CN',
'event-id': 'ffab5139-0b89-01cf-1afd-8a5350f065f9',
'jexpress-report-time': '1704382019497',
'jexpress-trace-id': 'e8aef0b4-44fa-3a71-9fca-1b075a4ebe55',
'lop-dn': 'jdwl.com',
'origin': 'https://www.jdl.com',
'pkid': '4095',
'pragma': 'no-cache',
'referer': 'https://www.jdl.com/',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-site',
'source-client': '4',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
}
r = {
"requestData": [
{
"queryType": 1,
"volume": 0,
"weight": 1,
"sendTime": 1704038400000,
"sendDetailAddress": "",
"receiveDetailAddress": "",
"sendProvinceId": "1",
"sendCityId": "72",
"sendCountyId": "2819",
"receiveProvinceId": "1",
"receiveCityId": "72",
"receiveCountyId": "4137"
},
{
"client": "4",
"entrance": "JDWL-GW"
}
],
"pubKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCSp5eYB2FfHSXhzaUuHHbMfeOJp2dJ/oew7EKwzhLYfRa29d2pXm+rtN4c2HdhR+NGwm/5fY8T3entKq/7qrNBagG8R8tGl604vqteU+8Tjl4SRbQRpm0Il64ruz+xjE4NWJFtr8CWW0U6mA8yjSffSDbvqm87bsxTpHIn2frr/QIDAQAB"
}
datas = jsstr.call("get_data", r)
data = datas["d"]
headers['ciphertext'] = datas["l"]
# data = 'YGEI+oYDhXEmbnhIX4zVQWrq8LTkTB9MJNUjd5pCXMcbD12W8H/YUg+WuAbZ4yg2OpA316zlUsk6hTY8ssDifW8LTWlaCktVRfwi1N1w09fox4VJqc8LrAlxwK6kDbtIYECxyL9DHQnGEtzgNwj6wMw1mWqkhkJUy9RzgtT4RN7ID1Q+yRcfANQaONFkDfRoyBtJij2EHVflCzPaSsElUDGyh91r2Dz2X3eNADVXgIlHunN77jJe/oMCsIvXf4/O8YGtGm43vDP5KRHGzkjBMVC7RSb1I9ckLXnW8+OhrJXWLipYi37Mc5Kg4cK8jvYV/+9NTKZma0NU3u1YYTY8yVDVRYtC8CfvThYmUaMKu2eJEN8KpXdmTIiLguwz9sja'
response = requests.post('https://api.jdl.com/aging/feeInquiryNewByJDL', headers=headers, data=data)
print(response)
print(response.text)