重庆大学登录密码加密逆向实战

// 实战案例:重庆大学登录密码加密逆向实战

// 网址:http://authserver.cqu.edu.cn/authserver/login

概述

本笔记分析重庆大学统一身份认证系统(authserver.cqu.edu.cn)的登录过程中密码加密的实现方式。系统使用AES-128-CBC加密算法对用户密码进行加密处理,前端JavaScript代码负责加密逻辑,而后端则进行解密验证。

逆向网页分析

1754211106305-dc17dc07-3220-4892-b17b-00948528e402.png

1754211208735-755d15ed-8f60-4983-8961-052e2275c245.png

1754211401116-68287d5b-da8b-4083-8680-463e5e30eed0.png

1754211533157-43dce7ac-a84b-4fe9-a5c3-af9224a2b411.png

1754211687909-3520b38c-8ef5-4041-b823-c0445876c0fa.png

1754211843141-0aa0ba01-9c86-47a3-bd81-4d36c0a4f07f.png

加密流程分析

1. 加密算法实现

加密过程主要使用CryptoJS库实现AES-128-CBC加密:

const CryptoJS = require("crypto-js")

// AES-128-CBC加密模式,key需要为16位,key和iv可以一样
function getAesString(data, key0, iv0) {
  // 清除key两端的空格
  key0 = key0.replace(/(^\s+)|(\s+$)/g, "");
  // 将key和iv转换为CryptoJS使用的WordArray对象
  var key = CryptoJS.enc.Utf8.parse(key0);
  var iv = CryptoJS.enc.Utf8.parse(iv0);
  // 执行AES加密
  var encrypted = CryptoJS.AES.encrypt(data, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });
  // 返回base64格式的密文
  return encrypted.toString();
}

2. 随机字符串生成

系统使用自定义字符集生成随机字符串,用于加密过程中的盐值和初始化向量(IV):

var $aes_chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
// 默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
var aes_chars_len = $aes_chars.length;

function randomString(len) {
    var retStr = '';
    for (i = 0; i < len; i++) {
        retStr += $aes_chars.charAt(Math.floor(Math.random() * aes_chars_len));
    }
    return retStr;
}

3. 密码加密主函数

function encryptAES(data, aesKey) {
    if (!aesKey) {
        return data;
    }
    // 在原始数据前添加64位随机字符串,使用16位随机字符串作为IV
    var encrypted = getAesString(randomString(64) + data, aesKey, randomString(16));
    return encrypted;
}

登录流程分析

1. 获取加密盐值

在登录页面中,服务器会返回一个名为pwdDefaultEncryptSalt的值,该值作为AES加密的密钥:

match = re.search(r'pwdDefaultEncryptSalt\s*=\s*"([^"]+)"', script.string)
if match:
    pwdDefaultEncryptSalt = match.group(1)

2. 密码加密过程

  1. 用户输入原始密码(如"12121")
  2. 前端获取pwdDefaultEncryptSalt作为加密密钥
  3. 调用encryptAES函数加密密码:
    • 在密码前添加64位随机字符串
    • 使用16位随机字符串作为IV
    • 使用AES-128-CBC模式加密
  4. 将加密结果作为password参数提交

3. Python实现示例

import execjs

# 读取JavaScript加密代码
with open("demo.js", "r", encoding="utf-8") as f:
    js_code = f.read()

# 原始密码
pw0 = "12121"
# 从页面获取的加密盐值
pwdDefaultEncryptSalt = "从HTML中提取的值"

# 调用JavaScript加密函数
enc_data = execjs.compile(js_code).call("encryptAES", pw0, pwdDefaultEncryptSalt)
print(enc_data)

请求参数分析

登录请求包含以下关键参数:

data = {
    "username": "1212",  # 用户名
    "password": "N4ePZ3ZdhfcqPvGH2/Sm2iIOz8WQo0uw4cBYMTvCBJ3ZMDPQftVMKIaA4c8aUG5zpJalQw2LsKgQEIrWKLsnL3/8+8B191aGzv6+5d/NGfk=",  # 加密后的密码
    "lt": "LT-916834-GxZTt2inatKmyt5Kq0HDKrh5kdllDa1754200439146-ZWqQ-cas",  # 登录令牌
    "dllt": "userNamePasswordLogin",  # 登录类型
    "execution": "e12s1",  # 执行标识
    "_eventId": "submit",  # 事件ID
    "rmShown": "1"  # 记住我选项
}

