吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2288|回复: 8
收起左侧

[Web逆向] 某店登录用户名与密码参数补环境

[复制链接]
Ceciliana 发表于 2025-10-1 23:54
本帖最后由 Ceciliana 于 2025-10-2 16:08 编辑

aHR0cHM6Ly9wYXNzcG9ydC55aGQuY29tLw==



各位老师傅早上、上午、中午、下午、晚上好啊,新人贴就发一个简单补环境吧

虽然简单,但是肥肠详细

1. 抓包



我们固定 username = "12333333333",password = "123456"

试登录多次会出现滑块,手动验证吧,本篇不搞滑块

login.png

多发俩包发现,credentials.username 与 credentials.password 的长度与内容会变化,考虑非对称加密,即 RSA

2. 跟参数与扣代码



callstack.png

send.png

ajax.png

b8.png

params.png

最终确定在 `double_submit` 这一栈

扣下代码:

var JSEncryptExports = {};

(function(a6) {
    // ......
})(JSEncryptExports);

var JSEncrypt = JSEncryptExports.JSEncrypt;

var k = "12333333333";
var j = "123456";

var i = new JSEncrypt();
i.setPublicKey(pubkey);

j = i.encrypt(j);
k = i.encrypt(k);

console.log(k);
console.log(j);


直接跑,就是扑面而来的 navigator is not defined

3. 构建补环境的框架



补环境最好不要一股脑都补到源码头上,特别涉及原型链的时候,一大坨很难看,用框架思路补,清晰不易乱

本篇使用志远的开源补环境框架思路:

框架本身志远老师已经讲的很详细了,本篇仅概括一下:

- envs
    - Window.js     -> 补上的环境
    - Navigator.js
    ......
    - env.js        -> 作为环境汇总拼接

- tools
    - proxy.js         -> 工具函数
    ......
    - tool.js       -> 作为工具汇总拼接

- src.js        -> 目标源码
- main.js        -> 主入口


执行时,env.js 和 tool.js 读取 envs 和 tools 目录下的所有文本代码,与目标源码拼接成字符串,于 main.js 中使用 vm2 沙箱执行

4. 开补!


第 1 回合



万补始于 window,vm2 的全局对象使用 this,避免会检测 global

// Window.js

window = this;
window = vmProxy(window, "window"); // 套上 Proxy 代理


再补上 navigator,navigator 所在的原型链为 navigator.__proto__ -> Navigator.prototype -> Object.prototype, 简单好补

// Navigator.js

Navigator = function Navigator() {}; safefunction(Navigator);
Object.defineProperties(Navigator.prototype, { [Symbol.toStringTag]: { value: "Navigator", configurable: true } });

navigator = new Navigator();
navigator = vmProxy(navigator, "navigator");


执行看看日志

[navigator get appName]   ==> undefined
[navigator get appName]   ==> undefined
[window get crypto]   ==> undefined
[window get addEventListener]   ==> undefined
[window get attachEvent]   ==> undefined
[navigator get cajaVersion]   ==> undefined
[navigator get userAgent]   ==> undefined
[window get location]   ==> undefined
[ set window.Hex]   ==> [object Object]
[ set window.Base64]   ==> [object Object]
[ set window.ASN1]   ==> function a(h, g, i, k, j) {
            this.stream = h;
            this.header = g;
            this.length = i;
            this.tag = k;
            this.sub = j
        }

第 2 回合



把 undefined 都补上,尽量考虑原型链

// Navigator.js

Navigator.prototype = {
    appName: "Netscape",
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0'
};

// Crypto.js

Crypto = function Crypto() { }; safefunction(Crypto);
Object.defineProperties(Crypto.prototype, { [Symbol.toStringTag]: { value: "Crypto", configurable: true } });

SubtleCrypto = function SubtleCrypto() { }; safefunction(SubtleCrypto);
Object.defineProperties(SubtleCrypto.prototype, { [Symbol.toStringTag]: { value: "SubtleCrypto", configurable: true } });

Crypto.prototype.subtle = new SubtleCrypto();
crypto = new Crypto();
crypto = vmProxy(crypto, "crypto");

// Location.js

Location = function Location() {}; safefunction(Location);
Object.defineProperties(Location.prototype, { [Symbol.toStringTag]: { value: "Location", configurable: true } });

location = {
    "ancestorOrigins": {},
    "href": "https://passport.yhd.com/",
    "origin": "https://passport.yhd.com",
    "protocol": "https:",
    "host": "passport.yhd.com",
    "hostname": "passport.yhd.com",
    "port": "",
    "pathname": "/",
    "search": "",
    "hash": ""
};

Object.setPrototypeOf(location, Location.prototype);
location = vmProxy(location, "location");


事件监听器 addEventListener 传入事件类型和回调函数,事件触发时执行回调函数。addEventListener 在原型 EventTarget.prototype 上,window 完整原型链:window.__proto__ -> Window.prototype -> WindowProperties.prototype -> EventTarget.prototype -> Object.prototype

// Window.js

WindowProperties = function WindowProperties() { }; safefunction(WindowProperties);
Object.defineProperties(WindowProperties.prototype, { [Symbol.toStringTag]: { value: "WindowProperties", configurable: true } });
Object.setPrototypeOf(WindowProperties.prototype, EventTarget.prototype);
Object.defineProperty(WindowProperties.prototype, "constructor", { value: WindowProperties, writable: true, configurable: true });

Window = function Window() { }; safefunction(Window);
Object.defineProperties(Window.prototype, { [Symbol.toStringTag]: { value: "Window", configurable: true } });
Object.setPrototypeOf(Window.prototype, WindowProperties.prototype);
Object.defineProperty(Window.prototype, "constructor", { value: Window, writable: true, configurable: true });

