干货|挖洞遇到验证码那些事

admin 2023年10月8日11:42:06评论10 views字数 18868阅读62分53秒阅读模式

# 前言

平台:aHR0cHM6Ly93d3cudnVsYm94LmNvbS8=公益SRC

厂商:zay7qMuz

链接:aHR0cHM6Ly91cGFzcy4xMGpxa2EuY29tLmNuL2xvZ2lu

文章搭配视频地址:挖洞遇到验证码那些事

# 正文

输入手机号码与账号密码登录的接口都有滑块。区别在于账号密码登录的时候有个加盐密码。流程比手机号码的接口复杂一下,为了省时间。此文章便是根据手机号码的接口去写的,毕竟咱的目的是过滑块嘛。

干货|挖洞遇到验证码那些事

## 发包逻辑分析

每次刷新验证码,都会发四个数据包下来。第一个数据包用于请求图片。图片链接的拼接就是urlParams加上imgs的值。

干货|挖洞遇到验证码那些事

第三个数据包是背景图

干货|挖洞遇到验证码那些事

第四个数据包是缺口图片

干货|挖洞遇到验证码那些事

正确拼接验证码,短信验证码发送成功

干货|挖洞遇到验证码那些事

captcha_signature在刷新验证码发下来的数据包里面的sign参数。

captcha_phrase和captcha_ticket在getTicket接口从服务器返回回来的,captcha_phrase是缺口,如果缺口对齐失败的话captcha_ticket是获取不到的。所以得先把getTicket接口的参数补齐拿到ticket。

干货|挖洞遇到验证码那些事

getTicket的前五个参数直接从getPreHandle接口返回的urlParams获取。

干货|挖洞遇到验证码那些事

干货|挖洞遇到验证码那些事

phrase直接用搜索大法就能搜到关键位置

phrase: (x) + ";" + inity + ";" + opt.width + ";" + opt.height

x是缺口识别的x轴,opt.width和opt.height是固定的值

inity也是直接在js文件一搜就能拿到他的关键代码。data.data.inity在getPreHandle接口里面的inity。这段代码就是取那个inity相除相乘再拼接到phrase里头

inity = (data.data.inity / 195 * opt.height);

x直接就是缺口识别然后减去15(因为图片实际大小跟他在网页上面的大小不一样),懒得缩小了。因为通过训练相同的图片跟缺口其x就相差15,直接减更方便(懒人做法)

图片缺口识别代码:

