Target:aHR0cHM6Ly93d3cuZGlnaWtleS5jbi8=
前言
本文參考了以下文章和視頻,感謝大佬們的分享
基本分析
-
akm的目標是cookie裡的_abck
這個值
-
當_abck
裡的~-1~
變成~0~
時就算是有效
-
上述的_abck
由類似1diI9T-4eS/HLR5GidZ/XH/YkNYXGfprwm5/cEMlcQYB/TnUjFxE/ZWTA
這樣的接口返回
-
本網站屬於簡單類型的akm,因此在風控正常的情況下,第1個接口返回的cookie就已經是有效的
-
而對於其他難度的akm,則可能需要在第3次後,什至是在某些事件觸發後,才會返回有效的cookie
第一次請求
- 從上述接口的堆棧,直接可以跟到這裡
Txf
就是接口請求的data,而其主要部分是wFf
- 向上跟來到這裡,可以看到
ATf
明顯是一個環境檢測的數據,裡面保存著當前的各種環境
ATf
環境數組具體如下,基本上每個都是環境檢測點,建議與自己的環境逐一對比
- 個人認為最主要關注的部分就是這個環境數組,只要這裡能基本一致應該就可以
- 後續的各種操作生成最終的
sensor_data
應該就沒有那麼重要了
[
// 0: 固定值
"-100",
// 1: 檢測了ua、window的一些屬性、自動化工具、Screen等
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36,uaend,12147,20030107,zh-TW,Gecko,5,0,0,0,416881,0,1920,1040,1920,1080,1920,931,1920,,cpen:0,i1:0,dm:0,cwen:0,non:1,opc:0,fc:0,sc:0,wrc:1,isc:0,vib:1,bat:1,x11:0,x12:1,8105,0.419036962209,847157403808.5,0,0,loc:",
"-105",
// 3: 檢測頁面input標籤的一些屬性
"0,0,0,0,-1,888,0;0,-1,0,0,-1,-1,0;",
"-108",
"",
"-101",
"do_en,dm_en,t_en",
"-110",
"",
"-117",
"",
"-109",
"",
"-102",
"0,0,0,0,-1,888,0;0,-1,0,0,-1,-1,0;",
"-111",
"",
"-114",
"",
"-103",
"",
"-106",
"0,0",
"-115",
// 25: 這裡取了cookie,因此在第1次請求前,要先對頁面進行1次請求,從而獲取頁面返回的cookie
"1,32,32,0,0,0,0,4,0,1694314807617,-999999,18125,0,0,3020,0,0,9,0,0,358649D9584BA9DE6AC5E821111B1819~-1~YAAQlBw/O81cCUmKAQAAp5YAfQrZ/fMGHSsNvloPsNh/jJ7n4XXUu6UHaA1RaKg7vczO18ylrCuF4EySkQ3t6XoOAwTJCNmqoAqcXdQ/SZ+evRynCqtSq6EuenlcO2+KeqRaC+qovOMyuUxX9M9KTDNvmU9zsmQ5fjaayV9pHOO9+O2lsN/Ihl4ODUU4/IAUv8ty5/TFT7VqCAGJmdhArhi5Bhq+y8It62D6MSGnZ4JGyz7m6TuNGx/1Wnfa03pi8u7hobrX3k7+NtZO7SrCMkQpynfZ62rz72edbZ22awJ/hOwJw+lI7KR87dOso7hrZQ5oR6Ke7vzXF0rgyETCaO+nUqVo5HsJ1ePZzv90oRMhA8SqiE4KBC8DhHYv4cxd6WyAKdqQIwHXGg==~-1~-1~-1,36758,-1,-1,30261693,PiZtE,12969,86,0,0,0,,,",
"-112",
"https://www.digikey.cn/",
"-119",
"-1",
"-122",
// 31: 檢則了一堆東西,如 XPathResult
"0,0,0,0,1,0,0",
"-123",
"",
"-124",
"",
"-126",
"",
"-127",
8,
"-128",
",,",
"-131",
",,,",
"-132",
"",
"-133",
"",
"-70",
"-1",
"-80",
"94",
"-90",
"MjZkMjI4NjYzZjEzYTg4NTkyYTEyZDE2Y2Y5NTg3Y2FhYjAzODhiMjYyZDZkOWYxMjZlZDYyZjkzMzNhY2E5NA==|-1|3,1,53,178,165",
"-116",
0,
"-129",
",,0,,,,,,,,"
]
技巧:以上述環境數組的第3個索引為例,要如何找到其生成位置?
- 先確認它是哪個變量
- 通過search快速定位
- 發現是一堆switch…case,這時可以在每個
return
處下斷點
- 可以看到是由
UJ.apply(undefined, tJ)
返回,進入該函數,裡面就是對input的檢測
sensor_data
這個請求參數可以在XMLHttpRequest.prototype.send
裡接收
第二、三次請求
雖然只需第一次請求就夠,但第二、三次請求的一些檢測點還挺有意思的,簡單地說一下吧
- 在第2次請求時,在以下代碼的位置檢測了
font
相關的東西,例如不同fontSize
和fontFamily
的offsetHeight
和offsetWeight
- 應付的方法也很簡單,就是根據
fontSize
和fontFamily
構建字典一一對應就可以了
var Mtf = cE.slice();
var Gtf = ff[hf.dL(pPf, Pp)][hf.pf(cG, Tk, cc, tLf)](hf.qs(VG, YI));
Gtf[hf.bP(FC, dc, jH, Qp)] = hf.Us(V4, AB),
Gtf[hf.kS.apply(null, [Ab, vI])][hf.rs(cR, DI)] = hf.lP(GM, mC, Lp, Kp);
var Ctf = hf.jL(qW, K1, HG, FC)
, ktf = (ff[hf.dL.call(null, pPf, Pp)][hf.ss(WQf, OI)](hf.Ys.call(null, xLf, XI)))[K1]
, ctf = ktf
, Jtf = SE(Q1);
jE(ff[hf.jf(MM, N1, gR, fC)][hf.vs(Ec, mI)], K1) && dE(K1)() && (Jtf = SE(K1)),
Jtf && ((ctf = ff[hf.dL.apply(null, [pPf, Pp])][hf.pf(cG, Tk, vp, tLf)](hf.Ds(p3f, nI)))[hf.kS.call(null, Ab, vI)][hf.Os.call(null, JH, fPf)] = hf.Xs.call(null, TLf, HG, pc, B3f),
ktf[hf.bF.apply(null, [jC, ZI])](ctf)),
ctf ? (Etf[hf.Cz(lLf, gI)](function(wtf) {
cE.push(nR);
Gtf[hf.kS(Ab, II)][hf.ms.apply(null, [IV, qG, hJ, Ahf])] = wtf,
ctf[hf.bF(jC, jI)](Gtf),
Ctf += (((hf.jL(f3f, zJ, TJ, FC))[hf.LS.call(null, Sp, SE(SE([])), SE(SE({})), w3f)](wtf, hf.tL.call(null, nJ, QA)))[hf.LS(Sp, dPf, JH, w3f)](Gtf[hf.ns(UC, hLf)], hf.BK(NLf, PLf)))[hf.LS(Sp, kG, xb, w3f)](Gtf[hf.Zs(fR, xl)], hf.mS.apply(null, [vG, QLf])),
ctf[hf.SP(OG, xb, QB, gJ)](Gtf);
cE.pop();
- 同樣是第2次請求,這裡先執行了
Object.keys(iframe.contentWindow)
的操作,然後用JSON.stringify
將其變成字符串,最後再將它用某種算法加密了一下,然後加上Object.keys
返回的數組的長度
E7f = ff[hf.tK.call(null, ZG, Ux)][hf.PF.call(null, Cb, QE)](d7f);
I7f = ((hf.jL.call(null, YPf, Lhf, OG, FC))[hf.LS.call(null, Ml, JJ, OG, w3f)](Atf(MSf(ff
- 第3次請求,這裡是一些CSS的檢測,有興趣可以自己來看看
return [hf.I5.call(null, fW, Z9), hf.j5.apply(null, [ng, dk, SE(K1), NG]), hf.N5(Lk, AI), hf.x5(kV, g9), hf.d5(jC, fj), hf.E5.apply(null, [kV, Qn]), hf.M5(bH, HV), hf.G5(Ehf, khf, hB, c4), hf.C5(Chf, I9), hf.k5.apply(null, [vE, j9]), hf.c5(Yb, N9), hf.J5(cR, x9), hf.B5(xJ, Uk, Wk, kc), hf.w5.call(null, Cw, qV), hf.A5(NR, Rp, cG, Xp), hf.b5(F9, pc, SE(K1), Ec), hf.l5(Qb, d9), hf.p5.apply(null, [nB, E9]), hf.V5.call(null, gLf, M9), hf.R5(r3f, G9), hf.H5.call(null, xC, C9), hf.W5(k9, NH, cG, Pw), hf.f0(c9, hJ, SE(K1), hJ), hf.dQ(Bk, Ip, pG, Eb), hf.EQ(EJ, CM, DC, MG), hf.h0(Khf, SE(K1), Ec, rhf), hf.P0(JH, CO), hf.Q0.call(null, Cc, J9), hf.MQ.apply(null, [FC, ZG, pJ, rV]), hf.L0(pc, ng), hf.K0.call(null, OG, B9), hf.S0.apply(null, [kb, Fl]), hf.T0.call(null, EG, Il), hf.GQ(EG, VW, Vc, TPf), hf.z0(AA, w9), hf.t0.apply(null, [hV, DC, JB, xw]), hf.F0.call(null, Pff, A9), hf.q0(Rff, SE(SE(K1)), SE(K1), rW)][hf.Cz(lLf, b9)](function(HYf) {
cE.push(Ol);
pYf[hf.kS.call(null, Ab, l9)] = (hf.U0(gLf, p9))[hf.LS(OC, WJ, q3f, w3f)](HYf, hf.r0(Dff, U3f, SE(K1), CM));
var WYf = (ff[hf.s0.apply(null, [Off, t3f, SE(SE(K1)), Bk])](pYf))[hf.Y0.call(null, Tk, V9)];
VYf[HYf] = WYf;
cE.pop();
}),
注:三次請求的觸發條件分別是
1. 最開始的自執行函數
2. setTimeout-> delay為500的函數
3. setTimeout-> delay為1000的函數
實際請求
總體流程如下:
效果如下:
curl_cffi
是用來躲避TLS檢測,注意`impersonate="chrome101"`要與js環境的ua和appVersion一致
node_vm2
太經典了就不多說啦