1
此篇文章仅记录某次渗透测试中遇到的传输与请求包存在加密以及破解密文的过程

0x01 抓包遇加密

前几日,在公司对某单位的网站与APP进行授权渗透,在使用用户提供账号登录APP端进行抓包时,发现APP传输包与返回包均进行了加密

APP界面如下:

upload successful

bp抓包界面如下:

upload successful

为破解密文获取请求与传输包中内容,于是便对APK文件进行逆向

0x02 APP逆向寻找破解点

使用jadx 打开 APK 文件, 搜索发送加密请求接口,寻找加密方式

upload successful

upload successful

跟踪到请求接口,发现请求接口加密使用注解@Encrypt,未找到直接的请求包加密方式,在jadx中搜索Request,找到 RequestDataBuilder类

upload successful

该类中包含有请求包加密解密函数,并含有一个APP_KEY

在主管帮助下在github上获取到一个js文件

upload successful

upload successful

因该文件为js文件,且客户单位给的网站与APP同样进行了数据加密,猜测客户单位的网站应该是使用了该js文件进行传输数据加解密,于是根据该js文件尝试对客户单位网站数据加密进行破解

0x03 网站js加密破解

对该JS文件进行分析,发现使用该JS文件会发送两种类型请求,登录请求登录后发送的普通请求 , 对应函数如下:

  1. 登录请求

upload successful

  1. 登录后发送的普通请求

    upload successful

分析登录请求

登录请求会调用login,首先对登录函数login进行分析,该函数传值并调用generateKey函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 登录函数
* @param username 会员号
* @param pass 密码
*/
export function login(username, pass, resultfunc) {
generateKey(username,
function(obj) {
dologin(obj, username, pass, resultfunc);
},
function(info) {
resultfunc(false, info);
});
}
/*
* 在这个login函数中传入username变量和两个function函数到generateKey函数中
* 因为在JavaScript中函数是第一公民,所以可以作为变量传递
*/

login函数传参到generateKey函数后,分析generateKey函数逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 发送请求到服务端,进行秘钥的产生,产生的秘钥包括RSA密钥对,和进行秘钥交换通讯的会话秘钥
* @param tjid
* @param successfunc
* @param errorfunc
*/

function generateKey(tjid, successfunc, errorfunc) {
$.ajax({
type: "get",
url: nctUrl + "/gen/key",
data: {
"tjid": tjid
},
dataType: "json",
success: function(obj) {
successfunc(obj);
},
error: function(req, info) {
errorfunc(info);
}
});
}
/*
* generateKey函数通过get请求向接口 /gen/key 发起请求,传入参数为tjid
* tjid参数其实就是登录网站时输入的用户名
* 如果请求成功, 则调用第一个传入generateKey函数的函数,就是调用dologin函数
* 如果请求失败, 则调用第二个传入generateKey函数,就是resultfunc函数
*/
// resultfunc函数其实也是传入的一个函数变量,猜测传入的函数应该为failfunc函数
// 该函数作用其实就是alert一下错误信息,如下
function failfunc(info) {
alert(info);
}

// 总结一下, generateKey函数的作用就是拿用户输入的用户名去跟服务器请求会话秘钥
// 如果成功调用dologin函数, 如果失败alert弹出错误信息

调用 /gen/key 接口如下

upload successful

upload successful

如果tjid存在,也就是用户名存在,则请求成功,获取到服务器返回的 ssps两个值。
当generateKey函数发起请求成功后,则调用dologin函数,下面查看dologin函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/***
* 执行登录
* @param obj
* @param username
* @param pass
*/
function dologin(obj, username, pass, resultfunc) {
if (obj.code == 1) {
var sessionkey = obj.data.ss;
$.ajax({
url: nctUrl + "/login",
type: "post",
data: {
"username": username,
"userpass": pass,
"publickey": obj.data.ps
},
dataType: "json",
beforeSend: function(xhr) {
addHeaders(xhr);
},
error: function(xhr, info) {
resultfunc(false, info);
},
success: function(obj) {
if (obj.code == 1) {
var secretkey = obj.data.secretkey;
var cryptedInfo = obj.data.info;
decryptSecretKey(username, sessionkey, secretkey, function(retObj) {
if (retObj.code == 1) {
sessionKey = decodeBase64AndDecryptWith3Des(sessionkey, retObj.data);
var decoded = decodeBase64(cryptedInfo);
var plainInfo = decodeBase64AndDecryptWith3Des(produceSessionKey(sessionKey), decoded);
var plainObj = JSON.parse(plainInfo);
sessionId = plainObj.sessionid;
$.cookie("sessionKey", sessionKey);
$.cookie("sessionId", sessionId);
// $("#content1").val("sessionid:" + sessionId + " sessionKey:" + sessionKey);
resultfunc(true, "登录成功!", plainInfo);
} else {
resultfunc(false, retObj.msg);
}
}, function(info) {
resultfunc(false, info);
});
} else {
resultfunc(false, obj.msg);
}
}
});
} else {
resultfunc(false, obj.msg);
}
}
/*
* dologin函数首先将之前请求获取到的ss值存储到sessionKey变量中,
* 之后向 /login 接口发送POST请求,请求中带有username、password以及之前获取到的ps值(作为publicKey参数)
* 如果请求成功,则从返回数据包中获取secretKey和info
* 之后调用decryptSecretKey函数对secretKey进行解密,解密成功后操作如下:
* 1. 对sessionKey值(注意是sessionKey,不是secretKey,sessionKey就是之前请求返回的ss)加密,处理后存储到浏览器cookie中
* 2. 对info(info值存储到变量cryptedInfo中,因此解密使用该变量名)进行解密,解密后获取sessionId存储到cookie中
* 3. 页面alert登录成功信息
* 另外如果dologin函数请求失败,也就是登录失败,则alert错误信息
*/

