极验滑块分析+雪球网登录相关分析

最近朋友有个业务里多了个滑块,于是找到我想把原本的自动化改改,那就绕不开这个极验了,说到极验,这可能是我的心魔,半年前啥也不会的时候头铁花了5天把极验的协议复现出来了,但是就是不给通过,那段时间有阴影了,后面又尝试了一次,还是以失败告终,以至于后来看到这玩意就绕道,宁愿去分析ali都不愿意去看极验(我个人的感觉是顶象数美易盾啥的比这简单多了,可能真是有阴影了哈哈哈😂),不过这次我没退缩,花了几个小时硬着头皮给他过了(也算是打破心魔了),我这篇博客主要记录我面对这次心魔的一些坑点

目标网址

看标题自己找了

流程分析

先触发整个流程看看效果
在这里插入图片描述

箭头指出来的都是和这个登录有关的请求,每一步都要完善。虽然半年前就知道了极验的w好像只有最后一个轨迹的会校验其他的置空写死都可以,但由于是面对心魔,所以我秉着每一步都排查仔细,参数全都要生成的原则来写这个流程。

gee_test/get

第一步没啥好说的,直接模拟拿到结果 challenge,gt,xq_geetest

gettype.php

第二步也要模拟,别看他不返回有用的东西就不做,也很简单

第一个get.php

这第一个php的 负载里面的gt和challenge用前面返回的,这个w值我也模拟了,先定位到加密值,过程就不说了,直接看内容
在这里插入图片描述
w值由 i + r 组成的,把代码全部拿下来,然后补上环境,我是一点一点补的,没有用jsdom,补了20多分钟,很头铁。然后把r的生成函数导出和i生成有关的函数都导出,可以拿到第一个w值,如图

在这里插入图片描述
然后迎来第一个坑点了,r的生成函数里面依赖了一个随机数,o的生成也依赖了一个随机数,这两个随机数一定要相同的,如果不相同,那这个接口返回就一直是 param error, 这边直接写死
在这里插入图片描述
无论是r的生成还是o的生成,随机数都是一致的生成的w值才是正确的,然后返回的c值和s值都存下来,后面有用

第一个ajax.php

首先这个接口是必须要的,因为你别看他只返回了一个slide,看起来对你后面没什么帮助,但是这个接口你不做的话,后面的会拿不到结果。那这个w要做吗? 很坑,这是第二个坑点,我一开始是直接写死,能返回结果,但是最后一步验证可就别想过去了,排查半天只能给他完善。所以这个第二个w值是一定要做的,一样的,直接看内容,怎么跟的就不赘述了,太繁杂了

在这里插入图片描述

可以看到是对一个r和一个随机数加密,这个随机数依旧写死,和前面一样,来看看这个r

{
    "lang": "zh-cn",
    "type": "fullpage",
    "tt": "Mm(*(f(H1((YM((",
    "light": -1,
    "s": "c7c3e21112fe4f741921cb3e4ff9f7cb",
    "h": "321f9af1e098233dbd03f250fd2b5e21",
    "hh": "39bd9cad9e425c3a8f51610fd506e3b3",
    "hi": "09eb21b3ae9542a9bc1e8b63b3d9a467",
    "vip_order": -1,
    "ct": -1,
    "ep": {
        "v": "9.1.9-cyhomb",
        "$_Ei": false,
        "me": true,
        "ven": "Google Inc. (NVIDIA)",
        "ren": "ANGLE (NVIDIA, NVIDIA T1000 8GB (0x00001FF0) Direct3D11 vs_5_0 ps_5_0, D3D11)",
        "fp": null,
        "lp": null,
        "em": {
            "ph": 0,
            "cp": 0,
            "ek": "11",
            "wd": 1,
            "nt": 0,
            "si": 0,
            "sc": 0
        },
        "tm": {
            "a": 1745744494557,
            "b": 0,
            "c": 0,
            "d": 0,
            "e": 0,
            "f": 1745744494566,
            "g": 1745744494584,
            "h": 1745744494584,
            "i": 1745744494584,
            "j": 1745744494653,
            "k": 1745744494614,
            "l": 1745744494653,
            "m": 1745744494831,
            "n": 1745744494901,
            "o": 1745744494835,
            "p": 1745744495717,
            "q": 1745744495717,
            "r": 1745744495720,
            "s": 1745744755658,
            "t": 1745744755658,
            "u": 1745744755659
        },
        "dnf": "dnf",
        "by": 2
    },
    "passtime": 1068463,
    "rp": "6506528540e6617c70194a710295e16f",
    "captcha_token": "1938544055",
    "ydue": "hfoj0glb"
}