Object.setPrototypeOf(window, Window.prototype);

// EventTarget.js

EventTarget = function EventTarget() {}; safefunction(EventTarget);
Object.defineProperties(EventTarget.prototype, { [Symbol.toStringTag]: { value: "EventTarget", configurable: true } });

Object.defineProperty(EventTarget.prototype, "_listeners",
    {
        get: function () {
            if (!this.__listeners) {
                this.__listeners = {};
            };
            return this.__listeners;
        },
        configurable: true
    }
);

EventTarget.prototype.addEventListener = function addEventListener(type, callback) {
    if (!(type in this._listeners)) {
        this._listeners[type] = [];
    }
    this._listeners[type].push(callback);   // 实际传入的回调函数我们先存着
}; safefunction(EventTarget.prototype.addEventListener);


执行看看日志

[navigator get appName]   ==> Netscape
[navigator get appName]   ==> Netscape
[window get crypto]   ==> [object Crypto]
[window get crypto]   ==> [object Crypto]
[crypto get getRandomValues]   ==> undefined
[window get addEventListener]   ==> function addEventListener() { [native code] }
[window get addEventListener]   ==> function addEventListener() { [native code] }
[window get _listeners]   ==> [object Object]
[window get _listeners]   ==> [object Object]
[window get _listeners]   ==> [object Object]
[navigator get cajaVersion]   ==> undefined
[navigator get userAgent]   ==> Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0
[window get location]   ==> [object Location]
[location get href]   ==> https://passport.yhd.com/
[ set window.Hex]   ==> [object Object]
[ set window.Base64]   ==> [object Object]
[ set window.ASN1]   ==> function a(h, g, i, k, j) {
            this.stream = h;
            this.header = g;
            this.length = i;
            this.tag = k;
            this.sub = j
        }

第 3 回合



getRandomValues 是定义在 Crypto.prototype 上的方法,传入一个 TypedArray,返回一个随机值填充的 TypedArray

// Crypto.js

Crypto.prototype.getRandomValues = function getRandomValues(array) {
    if (!ArrayBuffer.isView(array)) {
        throw new TypeError('Argument 1 of Crypto.getRandomValues is not an object of a type that is assignable to one of the allowed types');
    };

    if (array.byteLength > 65536) {
        throw new DOMException('The requested length exceeds 65,536 bytes', 'QuotaExceededError');
    };

    if (array instanceof Uint32Array) { // 本例测试只看到传入了 Uint32Array,其他类型暂时不处理
        for (let i = 0; i < array.length; i++) {
            array[i] = Math.floor(Math.random() * 4294967296);
        }
    } else {
        debugger;
    };

    return array;
}; safefunction(Crypto.prototype.getRandomValues);


执行看看日志

[navigator get appName]   ==> Netscape
[navigator get appName]   ==> Netscape
[window get crypto]   ==> [object Crypto]
[window get crypto]   ==> [object Crypto]
[crypto get getRandomValues]   ==> function getRandomValues() { [native code] }
[window get crypto]   ==> [object Crypto]
[crypto get getRandomValues]   ==> function getRandomValues() { [native code] }
[window get addEventListener]   ==> function addEventListener() { [native code] }
[window get addEventListener]   ==> function addEventListener() { [native code] }
[window get _listeners]   ==> [object Object]
[window get _listeners]   ==> [object Object]
[window get _listeners]   ==> [object Object]
[navigator get cajaVersion]   ==> undefined
[navigator get userAgent]   ==> Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0
[window get location]   ==> [object Location]
[location get href]   ==> https://passport.yhd.com/
[ set window.Hex]   ==> [object Object]
[ set window.Base64]   ==> [object Object]
[ set window.ASN1]   ==> function a(h, g, i, k, j) {
            this.stream = h;
            this.header = g;
            this.length = i;
            this.tag = k;
            this.sub = j
        }

pubkey is not defined

第 4 回合



熟悉 RSA 的老师傅已经看出来了,pubkey 是 RSA 加密公钥 publicKey,一般由服务器下发到客户端

刷新网页搜索 pubkey

pubkey.png

复制下来补上,执行出结果,总共 4 回合补齐

result.png

yhdLogin.zip (958.92 KB, 下载次数: 12)

免费评分

参与人数 8威望 +1 吾爱币 +26 热心值 +8 收起 理由
jaffa + 1 谢谢@Thanks!
allspark + 1 + 1 用心讨论,共获提升!
daxz + 1 + 1 谢谢@Thanks!
涛之雨 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
FZZZP + 1 + 1 谢谢@Thanks!
buluo533 + 1 + 1 我很赞同!
dzc999 + 1 + 1 谢谢@Thanks!
liuxuming3303 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

yycvip 发表于 2025-10-4 20:31
看来学编程要学精啊!不然太容易被破解了!
 楼主| Ceciliana 发表于 2025-10-4 22:44
yycvip 发表于 2025-10-4 20:31
看来学编程要学精啊!不然太容易被破解了!

其实这个站要真正实现接口登录,不简单的,有滑块这个大头拦着
Jiahui1022 发表于 2025-10-6 08:27
andyzhou132 发表于 2025-10-6 17:09
学习学习
fanssong 发表于 2025-10-7 11:23
Ceciliana 发表于 2025-10-4 22:44
其实这个站要真正实现接口登录,不简单的,有滑块这个大头拦着

可以多写一个ai程序,用于滑块自动滑动 嘿嘿
qq365418819 发表于 2025-10-7 21:31
谢谢分享
zxaagds2007 发表于 2025-10-8 09:34
谢谢分享
gg666 发表于 2025-11-14 15:17
补环境应该补补captchaToken这个参数 还是检测了点东西的 虽然不带貌似也没问题
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-2-17 14:25

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表