请求获得secretKey如下:
upload successful

上面dologin函数解密用到的decryptSecretKey函数分析如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 对服务端返回的secretKey进行解密的decryptSecretKey函数
/**
* 对服务端返回的secretKey进行解密,目前通过与服务端交互实现
* @param secretKey
*/
function decryptSecretKey(tjid, sessionkey, secretKey, succcessfunc, failfunc) {
var crypted = encryptWith3DesAndEncodeBase64(sessionkey, secretKey);
$.ajax({
type: "get",
url: nctUrl + "/gen/unc",
data: {
tjid: tjid,
crypted: crypted
},
dataType: "json",
success: function(obj) {
succcessfunc(obj);
},
error: function(xhr, info) {
failfunc(info);
}
});
}
/*
* 该函数首先使用加密函数encryptWith3DesAndEncodeBase64,将sessionKey(此时sessionKey还未进行处理,值还是之前的服务端返回的ss的值)和secreteKey进行加密,加密后的结果赋值给crypted变量
* 之后向 /gen/unc 接口发送POST请求,请求参数是tjid(用户输入的用户名)和上面加密得到的crypted
* 如果请求成功,服务端会返回一个data参数,并进行后续操作,也就是上面dologin函数分析的decryptSecretKey函数解密成功后的操作
* 如果请求失败,则alert失败信息
*/

请求解密secretKey如下:
upload successful

其他加解密函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
* 用3des加密,结果采用base64编码返回
* @param key
* @param plainText
* @returns {*}
*/
function encryptWith3DesAndEncodeBase64(key, plainText) {
if (key == null || key == '' || plainText == null || plainText == '') {
return '';
}
var ckey = produce3DesKey(key);
var result = CryptoJS.TripleDES.encrypt(plainText, CryptoJS.enc.Utf8.parse(ckey), {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return result.toString();
}

var secretSeed = "123456789012345678901234";
function produce3DesKey(key) {
if (key == undefined || key == null || key == '')
return secretSeed;
if (key.length >= 24) {
return key.substr(0, 24);
}
return key + secretSeed.substr(key.length);
}

/**
* 进行base64解码
* @param bs64
* @returns {*}
*/
function decodeBase64(bs64) {
var decoded = CryptoJS.enc.Utf8.stringify(CryptoJS.enc.Base64.parse(bs64));
return decoded;
}

/**
* 进行base64编码
* @param
* @returns {*}
*/
function encodeBase64(str) {
var encoded = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str));
return encoded;
}

