2023年5月30日超星登录加密算法分析
前言
不知道什么时候超星又修改了他的登录加密算法,研究一下,本文仅供学习交流,转载请注明出处
算法比较简单,就不慢慢下断点逆向了,直接干
正文
老规矩打开Chrome或者你电脑上一切能打开开发者工具的浏览器,输入i.chaoxing.com,来到登录页面,打开开发这工具,随便输入账号密码,这里我输入的账号是13900000000,密码是123456789,点击登录,看网络请求
可以看到,uname加密了,password也加密了,那毫无疑问uname就是手机号码,password就是密码,老规矩看一下登录按钮按下之后做了什么,右键检查按钮这个元素
可以清晰看到,当点击按钮的时候,执行了一个js方法,名为loginByPhoneAndPwd()
那我们就在刚才的网络请求那里找一下这个方法
把这个方法先拿出来分析
function loginByPhoneAndPwd(){
util.showMsg(false,"phoneMsg","",true);
util.showMsg(false,"pwdMsg","",true);
util.showMsg(false,"err-txt","");
var phone = $("#phone").val().trim();
var pwd = $("#pwd").val();
var fid = $("#fid").val();
var refer = $("#refer").val();
var forbidotherlogin = $("#forbidotherlogin").val();
if(util.isEmpty(phone)){
util.showMsg(true,"phoneMsg",please_input_phone,true);
return;
}/*else if(!util.isInterPhone(phone) && (phone.length > 50 || !util.checkEmail(phone))){
util.showMsg(true,"phoneMsg","手机号格式错误",true);
return;
}*/
if(util.isEmpty(pwd)){
util.showMsg(true,"pwdMsg",please_input_pwd,true);
return;
}
var t = $("#t").val();
if(t == "true"){
var transferKey = "u2oh6Vu^HWe4_AES";
pwd = encryptByAES(pwd, transferKey);
//pwd = $.base64.btoa(pwd,"UTF-8");
}
if(capInstance == null || $("#needVcode").val() != "1"){
//容错
loginByPhoneAndPwdSubmit();
}else{
capInstance && capInstance.popUp();
}
}
我们需要关注的是这一小段
if(t == "true"){
var transferKey = "u2oh6Vu^HWe4_AES";
pwd = encryptByAES(pwd, transferKey);
//pwd = $.base64.btoa(pwd,"UTF-8");
}
这一小段可以给出的信息是,加密密钥是transferKey
加密过程就是encryptByAES(pwd, transferKey);
老方法(就是在网络请求那里查找)查找一下对应的方法,可以找到在loginByPhoneAndPwd()
方法的上面有一个方法
function encryptByAES(message, key){
let CBCOptions = {
iv: CryptoJS.enc.Utf8.parse(key),
mode:CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
};
let aeskey = CryptoJS.enc.Utf8.parse(key);
let secretData = CryptoJS.enc.Utf8.parse(message);
let encrypted = CryptoJS.AES.encrypt(
secretData,
aeskey,
CBCOptions
);
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
这个时候我们可以抽离出来,放到IDE里,需要补一下CryptoJS的依赖,这里需要安装Node.js,这里就不废话补充了
npm i crypto-js
补充完依赖后,我们就可以新建一个js文件,然后把下面的代码放到IDE里,放心,我会解释代码的意思
const CryptoJS = require("crypto-js");
function encryptByAES(message, key) {
let CBCOptions = {
iv: CryptoJS.enc.Utf8.parse(key),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
};
let aeskey = CryptoJS.enc.Utf8.parse(key);
let secretData = CryptoJS.enc.Utf8.parse(message);
let encrypted = CryptoJS.AES.encrypt(
secretData,
aeskey,
CBCOptions
);
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
let transferKey = "u2oh6Vu^HWe4_AES", pwd = "123456789";
console.log(encryptByAES(pwd, transferKey));
第一行是引入CryptoJS的依赖
然后就是我们刚才拿到的encryptByAES
方法,原封不动
接着就是创建一个变量放密钥,这个密钥就是刚才我们找到的 u2oh6Vu^HWe4_AES
,不知道怎么来的?往上面翻翻,刚说完
接着pwd
就是模拟的密码,刚才测试的时候输入的密码是123456789,最后一行就是加密过程,不知道怎么来的?往上面翻翻,原封不动拿下来的
得出结果8La9l9FwD0SxCAYAbGmVFQ==
对比一下刚才我们通过官方加密后的结果
// 官方: 8La9l9FwD0SxCAYAbGmVFQ==
// 我们: 8La9l9FwD0SxCAYAbGmVFQ==
OK,到这里,密码加密就完毕了,但还有一个问题,手机号码,uname还没处理好,用同样的方法试试,把pwd改成13900000000试试
得出结果是96OlDUDY7HsmBfaMHg2CMg==
,而我们从官方得出的结果也是96OlDUDY7HsmBfaMHg2CMg==
,虽然如此,但我们还是得分析一波为什么
还记得我们一开始就得到的信息loginByPhoneAndPwd
方法吗,忘记了?没关系,再给你看一次
function loginByPhoneAndPwd(){
util.showMsg(false,"phoneMsg","",true);
util.showMsg(false,"pwdMsg","",true);
util.showMsg(false,"err-txt","");
var phone = $("#phone").val().trim();
var pwd = $("#pwd").val();
var fid = $("#fid").val();
var refer = $("#refer").val();
var forbidotherlogin = $("#forbidotherlogin").val();
if(util.isEmpty(phone)){
util.showMsg(true,"phoneMsg",please_input_phone,true);
return;
}/*else if(!util.isInterPhone(phone) && (phone.length > 50 || !util.checkEmail(phone))){
util.showMsg(true,"phoneMsg","手机号格式错误",true);
return;
}*/
if(util.isEmpty(pwd)){
util.showMsg(true,"pwdMsg",please_input_pwd,true);
return;
}
var t = $("#t").val();
if(t == "true"){
var transferKey = "u2oh6Vu^HWe4_AES";
pwd = encryptByAES(pwd, transferKey);
//pwd = $.base64.btoa(pwd,"UTF-8");
}
if(capInstance == null || $("#needVcode").val() != "1"){
//容错
loginByPhoneAndPwdSubmit();
}else{
capInstance && capInstance.popUp();
}
}
注意"容错"这两个字下面有一个方法loginByPhoneAndPwdSubmit()
巧合的是,我们得到的loginByPhoneAndPwd
方法下面就是loginByPhoneAndPwdSubmit
方法,可能有点绕,看图就很清晰了
还是把它拿下来看吧
function loginByPhoneAndPwdSubmit() {
let phone = $("#phone").val().trim();
let pwd = $("#pwd").val();
let fid = $("#fid").val();
let refer = $("#refer").val();
let forbidotherlogin = $("#forbidotherlogin").val();
let t = $("#t").val();
let _blank = $("#_blank").val();
let doubleFactorLogin = $("#doubleFactorLogin").val();
let independentId = $("#independentId").val();
if(t == "true"){
let transferKey = "u2oh6Vu^HWe4_AES";
pwd = encryptByAES(pwd, transferKey);
phone = encryptByAES(phone, transferKey);
}
let validate = $("#validate").val();
if(undefined == validate){
validate = "";
}
$.ajax({
url: _CP_+"/fanyalogin",
type:"post",
dataType : 'json',
data: {
'fid': fid,
'uname': phone,
'password': pwd,
'refer': refer,
't': t,
'forbidotherlogin': forbidotherlogin,
'validate': validate,
'doubleFactorLogin': doubleFactorLogin,
'independentId': independentId
},
success: function(data){
if(data.status){
let url = "";
if(isChaoxingReader()){
let path= window.location.protocol+'//' + window.location.host ;
url = path+_CP_+"/towriteother?name="+encodeURIComponent(data.name)+"&pwd="+encodeURIComponent(data.pwd)+"&refer="+data.url;
}else{
url = decodeURIComponent(data.url);
}
//跳转到双因子登录页面
if (data.containTwoFactorLogin) {
let toTwoFactorLoginPCUrl = data.twoFactorLoginPCUrl;
location.href = toTwoFactorLoginPCUrl + "&_blank=" + _blank + "&refer=" + encodeURIComponent(url);
return false;
}
if (top.location != self.location && _blank == "1") {
top.location = url;
} else {
window.location = url;
}
} else {
if (data.weakpwd) {
window.location =_CP_+ "/v11/updateweakpwd?uid=" + data.uid + "&oldpwd=" + encodeURIComponent($("#pwd").val()) + "&_blank=" + $("#_blank").val() + "&refer=" + refer;
} else {
let msg = util.isEmpty(data.msg2) ? "登录失败" : data.msg2;
msg = ("密码错误" == msg || "用户名或密码错误" == msg) ? "手机号或密码错误" : msg;
util.showMsg(true,"err-txt",msg);
}
}
}
});
}
可以注意到这三行代码
let transferKey = "u2oh6Vu^HWe4_AES";
pwd = encryptByAES(pwd, transferKey);
phone = encryptByAES(phone, transferKey);
可以得出的信息是,密钥,加密算法都是一样的,通过这样,我们就能证明刚才我们的猜想是对的
到这里,我们就完成了所有的分析,最终代码如下
const CryptoJS = require("crypto-js");
function encryptByAES(message, key) {
let CBCOptions = {
iv: CryptoJS.enc.Utf8.parse(key),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
};
let aeskey = CryptoJS.enc.Utf8.parse(key);
let secretData = CryptoJS.enc.Utf8.parse(message);
let encrypted = CryptoJS.AES.encrypt(
secretData,
aeskey,
CBCOptions
);
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
let transferKey = "u2oh6Vu^HWe4_AES", phone = "13900000000", pwd = "123456789";
console.log(`phone: ${encryptByAES(phone, transferKey)}`);
console.log(`pwd: ${encryptByAES(pwd, transferKey)}`);
版权声明:
作者:X1a0He
链接:https://www.x1a0he.com/cxnewsign_230530
来源:X1a0He's Blog
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论