天天看點

網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門

什麼是“極驗”?

如果你是從事爬蟲相關工作的,那麼一定對這兩個字不會陌生的。

極驗是首家「行為式驗證」安全技術服務提供商,并以提供驗證碼服務而聞名。我們日常會登入一些網站,有的網站登入前需要校驗驗證碼,而這個驗證碼服務很可能就是極驗提供的。

我們直接進入正題

網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門

如圖所示 這個在登陸面前的攔路虎 便是大名鼎鼎的極驗滑塊驗證碼了

看到這裡 有點基礎的小夥伴 應該馬上能想到用selenium來模拟人為拖動滑塊來解決,這确實是一個不錯的方法,在需求量較小的情況下,不失為一個優先的選擇,但它的缺點也十分明顯:

一是模拟滑動,容易被極驗檢測到我們使用的是自動化軟體,進而導緻滑動操作失敗;

二是每一次登入任務都需要驅動浏覽器,将會導緻登入耗時較長。

是以今天我們講的是另一個方式,硬剛JS,破解每個請求中的加密參數,之後在程式中發送請求得到正确響應,即POST逆向協定的方式來解決它

首先國際慣例第一步先抓包分析

網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門

請求參數 Form Data 有多個,包括:appId、loginName、loginPwd、geetest_challenge 等。可以看到,密碼被加密成 CN-SA95… 這一長段,另外還有三個以 geetest_ 開頭的加密參數,分别是:

•geetest_challenge: 102f7d723ad76e387ad6000f87ff91f8j3

•geetest_validate: 651ecdf62cb1e940e5ea999b6af7fc10

•geetest_seccode: 651ecdf62cb1e940e5ea999b6af7fc10|jordan

從參數命名上,我們能夠很清晰地看出,這是極驗滑動驗證碼的加密參數。也即是說,我們點選驗證碼,拖動滑塊這些動作,最終轉換為這三個加密參數。我們的主要工作,也在于破解這三個參數。細心的同學可能發現了,其中 geetest_validate 與 geetest_seccode 參數基本相同,隻不過 geetest_seccode 多了 |jordan 的字元串字尾。那麼,最主要的工作就是解出 challenge/validate 兩個參數。

我們接着往上找,可以發現ajax.php這個請求

網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門
網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門

仔細剖析這個接口 不難發現params裡面有 gt、challenge、lang、w 和 callback。其中 w 加密成了一長串,是以我們重點來看這個w參數。

我們找到slide.xxx.js 檔案,跳轉到 Chrome Sources 菜單欄,檢視 JavaScript 代碼

網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門
網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門

剖析出一些關鍵代碼

function tPcX(e) {
    var SkB = uklgT.yaA()[0][22];
    for (; SkB !== uklgT.yaA()[16][19]; ) {
        switch (SkB) {
        case uklgT.yaA()[0][22]:
            var t = this;
            var r = e["DxJq"];
            SkB = uklgT.yaA()[0][21];
            break;
        case uklgT.yaA()[16][21]:
            r["height"] = r["width"] = 0;
            t["vjyG"] = r["getContext"]("2d");
            SkB = uklgT.yaA()[4][20];
            break;
        case uklgT.yaA()[4][20]:
            t["wOTb"] = t["xmDd"] = t["yZRm"] = t["AZ_O"] = 0;
            t["BnKG"] = r;
            SkB = uklgT.yaA()[4][19];
            break;
        }
    }
}

           

去除備援代碼後

function tPcX(e) {
    var t = this;
    var r = e["DxJq"];
    r["height"] = r["width"] = 0;
    t["vjyG"] = r["getContext"]("2d");
    t["wOTb"] = t["xmDd"] = t["yZRm"] = t["AZ_O"] = 0;
    t["BnKG"] = r;
}
           

通過對多個 JavaScript 檔案,如 slide.js/fullpage.js 等進行反混淆、去備援,我們對 JavaScript 的調用邏輯清晰了很多。

完成了代碼反混淆,還有一個重要的工作,就是如何從 JavaScript 代碼中抽離出關鍵的 JavaScript 代碼,這些代碼就是請求參數的加密邏輯。我将此過程稱為“代碼解綁定”。

這個過程并不需要什麼技巧,需要的隻是耐心,耐心,耐心。跟着 Chrome 浏覽器,打斷點分析請求的入口與出口,一步步将關鍵代碼剝離出來。

網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門

比如,我們需要解出參數 a,那麼就抽離出加密參數 a 的代碼,封裝成一個 get_a() 的函數。

網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門

封裝了幾個需要的 JavaScript 函數,我們可以在 Python 程式中,使用 PyExecJS 庫,友善地執行 JavaScript 代碼拿到加密參數。以下為一些示例代碼:

import execjs


path1 = path + '/js-file/get_rp.js'
path2 = path + '/js-file/get_gj.js'


# RSA
def get_yf():
    ec = Encrypyed()
    key = ec.create_secret_key(8)
    enc_sec_key = ec.rsa_encrpt(key, ec.pub_key, ec.modulus)
    return enc_sec_key,key