这里只有rp需要模拟生成,其他的都可以定值,看看rp怎么生成的,藏的好深,我找了有一会才找到
在这里插入图片描述
rp就藏在这个a数组里面,直接定义的,拉老长了
在这里插入图片描述
就像这样的一个定义,可以看到rp是用了 G(gt + challenge + pastime ),经过验证这个函数是标准的md5加密,那么这第二个w也可以得出了

在这里插入图片描述
这个rp我是在外面生成的,passtime就被我写死了

第二个get.php

ok,这第二个get.php并没有什么加密的值,直接拿到结果,把图片都下载下来,并且更新一下challenge和gt和c和s的值,拿到的图片自己还原一下,这里就不讲了

第二个ajax.php

到最后一个验证的w值了,步骤都是一样,全拿下来,导出该导出的函数,然后调用,这里资料大把,就不说还原了,讲讲坑点
在这里插入图片描述
拿下来都可以直接用的,唯一需要注意的还是那个随机值,又是这玩意,直接写死,别给他机会
在这里插入图片描述

在这里插入图片描述

h个u的生成都会依赖这个随机值,一定要一样,然后还有传入gt,challenge的时候也要传对来,是更新后的才行。

login

验证通过后拿到一个validate,然后会发现加密了账号密码等值

在这里插入图片描述
全局一搜,断住,发现是个sm4加密,我直接扣下来用了
在这里插入图片描述

