公众号登陆加密算法JS逆向
在登陆时 查看数据包发现密码字段被加密了
查看调用栈信息,找到一个执行了post方法的js文件
重点关注跟login相关的js文件 下断点进行调试
在执行这一行之前是明文密码
执行之后就变成密文
所以加密操作一定是在pwd: v(a.pwd.substr(0, 16)),这一行进行操作的,打印出v,然后跟进
发现是一个md5加密函数
接下来复制这个函数,编写js脚本
let getStr
!function(A, z, k){
"use strict";
var j;
;!(j =function(C, F, g){
function_(t, i){
var r =(t &65535)+(i &65535)
, f =(t >>16)+(i >>16)+(r >>16);
return f <<16| r &65535
}
functionD(t, i){
return t << i | t >>>32- i
}
functionR(t, i, r, f, T, O){
return_(D(_(_(i, t),_(f, O)), T), r)
}
functionS(t, i, r, f, T, O, $){
returnR(i & r |~i & f, t, i, T, O, $)
}
functiond(t, i, r, f, T, O, $){
returnR(i & f | r &~f, t, i, T, O, $)
}
functionm(t, i, r, f, T, O, $){
returnR(i ^ r ^ f, t, i, T, O, $)
}
functionv(t, i, r, f, T, O, $){
returnR(r ^(i |~f), t, i, T, O, $)
}
functiono(t, i){
t[i >>5]|=128<< i %32;
t[(i +64>>>9<<4)+14]= i;
var r, f, T, O, $, s =1732584193, c =-271733879, p =-1732584194, n =271733878;
for(r =0; r < t.length; r +=16){
f = s;
T = c;
O = p;
$ = n;
s =S(s, c, p, n, t[r],7,-680876936);
n =S(n, s, c, p, t[r +1],12,-389564586);
p =S(p, n, s, c, t[r +2],17,606105819);
c =S(c, p, n, s, t[r +3],22,-1044525330);
s =S(s, c, p, n, t[r +4],7,-176418897);
n =S(n, s, c, p, t[r +5],12,1200080426);
p =S(p, n, s, c, t[r +6],17,-1473231341);
c =S(c, p, n, s, t[r +7],22,-45705983);
s =S(s, c, p, n, t[r +8],7,1770035416);
n =S(n, s, c, p, t[r +9],12,-1958414417);
p =S(p, n, s, c, t[r +10],17,-42063);
c =S(c, p, n, s, t[r +11],22,-1990404162);
s =S(s, c, p, n, t[r +12],7,1804603682);
n =S(n, s, c, p, t[r +13],12,-40341101);
p =S(p, n, s, c, t[r +14],17,-1502002290);
c =S(c, p, n, s, t[r +15],22,1236535329);
s =d(s, c, p, n, t[r +1],5,-165796510);
n =d(n, s, c, p, t[r +6],9,-1069501632);
p =d(p, n, s, c, t[r +11],14,643717713);
c =d(c, p, n, s, t[r],20,-373897302);
s =d(s, c, p, n, t[r +5],5,-701558691);
n =d(n, s, c, p, t[r +10],9,38016083);
p =d(p, n, s, c, t[r +15],14,-660478335);
c =d(c, p, n, s, t[r +4],20,-405537848);
s =d(s, c, p, n, t[r +9],5,568446438);
n =d(n, s, c, p, t[r +14],9,-1019803690);
p =d(p, n, s, c, t[r +3],14,-187363961);
c =d(c, p, n, s, t[r +8],20,1163531501);
s =d(s, c, p, n, t[r +13],5,-1444681467);
n =d(n, s, c, p, t[r +2],9,-51403784);
p =d(p, n, s, c, t[r +7],14,1735328473);
c =d(c, p, n, s, t[r +12],20,-1926607734);
s =m(s, c, p, n, t[r +5],4,-378558);
n =m(n, s, c, p, t[r +8],11,-2022574463);
p =m(p, n, s, c, t[r +11],16,1839030562);
c =m(c, p, n, s, t[r +14],23,-35309556);
s =m(s, c, p, n, t[r +1],4,-1530992060);
n =m(n, s, c, p, t[r +4],11,1272893353);
p =m(p, n, s, c, t[r +7],16,-155497632);
c =m(c, p, n, s, t[r +10],23,-1094730640);
s =m(s, c, p, n, t[r +13],4,681279174);
n =m(n, s, c, p, t[r],11,-358537222);
p =m(p, n, s, c, t[r +3],16,-722521979);
c =m(c, p, n, s, t[r +6],23,76029189);
s =m(s, c, p, n, t[r +9],4,-640364487);
n =m(n, s, c, p, t[r +12],11,-421815835);
p =m(p, n, s, c, t[r +15],16,530742520);
c =m(c, p, n, s, t[r +2],23,-995338651);
s =v(s, c, p, n, t[r],6,-198630844);
n =v(n, s, c, p, t[r +7],10,1126891415);
p =v(p, n, s, c, t[r +14],15,-1416354905);
c =v(c, p, n, s, t[r +5],21,-57434055);
s =v(s, c, p, n, t[r +12],6,1700485571);
n =v(n, s, c, p, t[r +3],10,-1894986606);
p =v(p, n, s, c, t[r +10],15,-1051523);
c =v(c, p, n, s, t[r +1],21,-2054922799);
s =v(s, c, p, n, t[r +8],6,1873313359);
n =v(n, s, c, p, t[r +15],10,-30611744);
p =v(p, n, s, c, t[r +6],15,-1560198380);
c =v(c, p, n, s, t[r +13],21,1309151649);
s =v(s, c, p, n, t[r +4],6,-145523070);
n =v(n, s, c, p, t[r +11],10,-1120210379);
p =v(p, n, s, c, t[r +2],15,718787259);
c =v(c, p, n, s, t[r +9],21,-343485551);
s =_(s, f);
c =_(c, T);
p =_(p, O);
n =_(n, $)
}
return[s, c, p, n]
}
functionu(t){
var i, r ="";
for(i =0; i < t.length*32; i +=8){
r +=String.fromCharCode(t[i >>5]>>> i %32&255)
}
return r
}
functionb(t){
var i, r =[];
r[(t.length>>2)-1]=void0;
for(i =0; i < r.length; i +=1){
r[i]=0
}
for(i =0; i < t.length*8; i +=8){
r[i >>5]|=(t.charCodeAt(i /8)&255)<< i %32
}
return r
}
functionL(t){
returnu(o(b(t), t.length*8))
}
functionh(t, i){
var r, f =b(t), T =[], O =[], $;
T[15]= O[15]=void0;
if(f.length>16){
f =o(f, t.length*8)
}
for(r =0; r <16; r +=1){
T[r]= f[r]^909522486;
O[r]= f[r]^1549556828
}
$ =o(T.concat(b(i)),512+ i.length*8);
returnu(o(O.concat($),512+128))
}
functiony(t){
var i ="0123456789abcdef", r ="", f, T;
for(T =0; T < t.length; T +=1){
f = t.charCodeAt(T);
r += i.charAt(f >>>4&15)+ i.charAt(f &15)
}
return r
}
functionE(t){
returnunescape(encodeURIComponent(t))
}
functionI(t){
returnL(E(t))
}
functionP(t){
returny(I(t))
}
functionB(t, i){
returnh(E(t),E(i))
}
functionl(t, i){
returny(B(t, i))
}
getStr =function(t, i, r){
if(!i){
if(!r){
returnP(t)
}else{
returnI(t)
}
}
if(!r){
returnl(i, t)
}else{
returnB(i, t)
}
}
}
.call(z, k, z, A),
j !==void0&&(A.exports= j))
}(),
getStr("123")
成功调用加密。
crypto-js库
npm install crypto-js
常用加密与解密
const CryptoJS=require("crypto-js")
var str ="123"
//md5加密
console.log(CryptoJS.MD5(str).toString())
//sha加密
console.log(CryptoJS.SHA256(str).toString())
console.log(CryptoJS.SHA512(str).toString())
//base64编码
var str1 =CryptoJS.enc.Utf8.parse(str)
var enBase64 =CryptoJS.enc.Base64.stringify(str1)
console.log(enBase64)
//base64解码
var str2 =CryptoJS.enc.Base64.parse(enBase64)
var deBase64 =CryptoJS.enc.Utf8.stringify(str2)
console.log(deBase64)
//AES加解密
var key =CryptoJS.enc.Utf8.parse("1234567890ABCDEF");
var iv =CryptoJS.enc.Utf8.parse("ABCDEF1234123412");// IV 为空时需要注意实际使用中的安全性
functionEncrypt(word){
var srcs =CryptoJS.enc.Utf8.parse(word);
var encrypted =CryptoJS.AES.encrypt(srcs, key,{iv: iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});
return encrypted.ciphertext.toString().toUpperCase();// Base64 编码后的字符串
}
functionDecrypt(word){
let encryptHexStr =CryptoJS.enc.Hex.parse(word);
let srcs =CryptoJS.enc.Base64.stringify(encryptHexStr)
let decrypted =CryptoJS.AES.decrypt(srcs, key,{iv: iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});
let decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();// 已经是字符串,不需要再调用 toString()
}
// 加密
var encrypted =Encrypt("Hello, world!");
console.log("Encrypted:", encrypted);
// 解密
console.log(Decrypt(encrypted))
RSA加解密
npm install jscrypto
const NodeRSA=require('node-rsa');
// 创建一个 RSA 实例
const key =newNodeRSA({b:512});// 生成一个 512 位的密钥对
// 导出公钥和私钥
// let publicKey = key.exportKey('public');
// let privateKey = key.exportKey('private');
// console.log(publicKey)
// console.log(privateKey)
let publicKey ="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANE3dGPtzVQ3kROcSh85gyT2KiakhFpo0FUYUA2RvByeXpXHBi2sOgTxR9Ql6jjBKD86jgfmVcyFkr/HRGWqqVsCAwEAAQ=="
let privateKey ="MIIBPAIBAAJBANE3dGPtzVQ3kROcSh85gyT2KiakhFpo0FUYUA2RvByeXpXHBi2sOgTxR9Ql6jjBKD86jgfmVcyFkr/HRGWqqVsCAwEAAQJBAIwiYdJhQSwMwB7ri3ZYtm/2dotFnOVV2V12GIDOQbrEXzzE+l4Qjc4eSUift9ZpV/1CKCv7gDqcOS/5PQgBWLECIQDnutPZHzNjS11k2YczlnrOUKeq+4QI/R47o7StpV7N0wIhAOchACmmhqBAbTgf0L31OcsDdOuhzCcE7PRgJSbNRplZAiEAlVHH7OK0BEmt9qxM+KsAmy1RvVWw8PHZp2iHplUnT80CIDxCt2ckms8nXRKYAPW1/SZ4NUDGQ5Mczqb8dlNCjBipAiEA1ngFNfLcbnJdM1/k4vR47ZBd1Oq/7hSc8fUQJnKhBwA="
publicKey ="-----BEGIN PUBLIC KEY-----"+ publicKey +"-----END PUBLIC KEY-----"
privateKey ="-----BEGIN RSA PRIVATE KEY-----"+ privateKey +"-----END RSA PRIVATE KEY-----"
// RSA 加密函数
functionencryptWithRSA(plaintext, publicKey){
const key =newNodeRSA(publicKey);// 使用公钥创建 RSA 实例
const encrypted = key.encrypt(plaintext,'base64');// 加密后转为 base64 编码
return encrypted;
}
// RSA 解密函数
functiondecryptWithRSA(encryptedText, privateKey){
const key =newNodeRSA(privateKey);// 使用私钥创建 RSA 实例
const decrypted = key.decrypt(encryptedText,'utf8');// 解密后转为 UTF-8 编码
return decrypted;
}
// 示例使用
const plaintext ="Hello, this is a secret message!";
const encryptedText =encryptWithRSA(plaintext, publicKey);
console.log("加密后的文本:", encryptedText);
const decryptedText =decryptWithRSA(encryptedText, privateKey);
console.log("解密后的文本:", decryptedText);
AES解密实战
登陆框登陆发现被加密 有中文和base64
选中密码框找到name=j_password
全局搜索j_password
找到加密函数 下断点进行调试
下断点调试后发现加密方式为security+AES加密密码后base64的内容
编写aes脚本
const CryptoJS=require("crypto-js");
// AES加解密
var key =CryptoJS.enc.Utf8.parse("A3155DF345A71BBD");
var iv =CryptoJS.enc.Utf8.parse("8BC8D1DCFFF5B210");// IV 为空时需要注意实际使用中的安全性
functionEncrypt(word){
var srcs =CryptoJS.enc.Utf8.parse(word);
var encrypted =CryptoJS.AES.encrypt(srcs, key,{iv: iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});
return encrypted.toString();// 返回Base64编码后的字符串
}
functionDecrypt(word){
var decrypted =CryptoJS.AES.decrypt(word, key,{iv: iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});
var decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedStr;// 已经是字符串,不需要再调用 toString()
}
// 加密
var encrypted =Encrypt("123");
var security ="䐵匠䴵"
console.log("Encrypted:", security+encrypted);
// // 解密
// console.log("Decrypted:", Decrypt(encrypted));
解密效果
sign解密
sign
是数据包中的签名字段,用于验证数据的完整性和发送者的身份。它通过加密算法生成,确保数据在传输过程中没有被篡改。
在网站上,签名认证通常是通过以下步骤实现的:
-
1. 客户端加密:使用 JavaScript 对提交的字符串(如时间戳、随机数、API密钥等)进行加密,生成一个
sign
值。这是为了确保数据在传输过程中不会被篡改。 -
2. 提交请求:将生成的
sign
值连同其他参数(如账号和密码)一起提交到后端服务器。 -
3. 后端校验:服务器接收到请求后,通过与客户端相同的加密方法或密钥重新计算
sign
,并与客户端提交的sign
值进行对比。如果校验通过,说明数据未被篡改,服务器才会进行后续的处理,如验证账号和密码。
打卡网站进行登陆 查看数据包 发现数据包中有sign校验
sign认证不通过两次会ban IP
提交的json格式
{"username":"admin","password":"123456","timestamp":1723878761272,"sign":"92edaf40400d38c9526ace4326cbe8e6e4c39d3b"}
全局查找sign
打断点进行调试
t.data中的内容,还没有sign值
跟进Do(t.data)
jo.hex(e.join("&"))将
password=123456×tamp=1723880835581&username=admin&secret=nM26]^9{nb
传到hex函数,跟进跟进
将上面那一串内容传入r函数 ,跟进跟进
发现是一个SHA1的一个加密函数,对e也就是
password=123456×tamp=1723880835581&username=admin&secret=nM26]^9{nb
进行SHA1加密
编写脚本
const CryptoJS = require("crypto-js")
var str = "password=123456×tamp=1723881676798&username=admin&secret=nM26]^9{nb"
console.log(CryptoJS.SHA1(str).toString())
加密效果,与网站加密一样
原文始发于微信公众号(SSP安全研究):渗透测试常见加密算法JS逆向实战(一)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论