def get_w1(gt,challenge):
    yf,key = get_yf()
    test  = '''{"gt":"%s","challenge":"%s","offline":false,"product":"bind","width":"300px","protocol":"http://","maze":"/static/js/maze.1.0.1.js","click":"/static/js/click.2.7.6.js","fullpage":"/static/js/fullpage.8.7.3.js","geetest":"/static/js/geetest.6.0.9_orgin.js","type":"fullpage","static_servers":["static.geetest.com/","dn-staticdown.qbox.me/"],"pencil":"/static/js/pencil.1.0.3.js","slide":"/static/js/slide.7.5.5.js","voice":"/static/js/voice.1.2.0.js","beeline":"/static/js/beeline.1.0.1.js","aspect_radio":{"click":128,"voice":128,"slide":103,"beeline":50,"pencil":128},"cc":12,"ww":true,"i":"3359!!17234!!CSS1Compat!!50!!-1!!-1!!-1!!-1!!3!!-1!!-1!!-1!!9!!9!!-1!!9!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!9!!-1!!4!!-1!!-1!!-35!!72!!0!!0!!901!!841!!1955!!958!!zh-CN!!zh-CN,zh!!-1!!1!!24!!Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36!!1!!1!!1920!!1080!!1920!!1030!!1!!1!!1!!-1!!Linux x86_64!!0!!-8!!2618e15e5d8c7f174cad42997c4436f2!!07f3564381d09b0994b7e73a99c6d7c7!!internal-pdf-viewer,mhjfbmdgcfjbbpaeojofohoefgiehjai,internal-nacl-plugin!!0!!-1!!0!!12!!Arial,Courier,CourierNew,Helvetica,Times,TimesNewRoman,Wingdings,Wingdings2,Wingdings3!!1559555859986!!-1,-1,1,0,0,0,0,1,57,3,3,3,4,368,368,407,693,693,693,-1!!-1!!-1!!60!!6!!-1!!-1!!14!!false!!false"}'''%(gt,challenge)
    ec = Encrypyed()
    iv = b"0000000000000000"
    enc_text = ec.aes_encrypt(test, key.decode('utf-8'), iv)
    array = []
    for byte in enc_text:
        array.append(byte)
    enc_text = ec.bytes_to_string(array)
    return enc_text+yf, key


def get_w2(gt,challenge,key,c,s):
    passtime = 1230
    _js = execjs.compile(open(path1, 'r').read())
    rp = _js.call('f3',gt,challenge,passtime)
    _js1 = execjs.compile(open(path2, 'r').read())
    tt = fun_u('M*d8PjAA3(-95e6D:)lN1NU91W-O/MEM92N*)O,n2_(/Xn(e5((,,-_N(,)(I-*5P4)(db9-5/)1g:AAdbE-NME)qqn(2DM()jFOJb5,)M9QEQ2,)(/*(M57(,(M((b',c,s)
    text = '''{"lang":"zh-cn","type":"fullpage","tt":"%s","light":"INPUT_0","s":"93e3d79ea85149d4e44244d3df6e16e5","h":"3deef994fc3cbf723df4c186cfe78a27","hh":"152caf38ccf01c64d90d2d0e8526c018","hi":"541c245c0365e2dcb84cef1b1366f775","ep":{"ts":1559840826770,"v":"8.7.3","ip":"192.168.124.11,218.98.33.165","f":"aea0f96bf3e494262bedf6ec7570f83b","de":false,"te":false,"me":true,"ven":"NVIDIA Corporation","ren":"GeForce GTX 1050 Ti/PCIe/SSE2","ac":[],"pu":false,"ph":false,"ni":false,"se":false,"fp":["move",302,315,1559840498541,"pointermove"],"lp":["up",234,339,1559840499124,"pointerup"],"em":{"ph":0,"cp":0,"ek":"11","wd":0,"nt":0,"si":0,"sc":0},"tm":{"a":1559840496633,"b":1559840496768,"c":1559840496768,"d":0,"e":0,"f":1559840496635,"g":1559840496635,"h":1559840496635,"i":1559840496635,"j":1559840496635,"k":0,"l":1559840496635,"m":1559840496735,"n":1559840496745,"o":1559840496773,"p":1559840496832,"q":1559840496832,"r":1559840496906,"s":1559840496930,"t":1559840496930,"u":1559840496930},"by":2},"captcha_token":"bboy","passtime":%s,"rp":"%s"}'''%(tt,passtime,rp)
    ec = Encrypyed()
    iv = b"0000000000000000"
    enc_text = ec.aes_encrypt(text, key.decode('utf-8'), iv)
    array = []
    for byte in enc_text:
        array.append(byte)
    enc_text = ec.bytes_to_string(array)
    return enc_text
           

以上便是整個極驗滑動驗證碼破解的過程,再簡單總結一下:

1.請求參數分析

2.代碼反混淆

3.代碼解綁定

4.滑動軌迹采集

其中,還包括驗證碼圖檔的還原,圖檔缺口的計算等等…

網絡爬蟲-破解極驗三代滑動驗證碼EndingGithub傳送門

最終我們經過測試 可以發現這個vcalidate是可以通過登陸驗證的關鍵token,至此破解結束。

Ending

Github傳送門

持續更新ing (歡迎各種star與fork)

聯系方式: 442891187(QQ)

如有權益問題可以發私信聯系我删除

繼續閱讀