/**
* 进行3des解密,解密之前,会将密文进行base64解码
* @param key
* @param cryptedBs64
* @returns {*}
*/
function decodeBase64AndDecryptWith3Des(key, cryptedBs64) {
if (key == null || key == '' || cryptedBs64 == null || cryptedBs64 == '') {
return '';
}
var ckey = produce3DesKey(key);
var result = CryptoJS.TripleDES.decrypt(
cryptedBs64, CryptoJS.enc.Utf8.parse(ckey), {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return result.toString(CryptoJS.enc.Utf8)
}

至此登录请求过程已经分析完成,流程如下:

  • 用户输入账号和密码,之后浏览器携带用户输入的账号向服务端/gen/key接口发起请求,如果用户输入的账号存在,则服务器返回 ss 和 ps参数
  • 浏览器携带用户输入的账号、密码以及上面请求返回的ps向服务端 /login 接口发起请求,如果信息正确,服务端返回secretKey和info参数
  • 浏览器对ss和secretKey合并加密,获取到新内容crypted,浏览器携带用户输入的账号和crypted向服务端/gen/unc接口发起请求对secretKey进行解密,解密成功后返回data参数,之后对ss进行处理,处理后的值作为sessionKey存储到浏览器cookie中,同时浏览器对之前返回的info进行解密,解密后获取到sessionId,sessionId也存储到浏览器中

下面分析第二种请求,登录后发送的普通请求

登录进web系统后浏览器向服务端请求数据都是使用该请求,该请求本质是调用函数sendRequest,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* 发送请求到服务端
* @param url
* @param params
* @param successfunc
* @param failfunc
*/
export function sendRequest(url, params, successfunc, failfunc, $this) {
var crypted = "";
var pstr = JSON.stringify(params);
var sessionKey = $.cookie("sessionKey");
var sessionId = $.cookie("sessionId");
if (pstr != "{}") {
crypted = encodeBase64(encryptWith3DesAndEncodeBase64(produceSessionKey(sessionKey), pstr));
}
$.ajax({
url: url,
type: "post",
data: crypted,
dataType: "json",
contentType: "application/json",
xhrFields: {
withCredentials: true
},
crossDomain: true,
beforeSend: function(xhr) {
addHeaders(xhr);
//发送业务请求时,需要进行签名
var timestamp = parseInt(new Date().getTime() / 1000);
var random = randomString(8);
var sign = produceSign(sessionId, timestamp, random, crypted);
xhr.setRequestHeader("sessionid", sessionId);
xhr.setRequestHeader("timestamp", timestamp);
xhr.setRequestHeader("random", random);
xhr.setRequestHeader("sign", sign);
},
error: function(xhr, info) {
failfunc(info);
$this.$Message.error({
content: info,
duration: 3,
closable: true
})
},
success: function(obj) {
if (obj.code == 1) {
var data = obj.data;
if (data) {
var decoded = decodeBase64(data);
var plainText = decodeBase64AndDecryptWith3Des(produceSessionKey(sessionKey), decoded);
var plainObj = JSON.parse(plainText);
successfunc(plainObj);
} else {
successfunc(obj);
}
} else {
failfunc(obj);
$this.$Message.error({
content: obj.msg,
duration: 3,
closable: true
})
}
}
});
}
/*
* 该请求主要分为两部分,请求前数据加密和请求后数据解密
* 请求前数据加密:
* 1. 从cookie中取出sessionKey,进行处理
* 2. 将处理后的seesionKey同要加密的数据一起通过encryptWith3DesAndEncodeBase64函数进行加密,加密后* 在进行一次base64编码,编码后的结果发送到服务器
* 请求后数据解密:
* 1. 从cookie中取出sessionKey,进行处理
* 2. 对服务端返回的结果进行base64解码,之后将处理后的sessionKey和解码后的数据一同通过调用
* decodeBase64AndDecryptWith3Des函数进行解密
*/

// 对sessionKey进行处理的函数如下
function produceSessionKey(key) {
return CryptoJS.MD5(APP_KEY_SEED + key).toString().toUpperCase();
}

至此登录后发送的普通请求过程分析完成,通过对以上两种类型请求过程分析,并通过使用该js文件中提供的加解密函数写出请求的加解密脚本(脚本为js脚本,可通过node调用运行),如下:

获取SeesionKey脚本, 该脚本获取的sessionKey是放置到cookie中的sessionKey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const CryptoJS = require('crypto-js')

var secretSeed = "123456789012345678901234";

function decodeBase64AndDecryptWith3Des(key, cryptedBs64) {
if (key == null || key == '' || cryptedBs64 == null || cryptedBs64 == '') {
return '';
}
var ckey = produce3DesKey(key);

var result = CryptoJS.TripleDES.decrypt(
cryptedBs64, CryptoJS.enc.Utf8.parse(ckey), {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return result.toString(CryptoJS.enc.Utf8)
}

function produce3DesKey(key) {
if (key == undefined || key == null || key == '')
return secretSeed;
if (key.length >= 24) {
return key.substr(0, 24);
}
return key + secretSeed.substr(key.length);
}

var ss = ""; // 请求/gen/key接口返回的ss
var data = ""; // 请求 /gen/unc 接口返回的data
console.log(decodeBase64AndDecryptWith3Des(ss, data));

加密数据包脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const CryptoJS = require('crypto-js')

var secretSeed = "123456789012345678901234";
var APP_KEY_SEED = "terjoycht2014!@#";
/**
* 用3des加密,结果采用base64编码返回
* @param key
* @param plainText
* @returns {*}
*/
function encryptWith3DesAndEncodeBase64(key, plainText) {
if (key == null || key == '' || plainText == null || plainText == '') {
return '';
}
var ckey = produce3DesKey(key);
var result = CryptoJS.TripleDES.encrypt(plainText, CryptoJS.enc.Utf8.parse(ckey), {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return result.toString();
}
/**
* 进行base64编码
* @param
* @returns {*}
*/
function encodeBase64(str) {
var encoded = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str));
return encoded;
}

function produce3DesKey(key) {
if (key == undefined || key == null || key == '')
return secretSeed;
if (key.length >= 24) {
return key.substr(0, 24);
}
return key + secretSeed.substr(key.length);
}

function produceSessionKey(key) {
return CryptoJS.MD5(APP_KEY_SEED + key).toString().toUpperCase();
}
var sessionKey = ''; // 浏览器cookie中的sessionKey

pstr = ''; // 浏览器发送的需要加密的数据
crypted = encodeBase64(encryptWith3DesAndEncodeBase64(produceSessionKey(sessionKey), pstr));
console.log(crypted)

解密数据包脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const CryptoJS = require('crypto-js')

var APP_KEY_SEED = "terjoycht2014!@#";
var secretSeed = "123456789012345678901234";

function decodeBase64AndDecryptWith3Des(key, cryptedBs64) {
if (key == null || key == '' || cryptedBs64 == null || cryptedBs64 == '') {
return '';
}
var ckey = produce3DesKey(key);
var result = CryptoJS.TripleDES.decrypt(
cryptedBs64, CryptoJS.enc.Utf8.parse(ckey), {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return result.toString(CryptoJS.enc.Utf8)
}
/**
* 进行base64解码
* @param bs64
* @returns {*}
*/
function decodeBase64(bs64) {
var decoded = CryptoJS.enc.Utf8.stringify(CryptoJS.enc.Base64.parse(bs64));
return decoded;
}

function produceSessionKey(key) {
return CryptoJS.MD5(APP_KEY_SEED + key).toString().toUpperCase();
}


function produce3DesKey(key) {
if (key == undefined || key == null || key == '')
return secretSeed;
if (key.length >= 24) {
return key.substr(0, 24);
}
return key + secretSeed.substr(key.length);
}

sessionKey = ""; // 存储在浏览器Cookie中的sessionKey
let data = ""; // 要解密的数据,可以是请求包,也可以是服务端返回包的数据
let crypted = decodeBase64AndDecryptWith3Des(produceSessionKey(sessionKey), decodeBase64(data));

console.log(crypted);

脚本使用对数据进行加解密如下:

  1. 获取sessionKey

upload successful

  1. 数据解密

upload successful

upload successful

upload successful

  1. 数据加密(对上面解密出的请求包进行加密,确认加密效果一致)

upload successful

至此已完成数据包的加解密,当准备进行渗透测试时,发现只要修改数据包,服务端就会返回401错误

upload successful

然后问了主管,发现请求包中存在签名sign,还需要修改数据包签名,于是查看js中的签名函数,编写生成签名脚本

签名函数如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/***
* 根据给出的数据产生签名
* @param sessionid
* @param timestamp
* @param random
* @param crypted 加密之后的请求参数
* @returns {string}
*/
function produceSign(sessionid, timestamp, random, crypted) {
var arr = new Array();
arr.push("sessionid=" + sessionid);
arr.push("apptype=" + APP_TYPE);
arr.push("iversion=" + APP_IVERSION);
arr.push("versioncode=" + APP_VERSION);
if (crypted != "")
arr.push("data=" + crypted);
arr.push("timestamp=" + timestamp);
arr.push("random=" + random);
arr.push("secretkey=" + produceSessionKey($.cookie("sessionKey")));
arr.sort();
var signString = "[" + arr.join() + "]";
return CryptoJS.MD5(signString).toString().toUpperCase();
}

签名脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const CryptoJS = require('crypto-js')

var APP_KEY_SEED = "xxxxxxxxxxxxx";
var APP_TYPE = "20";
var APP_VERSION = "388";
var APP_IVERSION = "2";


/***
* 根据给出的数据产生签名
* @param sessionid
* @param timestamp
* @param random
* @param crypted 加密之后的请求参数
* @returns {string}
*/
function produceSign(sessionid, timestamp, random, crypted) {
var arr = new Array();
arr.push("sessionid=" + sessionid);
arr.push("apptype=" + APP_TYPE);
arr.push("iversion=" + APP_IVERSION);
arr.push("versioncode=" + APP_VERSION);
if (crypted != "")
arr.push("data=" + crypted);
arr.push("timestamp=" + timestamp);
arr.push("random=" + random);
arr.push("secretkey=" + produceSessionKey(sessionKey));
arr.sort();
var signString = "[" + arr.join() + "]";
return CryptoJS.MD5(signString).toString().toUpperCase();

}

function produceSessionKey(key) {
return CryptoJS.MD5(APP_KEY_SEED + key).toString().toUpperCase();
}

var sessionId = ""; // 请求头中的sessionId
var sessionKey = ""; // 浏览器Cookie中的sessionKey
var timestamp = ""; // 请求包中的 timestamp
var random = ""; // 请求包中random
var crypted = ""; // 加密后的请求数据
let sign = produceSign(sessionId,
timestamp,
random,
crypted)

console.log(sign)

但是用编写的签名脚本生成签名后,服务端依旧返回401

upload successful

感觉哪里不对,于是对最初的请求进行计算签名,查看是否和请求中的签名一致

upload successful

生成的签名为B1576578C9D96654E7FBF961907DD6B6, 原始请求签名为B467D7093028A1B4E9BB97492B76EF9F,两者
并不一致,猜测该网站开发人员修改了签名中的部分配置参数,为了找寻修改后的配置参数,于是进行chrome debug

0x04 chrome debug 进行签名破解

首先进入后台,之后打开chrome开发人员工具,在Sources菜单处,找到页面js源代码位置,因为该网站对源代码进行了打包,因此js文件分为app , mainfest 和 vendor这三类,只用查看app的js文件即可,app的js文件为该网站开发人员的开发代码打包后的文件,另外需要点击pretty-print,方便调试

upload successful

之后找到一处可控的查询位置处,点击查询

upload successful

抓包,获取请求接口

upload successful

在js源代码中搜索该接口,因查询到该接口有4处,于是在该4处全打上断点

upload successful

打上断点后,再一次点击查询,chrome debug开始

upload successful

调试跟踪找到签名函数调用位置后,在签名函数的调用位置打上断点,然后点击Resume script excution

upload successful

取消之前接口处的4个断点,仅留该签名函数处的断点,重新点击查询,chrome debug开始
点击箭头处,深入到函数执行内部

upload successful

两个箭头搭配使用

upload successful

upload successful

寻找到全局参数的不同点,即开发人员将APP_TYPE 这个参数从之前的js文件中的20修改为了42

之后修改签名脚本中的该参数,调用签名脚本获取签名,并和之前请求包中的签名进行比对,结果一致,成功获取签名,改包之后也可生成新的签名,成功发包

upload successful

upload successful

修改后签名脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const CryptoJS = require('crypto-js')

var APP_KEY_SEED = "xxxxxxxxxxxxx";
var APP_TYPE = "42";
var APP_VERSION = "388";
var APP_IVERSION = "2";

/***
* 根据给出的数据产生签名
* @param sessionid
* @param timestamp
* @param random
* @param crypted 加密之后的请求参数
* @returns {string}
*/
function produceSign(sessionid, timestamp, random, crypted) {
var arr = new Array();
arr.push("sessionid=" + sessionid);
arr.push("apptype=" + APP_TYPE);
arr.push("iversion=" + APP_IVERSION);
arr.push("versioncode=" + APP_VERSION);
if (crypted != "")
arr.push("data=" + crypted);
arr.push("timestamp=" + timestamp);
arr.push("random=" + random);
arr.push("secretkey=" + produceSessionKey(sessionKey));
arr.sort();
var signString = "[" + arr.join() + "]";
return CryptoJS.MD5(signString).toString().toUpperCase();

}

function produceSessionKey(key) {
return CryptoJS.MD5(APP_KEY_SEED + key).toString().toUpperCase();
}

var sessionId = ""; // 请求头中的sessionId
var sessionKey = ""; // 浏览器Cookie中的sessionKey
var timestamp = ""; // 请求包中的 timestamp
var random = ""; // 请求包中random
var crypted = ""; // 加密后的请求数据
let sign = produceSign(sessionId,
timestamp,
random,
crypted)

console.log(sign)

0x05 后记

这里主要记录写这篇文章复盘时的一些新发现

  • 因为sessionKey是存储在cookie中的,因此不用特意写脚本获取,可以直接在浏览器的cookie中找到sessionKey
    upload successful
  • 在复盘的时候抓包,突然发现apptype这个值在某些请求包中自带了,不需要特意通过chrome debug获取
    upload successful