完整代码

import requests
from bs4 import BeautifulSoup
import re
import execjs


headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": "http://authserver.cqu.edu.cn",
    "Pragma": "no-cache",
    "Referer": "http://authserver.cqu.edu.cn/authserver/login",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
}
cookies = {
    "$JSESSIONID": "58luWz2RYVAtDPwgwzc9ceA6ktr-fY9s07sTrpBVNlUbtQb2T9oI\\u0021-2658797",
    "org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE": "zh_CN"
}
url = "http://authserver.cqu.edu.cn/authserver/login"
data = {
    "username": "1212",
    "password": "N4ePZ3ZdhfcqPvGH2/Sm2iIOz8WQo0uw4cBYMTvCBJ3ZMDPQftVMKIaA4c8aUG5zpJalQw2LsKgQEIrWKLsnL3/8+8B191aGzv6+5d/NGfk=",
    "lt": "LT-916834-GxZTt2inatKmyt5Kq0HDKrh5kdllDa1754200439146-ZWqQ-cas",
    "dllt": "userNamePasswordLogin",
    "execution": "e12s1",
    "_eventId": "submit",
    "rmShown": "1"
}
response = requests.post(url, headers=headers, cookies=cookies, data=data, verify=False)

# 解析 HTML
soup = BeautifulSoup(response.text, 'html.parser')

# 找到所有 <script> 标签
scripts = soup.find_all('script')

for script in scripts:
    # 使用正则匹配 pwdDefaultEncryptSalt 的值
    match = re.search(r'pwdDefaultEncryptSalt\s*=\s*"([^"]+)"', script.string)
    if match:
        print("提取的值:", match.group(1))
        # 密码
        pw0 = "12121"
        pwdDefaultEncryptSalt = match.group(1)
        enc_data = execjs.compile(open("demo.js", "r", encoding="utf-8").read()).call("encryptAES", pw0, pwdDefaultEncryptSalt)
        print(enc_data)
        break


const CryptoJS = require("crypto-js")

//AES-128-CBC加密模式,key需要为16位,key和iv可以一样
function getAesString(data,key0,iv0){//加密
	key0=key0.replace(/(^\s+)|(\s+$)/g, "");
	var key  = CryptoJS.enc.Utf8.parse(key0);
	var iv   = CryptoJS.enc.Utf8.parse(iv0);
	var encrypted =CryptoJS.AES.encrypt(data,key,
		{
			iv:iv,
			mode:CryptoJS.mode.CBC,
			padding:CryptoJS.pad.Pkcs7
		});
	return encrypted.toString();    //返回的是base64格式的密文
}

var $aes_chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';/****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
var aes_chars_len = $aes_chars.length;
function randomString(len) {
	var retStr = '';
	for (i = 0; i < len; i++) {
		retStr += $aes_chars.charAt(Math.floor(Math.random() * aes_chars_len));
	}
	return retStr;
}

function encryptAES(data,aesKey){ //加密
	if(!aesKey){
		return data;
	}
	var encrypted =getAesString(randomString(64)+data,aesKey,randomString(16)); //密文
	return encrypted;
}

安全注意事项

  1. 密钥管理:加密密钥pwdDefaultEncryptSalt直接暴露在客户端,降低了加密的安全性
  2. 随机性增强:通过在密码前添加随机字符串和使用随机IV,增加了每次加密结果的不同
  3. 传输安全:虽然密码被加密,但仍建议使用HTTPS协议传输敏感数据

总结

重庆大学统一身份认证系统采用前端AES加密的方式保护用户密码,主要特点包括:

  • 使用AES-128-CBC加密模式
  • 动态生成随机字符串增强安全性
  • 加密密钥由服务器动态生成
  • 每次加密结果不同(由于随机字符串和IV)