window = global
function xx(op) {
    const n = [214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 20, 194, 40, 251, 44, 5, 43, 103, 154, 118, 42, 190, 4, 195, 170, 68, 19, 38, 73, 134, 6, 153, 156, 66, 80, 244, 145, 239, 152, 122, 51, 84, 11, 67, 237, 207, 172, 98, 228, 179, 28, 169, 201, 8, 232, 149, 128, 223, 148, 250, 117, 143, 63, 166, 71, 7, 167, 252, 243, 115, 23, 186, 131, 89, 60, 25, 230, 133, 79, 168, 104, 107, 129, 178, 113, 100, 218, 139, 248, 235, 15, 75, 112, 86, 157, 53, 30, 36, 14, 94, 99, 88, 209, 162, 37, 34, 124, 59, 1, 33, 120, 135, 212, 0, 70, 87, 159, 211, 39, 82, 76, 54, 2, 231, 160, 196, 200, 158, 234, 191, 138, 210, 64, 199, 56, 181, 163, 247, 242, 206, 249, 97, 21, 161, 224, 174, 93, 164, 155, 52, 26, 85, 173, 147, 50, 48, 245, 140, 177, 227, 29, 246, 226, 46, 130, 102, 202, 96, 192, 41, 35, 171, 13, 83, 78, 111, 213, 219, 55, 69, 222, 253, 142, 47, 3, 255, 106, 114, 109, 108, 91, 81, 141, 27, 175, 146, 187, 221, 188, 127, 17, 217, 92, 65, 31, 16, 90, 216, 10, 193, 49, 136, 165, 205, 123, 189, 45, 116, 208, 18, 184, 229, 180, 176, 137, 105, 151, 74, 12, 150, 119, 126, 101, 185, 241, 9, 197, 110, 198, 132, 24, 240, 125, 236, 58, 220, 77, 32, 121, 238, 95, 62, 215, 203, 57, 72]
        ,
        r = [462357, 472066609, 943670861, 1415275113, 1886879365, 2358483617, 2830087869, 3301692121, 3773296373, 4228057617, 404694573, 876298825, 1347903077, 1819507329, 2291111581, 2762715833, 3234320085, 3705924337, 4177462797, 337322537, 808926789, 1280531041, 1752135293, 2223739545, 2695343797, 3166948049, 3638552301, 4110090761, 269950501, 741554753, 1213159005, 1684763257];

    function o(e) {
        const t = [];
        for (let n = 0, r = e.length; n < r; n += 2)
            t.push(parseInt(e.substr(n, 2), 16));
        return t
    }

    function i(e, t) {
        const n = 31 & t;
        return e << n | e >>> 32 - n
    }

    function a(e) {
        return (255 & n[e >>> 24 & 255]) << 24 | (255 & n[e >>> 16 & 255]) << 16 | (255 & n[e >>> 8 & 255]) << 8 | 255 & n[255 & e]
    }

    function s(e) {
        return e ^ i(e, 2) ^ i(e, 10) ^ i(e, 18) ^ i(e, 24)
    }

    function u(e) {
        return e ^ i(e, 13) ^ i(e, 23)
    }

    function c(e, t, n) {
        const r = new Array(4)
            , o = new Array(4);
        for (let t = 0; t < 4; t++)
            o[0] = 255 & e[4 * t],
                o[1] = 255 & e[4 * t + 1],
                o[2] = 255 & e[4 * t + 2],
                o[3] = 255 & e[4 * t + 3],
                r[t] = o[0] << 24 | o[1] << 16 | o[2] << 8 | o[3];
        for (let e, t = 0; t < 32; t += 4)
            e = r[1] ^ r[2] ^ r[3] ^ n[t + 0],
                r[0] ^= s(a(e)),
                e = r[2] ^ r[3] ^ r[0] ^ n[t + 1],
                r[1] ^= s(a(e)),
                e = r[3] ^ r[0] ^ r[1] ^ n[t + 2],
                r[2] ^= s(a(e)),
                e = r[0] ^ r[1] ^ r[2] ^ n[t + 3],
                r[3] ^= s(a(e));
        for (let e = 0; e < 16; e += 4)
            t[e] = r[3 - e / 4] >>> 24 & 255,
                t[e + 1] = r[3 - e / 4] >>> 16 & 255,
                t[e + 2] = r[3 - e / 4] >>> 8 & 255,
                t[e + 3] = 255 & r[3 - e / 4]
    }

    function l(e, t, n, {padding: i = "pkcs#7", mode: s = "cbc", iv: l, output: f = "string"} = {}) {
        if ("cbc" === s && (void 0 === l && (l = t),
        "string" == typeof l && (l = o(l)),
        16 !== l.length))
            throw new Error("iv is invalid");
        if ("string" == typeof t && (t = o(t)),
        16 !== t.length)
            throw new Error("key is invalid");
        if (e = "string" == typeof e ? 0 !== n ? function (e) {
            const t = [];
            for (let n = 0, r = e.length; n < r; n++) {
                const r = e.codePointAt(n);
                if (r <= 127)
                    t.push(r);
                else if (r <= 2047)
                    t.push(192 | r >>> 6),
                        t.push(128 | 63 & r);
                else if (r <= 55295 || r >= 57344 && r <= 65535)
                    t.push(224 | r >>> 12),
                        t.push(128 | r >>> 6 & 63),
                        t.push(128 | 63 & r);
                else {
                    if (!(r >= 65536 && r <= 1114111))
                        throw t.push(r),
                            new Error("input is not supported");
                    n++,
                        t.push(240 | r >>> 18 & 28),
                        t.push(128 | r >>> 12 & 63),
                        t.push(128 | r >>> 6 & 63),
                        t.push(128 | 63 & r)
                }
            }
            return t
        }(e) : o(e) : [...e],
        ("pkcs#5" === i || "pkcs#7" === i) && 0 !== n) {
            const t = 16 - e.length % 16;
            for (let n = 0; n < t; n++)
                e.push(t)
        }
        const d = new Array(32);
        !function (e, t, n) {
            const o = new Array(4)
                , i = new Array(4);
            for (let t = 0; t < 4; t++)
                i[0] = 255 & e[0 + 4 * t],
                    i[1] = 255 & e[1 + 4 * t],
                    i[2] = 255 & e[2 + 4 * t],
                    i[3] = 255 & e[3 + 4 * t],
                    o[t] = i[0] << 24 | i[1] << 16 | i[2] << 8 | i[3];
            o[0] ^= 2746333894,
                o[1] ^= 1453994832,
                o[2] ^= 1736282519,
                o[3] ^= 2993693404;
            for (let e, n = 0; n < 32; n += 4)
                e = o[1] ^ o[2] ^ o[3] ^ r[n + 0],
                    t[n + 0] = o[0] ^= u(a(e)),
                    e = o[2] ^ o[3] ^ o[0] ^ r[n + 1],
                    t[n + 1] = o[1] ^= u(a(e)),
                    e = o[3] ^ o[0] ^ o[1] ^ r[n + 2],
                    t[n + 2] = o[2] ^= u(a(e)),
                    e = o[0] ^ o[1] ^ o[2] ^ r[n + 3],
                    t[n + 3] = o[3] ^= u(a(e));
            if (0 === n)
                for (let e, n = 0; n < 16; n++)
                    e = t[n],
                        t[n] = t[31 - n],
                        t[31 - n] = e
        }(t, d, n);
        const p = [];
        let h = l
            , m = e.length
            , v = 0;
        for (; m >= 16;) {
            const t = e.slice(v, v + 16)
                , r = new Array(16);
            if ("cbc" === s)
                for (let e = 0; e < 16; e++)
                    0 !== n && (t[e] ^= h[e]);
            c(t, r, d);
            for (let e = 0; e < 16; e++)
                "cbc" === s && 0 === n && (r[e] ^= h[e]),
                    p[v + e] = r[e];
            "cbc" === s && (h = 0 !== n ? r : t),
                m -= 16,
                v += 16
        }
        if (("pkcs#5" === i || "pkcs#7" === i) && 0 === n) {
            const e = p.length
                , t = p[e - 1];
            for (let n = 1; n <= t; n++)
                if (p[e - n] !== t)
                    throw new Error("padding is invalid");
            p.splice(e - t, t)
        }
        return "array" !== f ? 0 !== n ? p.map(e => 1 === (e = e.toString(16)).length ? "0" + e : e).join("") : function (e) {
            const t = [];
            for (let n = 0, r = e.length; n < r; n++)
                e[n] >= 240 && e[n] <= 247 ? (t.push(String.fromCodePoint(((7 & e[n]) << 18) + ((63 & e[n + 1]) << 12) + ((63 & e[n + 2]) << 6) + (63 & e[n + 3]))),
                    n += 3) : e[n] >= 224 && e[n] <= 239 ? (t.push(String.fromCodePoint(((15 & e[n]) << 12) + ((63 & e[n + 1]) << 6) + (63 & e[n + 2]))),
                    n += 2) : e[n] >= 192 && e[n] <= 223 ? (t.push(String.fromCodePoint(((31 & e[n]) << 6) + (63 & e[n + 1]))),
                    n++) : t.push(String.fromCodePoint(e[n]));
            return t.join("")
        }(p) : p
    }

    return op.exports = {
        encrypt: (e, t, n) => l(e, t, 1, n),
        decrypt: (e, t, n) => l(e, t, 0, n),
        defaultKey: "0123456789abcdeffedcba9876543210"
    }

}
function getEncryptData(xq_geetest,username,pwd,challenge,validate) {
    rn = new xx(window)
    T = "44366db6541f579612624aa1ad23ba08"
    I = "web7cc8ec28d50946f7a68816438fa465c5"
    k = "0123456789abcdeffedcba9876543210"
    data = {
        "remember_me": true,
        "xq_geetest": xq_geetest,
        "username": username,
        "password": pwd,
        "captcha": "",
        "geetest_challenge": challenge,
        "geetest_validate": validate,
        "geetest_seccode": validate + "|jordan",
        "sid": "68ec71b2723e5fbfef6cf6cdb7db4bde",
        "secret": T,
        "ee2eDid": I
    }
    ans = rn.encrypt(JSON.stringify(data), k)
    return ans
}

注意

请求别太快,太快极验会给你forbidden。
代码结构大体如下
在这里插入图片描述

看看流程
在这里插入图片描述
至此,这个登录的全过程就是搞好了。心魔也拿下了,修为更进一步

免责声明

本技术分享仅供学习交流使用,本人不承担因使用这些信息而直接或间接导致的任何责任!!!我鼓励所有参与者遵守法律法规,并在合法合规的前提下使用相关技术。任何逆向工程活动都应在获得充分授权的情况下进行。本人不对分享内容的准确性、可靠性或完整性提供任何明示或暗示的保证。参与者应自行承担风险,并在实施任何技术操作前进行适当的法律咨询

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值