def detect_captcha_gap(bg, tp):  
    '''  
    bg: 背景图片  
    tp: 缺口图片  
    return:空缺距背景图左边的距离  
    '
''    # 读取背景图片和缺口图片  
    bg_img = cv2.imread(bg# 背景图片  
    tp_img = cv2.imread(tp) # 缺口图片  
    # 识别图片边缘  
    bg_edge = cv2.Canny(bg_img, 100, 200)  
    tp_edge = cv2.Canny(tp_img, 100, 200)  
    # 转换图片格式  
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)  
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)  
    # cv2.imwrite("bg_style.png",bg_pic) # 保存背景轮廓提取  
    # cv2.imwrite("slide_style.png",tp_pic) # 保存滑块背景提取  
    # 缺口匹配  
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)  
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)  # 寻找最优匹配  
    th, tw = tp_pic.shape[:2]  
    tl = max_loc  # 左上角点的坐标  
    # 返回缺口的左上角X坐标  
    br = (tl[0] + tw, tl[1] + th)  # 右下角点的坐标  
    cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形  
    cv2.imwrite("result_new.png", bg_img)  # 保存在本地  
    # 返回缺口的左上角X坐标  
    return tl[0]  
x = detect_captcha_gap("bg.jpg","tp.jpg")-15

mobile加密就是一个rsa加密,没有任何混淆跟难点。

验证码校验接口还有个hexin-v参数

干货|挖洞遇到验证码那些事

hexin-v硬扣

校验验证码的数据包里面有个加密的header参数hexin-v,他跟cookie的v是一模一样的。有两种方法可以找到关键加密位置,第一种是headers hook,第二种是cookie hook。

干货|挖洞遇到验证码那些事

cookie hook代码:

(function () {
    'use strict';
    var cookieTemp = "";
    Object.defineProperty(document, 'cookie', {
        setfunction (val) {
            console.log('Hook捕获到cookie设置->', val);
            if (val.indexOf('v') != -1) {
                debugger;
            }
            cookieTemp = val;
            return val;
        },
        get: function () {
            return cookieTemp;
        }
    });
})();

在控制台输入hook的代码

干货|挖洞遇到验证码那些事

断点断了下来。回溯堆栈找到关键代码加密的地方

干货|挖洞遇到验证码那些事

w函数便是设置cookie的函数,r就是v加密生成返回的值。那么qn.update()就是v生成的函数了。把断点下到qn.update()那一行然后刷新。由于这个网站的js文件是动态生成的,所以需要重新进入新的js文件在qn.update()那一行重新下个断点刷新。

干货|挖洞遇到验证码那些事

断点断下之后进入qn.update()看看里面写了啥

干货|挖洞遇到验证码那些事

进入到qn.update()函数内部可以看出他返回了另外一个函数的返回值。

干货|挖洞遇到验证码那些事

把断点断到R函数这一行进入到R函数内部。

干货|挖洞遇到验证码那些事

R函数往E对象里面压入一堆值。找找E在哪里生成的。

干货|挖洞遇到验证码那些事

E对象是在b函数里面被赋值的,但因作用域的原因,他并不是在这里声明的,E声明的地方还得往上面去找。

干货|挖洞遇到验证码那些事

在945行找到E声明的地方,同时也发现了这一段大的函数是一个自执行的函数。

干货|挖洞遇到验证码那些事

开始扣代码,就只扣需要的代码,R()是v加密后的值,R函数里面有E对象,E对象是在b函数里面被实例化的。b函数也扣下来,b函数里面调用了C函数。C函数也一并扣下来。因为E对象是全局作用域,其声明的代码在几个函数的外面。

var o = r[40], i = r[37], u = e[26], c = e[121], s = parseInt(Kn(n[80], e[122], t[135]), t[67]), f = n[94], v = r[59], l = e[74], p = n[53], d = parseInt(t[29], t[62]), h = parseInt(n[68], n[134]), g = n[135], m = parseInt(e[123], n[51]), w = parseInt(n[136], e[58]), I = parseInt(e[124], t[136]), _ = parseInt(e[125], e[79]), y = parseInt(n[137], n[134]), A = parseInt(e[126], t[67]), E;  
    function C() {  
        var r = Wn.getCookie(On) || $n.get(Pn);  
        if (r && r[t[59]] == parseInt(n[138], t[62])) {  
            var e = Qn.decode(r);  
            if (e && (E.decodeBuffer(e),  
            E[o] != n[29]))  
                return  
        }  
        E[o] = Gn.random()  
    }  
    function b() {  
        var t = e[31]  
          , a = parseInt(e[127], e[26])  
          , o = r[52]  
          , u = parseInt(e[128], e[26]);  
        E = new Un([u, u, u, u, t, t, t, o, a, a, a, a, a, a, a, u, a, t]),  
        E[i] = Gn.serverTimeNow(),  
        C(),  
        E[_] = Dn,  
        E[A] = xn,  
        E[y] = n[29],  
        E[c] = Gn.strhash(navigator.userAgent),  
        E[w] = Yn.getBrowserFeature(),  
        E
展开收缩
 = Yn.getPlatform(),  
        E[f] = Yn.getBrowserIndex(),  
        E[v] = Yn.getPluginNum()  
    }  
    function R() {  
        var n = Y;  
        E[y]++,  
        E[i] = Gn.serverTimeNow(),  
        E[u] = Gn.timeNow(),  
        E[_] = Dn,  
        E[l] = Jn.getMouseMove(),  
        n = q,  
        E

 = Jn.getMouseClick(),  
        E[d] = Jn.getMouseWhell(),  
        E[h] = Jn.getKeyDown(),  
        E[g] = Jn.getClickPos().x,  
        E[m] = Jn.getClickPos().y;  
        var t = E.toBuffer();  
        return Qn.encode(t)  
    }  

    console.log(R())

代码运行报错,r未定义。那么e,t,n是否也是未定义。在浏览器运行一下看看是什么呢

干货|挖洞遇到验证码那些事

在控制台打印r,e,t,n。发现他们都是大数组。直接扣下来就行了

干货|挖洞遇到验证码那些事

var n=["xi""n-""v""ai"".""get""kie""; d""x1c)Awx1b""3""ced""strT""rigi""]V8a""w""l", Array, "Map", Function, 58, "ttpR""Feb 2050""fZ,x19""x15x18;""", 9527, 256, String, "head", 0, 1, "al""Coo", 92, 81, !1, window, "[X9^QR""TR8""u250cu252c""localStorage""d""___""documentElement""addBehavior"'<script>document.w=window</script><iframe src="/favicon.icon"></iframe>'"frames""base_fileds""ZKx1f""f""ode", 2, 16, 8, "14""3f", 30, "ZV%Px0ex03x12P[X2P""ned""r""e"")^]a", 86, "le""u2559u253e""^{""th", / /g, "10", RegExp, '^".*"$'"u255bu0972""ready""1200000""script""src""sj.", 56, "ad""readyState", 14, "u2545u0978u095bu09f5u09a9u090eu099au09d0u0980u09d8""n*.z", document, Date, "i""[@", 85, "@""object""status_code""location""TX5TL^9[""length", 5, 32, "u2544u2530u2542u252au254bu2538u2550""random""L^;PvX!""addEventListener", !0, "onwheel""O_3PT""*6?v""rra"" gsx19?""u2543u252b""x arm""u2541u0961u097bu09ffu09b4""x15t""Po""x1a+FrJ", 22, 12, 34, "KV""maxHeight""u2576u2515u2561u2508u257eu251bu2543u250cu256eu2504u2561u2502u2576", 7, "Object""opr""QQBrowser""%TuD4""u2554u0975u0948u09feu09bdu0938""iso-8859-1""defaultCharset", 23, "ng""zh-cn""language""Native Client""^Android""plugins""mroftalPteg", 10, 11, "13""16""74""[^\r\n]""*)\r?$""u255bu253d""Fri, 01 ""error""[object Request]""^x16FyT""allow""sredaeh""headers""it", 95, 60, encodeURIComponent, 46, "PE3S""#""host""0x1a)_""g""Wi""prototype""0 GMT""/""`zx1a}lcx06", 15, "^""_raw""CHAMELEON_LOADED"],  
t = ["du""oma""ie", RegExp, "proto""base""enc", 79, "ode""und", 4, 28, "Domain""mUrl", 40, "hee""u2573u0952u0977u09dcu09bfu0928u099d", 57, "ri""t""Acti""th""gin""\.""x18B", Array, !0, "v""X-Antispider-Message""11""s.thsi.cn", 1, document, "", 2333, 0, String, "003""Thu, 01 Jan 1970 00:00:00 GMT""location""protocol""enon=etisemas ;""; secure=true""fH-&""co""ok", 16, "=""delCookie""^", window, !1, 94, "u256cu093cu0918u09b2u09f4u0978u09c8u0996u09dcu0994u09e8u099au0994u0992u09eau0a4du0a26u09e6u09f6u096cu091eu09a2u09beu09aau0998u0920u090cu0911u0a73u0981u09bbu092fu09b1""g"'KR"'"htmlfile""ducument""led""length""7""u255bu253eu2550u2537u2543u252b", 8, "eds""ff""001""u2551u097b", 2, "|AX"":]""es""oDec", 13, "//s.thsi.cn/js/chameleon/time.1""onerror""\Nx05""uyx1et""u255eu2530u2544u2521u2553u2532u2551u2525u254cu253au255f""onload""1000""\.com\.cn$|\.com\.hk$", 3, "10""{2,}([^\/\""fk%x1fx10bl]LC&Fx07rx7fndx18-x07x14J~nfkyix07kuidj}x1c"":""redi""href""redirect_url""on""parse""getServerTime", 59, "u2556u2538u2559u2535u254cu253fu2556u2525u2577u2504u2570""isIPAddr""eventBind""onmo""wesu""IA`\""u255au2535u2540""sew""ell""isTrusted""clientX""getMouseMove"'_R"xWB%P{[?VS'"a""32""4gCD""^iP""u2579u250cu2561""callPhantom""ActiveXObject""vendor""i""Maxthon""chrome""x1f2}e""}x1a""u2562u2520u2552u253du254au2539u255cu252e""P\erk""msDoNotTrack""20""as""webgl2""name""bjec""u2576u097eu094eu09f8u09a6u0938u09b6u09feu0996u09d7u09a7u09d2u09cc""mroftalp""$8""111100000", Date, "u2569u253eu2557u2539u250fu253b""xx17r]v""f^x06]WY3", 95, 10, "hos""ow""x18x07fx0fbx07lx05""open""Y[:""getAllResponseHeaders""error""fetch""type""toString""headers""ement""se""u2569u2501u2575u2501u2571u2502u253du2561u255b""u2543u2522u2550u2537u2552u2526""#""target""u255bu0978u0954u09f6u09a4u0935""HE9AWT9Y""apply""or""JbD}p""124f80""CHAMELEON_LOADED"],  
r =["he""lo""om"".*""State""u2545u2520u2543u2537""la;x19!""erTi", 65, Array, 19, "t""veXO""bjec", 73, "u2559u096b", String, "Shock""^W""in""ow""$""su", Function, RegExp, "thsi.cn""", 2333, document, "w""In", !0, "3ca""s.c""hostname"":sptth""0033cas.cn", 1, "; path=""=", 0, "length""document", window, "37""_fil""prototype""toBuffer""l%x16}""u2553u0978u0959u09feu09b4u0938u09acu09c4u0992u09dbu09a7u09c3""u255bu0978u0954u09f6u09a4u0935", 8, 3, "01""ff", 16, "<A`", 5, "u2504u097b", 6, 2, "edocnE46esab""u2552u0979""A=!""u2552u2534u255d""tps?:))?\/""f""bool""serv""ng""}$""d&"":""9~""protocol", Date, "x0fSf""onreadystatechange""complete", null, 10, ".""^\s*(?:(ht""h""edoc_sutats""3e8""3e9""1111101010""iFyx16""^(\d+\.)+\d+$""(c7'^", 72, "heel", 31, "div""hM""mousemove""u255cu2539u2540u2524u254bu253cu2552"'QDx02GMD"P\'"getKeyDown""getClickPos""ActiveX""3'ha""^Linu""ad""teg""u257au0972u0940u09c2u09b5u0929u099au09d8u099au09dau09b1u09f4u09ceu09d8u09d8u0a65""Uin""ActiveXObject""31"'yT"\'"WeakMap""Google Inc.""Apple Computer, Inc.""python""sgAppName""i""Q""y8.""mT%x1e""2345Explorer""chrome""MSGesture""e""1""doNotTrack", !1, "8tx1a>""languages""TR8RL_""PDF|Acrobat""ShockwaveFlash.ShockwaveFlash""^MacIntel""^Linux [ix]\d+""getBrowserIndex""getBrowserFeature""Init""MG2TLR""[ \t]*(", 62, "u2544u2536u2555u2510u257c""bm""^(.*?):""304""gm""otorp""url""headers", 42, "6px15i""click""parentNode""tagName""A""\?""&""?""src""analysisRst""insertBefore", 76, "XMLH""_str"],  
e=[".b""u2550u2524u254c""type""gth""2", Date, "u2507""rea""?\#\\]+)""oByt"'_R"gWX"', 95, "getO""imal""u2552u094eu0959u09e3u09bfu0931u0982""u2551u2530""Weak""roid""i^""plug""ins""1""ts""u2552u096fu0948""u255fu253au2542u252bu2545u2568u251e""CHAMELEON_CALLBACK", 2, 0, RegExp, "u2544u0972u0914u09e5u09b8u092eu0987u099fu0997u09d3""head", 1, """V587""it""u2554u0975u095fu09f2u09bbu093eu0981u09deu099fu09d4u09a7""u2556u0971u0956u09feu09a7""in=""location", window, "=""; expires=""setCookie", 9, "; ""#default#userData""___$&""qY?A""div""body""documentElement""0mU""u2550u2535u2541""base_fileds", 44, "len""length""18", 10, 12, 6, 16, "u2506u092cu090bu09a0u09e1u096cu09dfu0980""83""ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_""22", 94, "error""ox1f""nFro""u255au253fu2571u251e""11111111111111111111111111111111""x14"":", 7, "onload""5x1e${T"'LV"'"1750", 8, "_url""exx19=""getHostFromUrl""u2550u0978u094eu09dcu09bf""useWh", document, "touchmove""click""clientY""y""el""ng""OXev""wave""Plu""~)l!", 26, "veXO""bjec""postMessage""t8A""u2541u0978u0954u09f5u09bfu092f""chrome""BIDUBrowser""LBBROWSER""mMR""u2554u0975u0948u09feu09bdu0938""Q""2X""TheWorld""plugins""ca""ontouchstart""navigator""OR4QJ^ PJ""KN%A]Zx1aTVP#T_R", !1, "i""localStorage""^ARM""^BlackBerry", 3, "u2506u2536u2506""1100""14""17""10001""10""100""me""eque"" l""renetsiLtnevEdda""^@tuh""jsonp_ignore", Object, "headers""base""^_""target""ferh""PV%]""unload""tagName""SCRIPT""dlihCdneppa""tna""?""\.""$""11""nd""tcejbOXevitcA""Init"];

运行报window,document未定义。在开头定义一下为空对象

干货|挖洞遇到验证码那些事

var window ={}  
var document={}

运行报Kn未定义

干货|挖洞遇到验证码那些事

把断点下到报错代码那一行,进去Kn函数内部

干货|挖洞遇到验证码那些事

function Kn() {  
    var r = arguments[t[31]];  
    if (!r)  
        return t[33];  
    for (var a = e[32], o = n[25], i = n[29]; i < r.length; i++) {  
        var u = r.charCodeAt(i)  
          , c = u ^ o;  
        o = u,  
        a += n[27].fromCharCode(c)  
    }  
    return a  
}

运行报错Y未定义。

干货|挖洞遇到验证码那些事

浏览器查看Y是字符串“1”,直接在代码中写固定就行

干货|挖洞遇到验证码那些事

报这个错的原因是因为没有调用b函数,在R函数的开头调用运行一下b函数。

干货|挖洞遇到验证码那些事

对象实例化Un函数是未定义的。去浏览器扣。

干货|挖洞遇到验证码那些事

浏览器扣下来的Un函数

  var Un = function() {
            var a = r[44]
              , o = r[45];
            function i(a) {
                this[e[53]] = a;
                for (var o = r[40], i = a[t[59]]; o < i; o++)
                    this[o] = n[29]
            }
            return i[r[46]][r[47]] = function() {
                for (var o = t[60], i = this[n[47]], u = [], c = -n[30], s = n[29], f = i[Kn(r[48], t[61])]; s < f; s++)
                    for (var v = this
展开收缩
, l = i
展开收缩
, p = c += l; u

 = v & parseInt(a + o, t[62]),
                    --l != e[27]; )
                        --p,
                        v >>= t[62];
                return u
            }
            ,
            i[A + E][Xn(e[54], r[49], x)] = function(a) {
                for (var i = t[63], u = this[T + o + i], c = t[35], s = n[29], f = u[Xn(n[48], r[50])]; s < f; s++) {
                    var v = u

展开收缩

                      , l = r[40];
                    do {
                        l = (l << r[51]) + a[c++]
                    } while (--v > n[29]);this
展开收缩
 = l >>> e[27]
                }
            }
            ,
            i
        }()

运行报Xn未定义,分析代码的作用是把函数赋给对象,那么i后面跟着的肯定是字符串,把函数赋给某某对象原型链下面的某个属性。

干货|挖洞遇到验证码那些事

替换即可。

干货|挖洞遇到验证码那些事

运行报Gn未定义,直接进入Gn.serverTimeNow()函数内部查看写了什么。

干货|挖洞遇到验证码那些事

浏览器扣下来的代码,看看这段代码有什么作用。

        function cn() {
            var n = (s,
            u,
            new v[84]);
            return typeof TOKEN_SERVER_TIME == x + T + C ? I[27] : (time = parseInt(TOKEN_SERVER_TIME),
            time)
        }

cn函数有一个三元表达式,TOKEN_SERVER_TIME是数值,x + T + C是"undefined",TOKEN_SERVER_TIME == x + T + C 是false

所以执行(time = parseInt(TOKEN_SERVER_TIME),time)

这段函数的整体意思是将TOKEN_SERVER_TIME取整赋值给time,再把time值返回。

干货|挖洞遇到验证码那些事

E[i] = Gn.serverTimeNow()直接改写成E[i] = parseInt(TOKEN_SERVER_TIME)

运行代码报错TOKEN_SERVER_TIME未定义,在浏览器搜索TOKEN_SERVER_TIME。

干货|挖洞遇到验证码那些事

在第一行就可以看到TOKEN_SERVER_TIME。直接扣下来

干货|挖洞遇到验证码那些事

运行报错Wn未定义。这段C函数代码要是直接去扣就入坑了,先看看这个C函数有什么作用。

干货|挖洞遇到验证码那些事

第一行代码就是取cookie名为v的值,如果没取到cookie的v值就去取headers的"hexin-v"值。

var r = Wn.getCookie(On) || $n.get(Pn);

干货|挖洞遇到验证码那些事

一般情况下都不是第一次运行,那么他就会取得到前面cookie的v值。那么下面的if判断就会成立,就会执行。但是我们总不可能每次运行代码都去取他前面的cookie,那实在是太复杂了。假设,我是说假设。假设我每一次进去这个网站都是第一次,都取不到cookie的v值和headers的hexin-v。那么这段代码又是有什么样的作用呢。

干货|挖洞遇到验证码那些事

cookie的v和headers的hexin-v都取不到值的话那么if里面的就是null。就直接执行后面的代码

干货|挖洞遇到验证码那些事

最后C函数的代码就是直接改写成E[o] = Gn.random()

运行报错,直接扣Gn.random()

干货|挖洞遇到验证码那些事

        function rn() {
            var n = sn;
            return n = G,
            Math.random() * parseInt("11111111111111111111111111111111", 2) >>> 0
        }

C函数可以值改写成

E[o] =Math.random() * parseInt("11111111111111111111111111111111", 2) >>> 0

Dn报错

干货|挖洞遇到验证码那些事

Dn是数值0

干货|挖洞遇到验证码那些事

xn未定义

干货|挖洞遇到验证码那些事

xn是数值3

干货|挖洞遇到验证码那些事

报了Gn的错。分析这段代码就是把浏览器指纹ua传进了strhash函数。可以直接取最后的值写固定。

干货|挖洞遇到验证码那些事

E[c] = 自己浏览器头strhash后的值

后面的报错都是这几个值未定义。

干货|挖洞遇到验证码那些事

getBrowserFeature—>获得浏览器特性

getPlatform—>获取浏览器平台

getBrowserIndex—>获取当前网页所在浏览器的索引

getPluginNum—>获取当前网页或浏览器环境中已安装或可用的插件数量。

至于改写的话直接取最后的值就行了

b函数都改完之后到R函数报错了。Gn.serverTimeNow()在b函数就已经扣过了

Gn.serverTimeNow()—>parseInt(TOKEN_SERVER_TIME)

干货|挖洞遇到验证码那些事

Gn.timeNow()未定义

干货|挖洞遇到验证码那些事

进入Gn.timeNow()函数内部是个on函数

干货|挖洞遇到验证码那些事

on函数的作用就是取当前时间戳除以1000再无符号右移0位

改写后的代码

E[u] = Date.now()/ 1000

后面的代码都是未定义的

干货|挖洞遇到验证码那些事

Dn是数值0,n是字符串"DOMMous"

干货|挖洞遇到验证码那些事

getMouseMove—>获取鼠标当前的横坐标和纵坐标

getMouseClick—>获取鼠标点击时的横坐标和纵坐标,以及所点击的按钮

getMouseWhell—>获取滚轮事件的信息

getKeyDown—>获取按键事件的信息

getClickPos—>获取鼠标点击的坐标,然后进行相应的操作,比如记录点击位置或者根据点击位置执行特定的逻辑。

直接取最后运行完的值

运行Qn.encode未定义

干货|挖洞遇到验证码那些事

进入函数内部Qn对象总共有4个方法,直接把Qn对象补齐.

干货|挖洞遇到验证码那些事

var Qn;  
!function(a) {  
            var o = e[55]  
              , i = n[49]  
              , u = n[50]  
              , c = r[52];  
            function s(a) {  
                var o, i, u;  
                o = i = u = t;  
                var c, s, f;  
                c = s = f = r;  
                var v, p, d;  
                v = p = d = e;  
                var h, g, m;  
                h = g = m = n;  
                for (var w = g[29], I = (en,  
                on,  
                a[d[56]]), _ = []; w < I; ) {  
                    var y = l[a.charAt(w++)] << parseInt(p[57], v[58]) | l[a.charAt(w++)] << d[59] | l[a.charAt(w++)] << v[60] | l[a.charAt(w++)];  
                    _.push(y >> parseInt(Vn(f[53], Tn), d[61]), y >> c[51] & parseInt(Xn(X, p[62]), g[51]), y & parseInt(u[64], h[52]))  
                }  
                return _  
            }  
            function f(n, t, a, i, u) {  
                for (var c = n[o + C]; t < c; )  
                    a[i++] = n[t++] ^ u & parseInt(r[54], e[61]),  
                    u = ~(u * parseInt(e[63], r[55]))  
            }  
            for (var v = e[64], l = {}, p = n[29]; p < parseInt(Vn(t[65], r[56]), r[51]); p++)  
                l[v.charAt(p)] = p;  
            function d(n) {  
                for (var a = r[40], o = t[35], i = n[t[59]]; o < i; o++)  
                    a = (a << r[57]) - a + n[o];  
                return a & parseInt(Xn(q, t[66], In), e[61])  
            }  
            function h(r) {  
                var e = d(r)  
                  , a = [c, e];  
                return f(r, +n[29], a, +t[67], e),  
                g(a)  
            }  
            function g(a) {  
                for (var o = r[40], u = (G,  
                i,  
                a[e[56]]), c = []; o < u; ) {  
                    var s = a[o++] << parseInt(b + R, r[51]) | a[o++] << r[51] | a[o++];  
                    c.push(v.charAt(s >> parseInt(e[65], n[53])), v.charAt(s >> parseInt(n[54], t[62]) & parseInt(Xn(e[66], r[58], S), e[61])), v.charAt(s >> r[59] & parseInt(B + i, t[46])), v.charAt(s & parseInt(n[55], r[55])))  
                }  
                return c.join(Vn(r[26], n[56]))  
            }  
            function m(n) {  
                var t, a, o;  
                t = a = o = r;  
                var i, u, v;  
                i = u = v = e;  
                var l = s(n);  
                if (l[u[27]] != c)  
                    return error = i[67],  
                    void 0;  
                var p = l[t[37]]  
                  , h = [];  
                return f(l, +a[60], h, +i[27], p),  
                d(h) == p ? h : void 0  
            }  
            a[Vn(r[61])] = g,  
            a[Hn($n, n[57], t[68])] = s,  
            a[k + u] = h,  
            a[O + S] = m  
        }(Qn || (Qn = {}));

运行报错

干货|挖洞遇到验证码那些事

在浏览器打印o+C是字符串"length",直接替换

干货|挖洞遇到验证码那些事

干货|挖洞遇到验证码那些事

在浏览器打印Vn(r[61])是字符串"100",直接替换

干货|挖洞遇到验证码那些事

后面几个都是未定义的,在浏览器找到对应的值替换

干货|挖洞遇到验证码那些事

干货|挖洞遇到验证码那些事

a["base64Encode"] = g,  
a["base64Decode"] = s,  
a["encode"] = h,  
a["decode"] = m

直接拿运行之后的结果进行替换

干货|挖洞遇到验证码那些事

Xn(q, t[66], In)—>"ff"

干货|挖洞遇到验证码那些事

干货|挖洞遇到验证码那些事

G—>"w"

干货|挖洞遇到验证码那些事

干货|挖洞遇到验证码那些事

Xn(e[66], r[58], S)—>"3f"

干货|挖洞遇到验证码那些事

干货|挖洞遇到验证码那些事

B + i—>"3f"

干货|挖洞遇到验证码那些事

干货|挖洞遇到验证码那些事

Vn(r[26], n[56])—>""

干货|挖洞遇到验证码那些事

代码再次执行,值便出来了。

干货|挖洞遇到验证码那些事

带上值去请求一遍。手机验证码发送成功

干货|挖洞遇到验证码那些事

hexin-v(js-dom补环境)

在网上看到一堆文章都又说直接用js-dom包补document和window两个环境。

直接把整个js文件复制下来

干货|挖洞遇到验证码那些事

定义一个全局变量接受v的值,方便后面导出。

运行代码报window未定义

干货|挖洞遇到验证码那些事

导包

const jsdom = require('jsdom')  
const {JSDOM} = jsdom;  
const {window} = new JSDOM(``);  

运行代码报document未定义

干货|挖洞遇到验证码那些事

const document = window.document

运行代码报navigator未定义

干货|挖洞遇到验证码那些事

const navigator = window.navigator

干货|挖洞遇到验证码那些事

打印值出来了,报错不管他。直接用py调用。也是成功的!

干货|挖洞遇到验证码那些事

# 结尾

本文章仅供学习交流使用,如有侵权,联系我删除。

干货|挖洞遇到验证码那些事

原文始发于微信公众号(乌雲安全):干货|挖洞遇到验证码那些事

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年10月8日11:42:06
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   干货|挖洞遇到验证码那些事http://cn-sec.com/archives/2092149.html

发表评论

匿名网友 填写信息