聲明
本文章中所有內(nèi)容僅供學(xué)習(xí)交流使用,不用于其他任何目的,不提供完整代碼,抓包內(nèi)容、敏感網(wǎng)址、數(shù)據(jù)接口等均已做脫敏處理,嚴(yán)禁用于商業(yè)用途和非法用途,否則由此產(chǎn)生的一切后果均與作者無關(guān)!
本文章未經(jīng)許可禁止轉(zhuǎn)載,禁止任何修改后二次傳播,擅自使用本文講解的技術(shù)而導(dǎo)致的任何意外,作者均不負(fù)責(zé),若有侵權(quán),請(qǐng)?jiān)诠娞?hào)【K哥爬蟲】聯(lián)系作者立即刪除!
目標(biāo)
- 目標(biāo):數(shù)美全家桶,包括:滑塊、文字點(diǎn)選、圖標(biāo)點(diǎn)選、語序點(diǎn)選、空間推理、無感驗(yàn)證
- 地址:
// 官網(wǎng)體驗(yàn)地址
aHR0cHM6Ly93d3cuaXNodW1laS5jb20vdHJpYWwvY2FwdGNoYS5odG1s
// 官方隱藏地址
aHR0cHM6Ly9jYXN0YXRpYy5mZW5na29uZ2Nsb3VkLmNuL3ByL3YxLjAuNC9kZW1vLmh0bWw=
// 某紅書驗(yàn)證頁面
aHR0cHM6Ly93d3cueGlhb2hvbmdzaHUuY29tL3dlYi1sb2dpbi9jYXB0Y2hh
數(shù)美不同類型驗(yàn)證碼核心的 JS 都是一樣的,只是個(gè)別參數(shù)有微小差別,主要以滑塊為例來分析,通過 JS 代碼以及官方文檔可以看出數(shù)美是有無感驗(yàn)證的,但是官網(wǎng)體驗(yàn)地址里并沒有放出來,官方有一個(gè)隱藏地址,里面的 demo 是最全的,包括無感,可以去上面給出的第二個(gè)地址里查看;數(shù)美的加密參數(shù)包含了 DES 加密算法,參數(shù)名以及 DES Key 不定時(shí)會(huì)變化,本文也會(huì)分析如何利用 AST 來獲取動(dòng)態(tài)的參數(shù)。
抓包分析
conf
接口,獲取配置,主要是獲取核心的 captcha-sdk.min.js
的地址,請(qǐng)求參數(shù)解釋:
參數(shù) | 含義 |
---|---|
organization |
數(shù)美分配的公司標(biāo)識(shí),一般是每個(gè)網(wǎng)站唯一,寫死即可 |
appId |
應(yīng)用標(biāo)識(shí),區(qū)分不同應(yīng)用,數(shù)美后臺(tái)可以管理 |
callback |
回調(diào)參數(shù) |
lang |
語言,zh-cn 簡(jiǎn)體中文、zh-tw 繁體中文、en 英文 |
model |
模式,slide 滑塊、auto_slide 無感驗(yàn)證、select 文字點(diǎn)選、icon_select 圖標(biāo)點(diǎn)選、seq_select 語序點(diǎn)選、spatial_select 空間推理 |
sdkver |
這個(gè) sdk 版本是 captcha-sdk.min.js 內(nèi)部寫死的 |
channel |
推廣渠道,數(shù)美后臺(tái)可以管理 |
captchaUuid |
32位隨機(jī)字符串,與業(yè)務(wù)方自身埋點(diǎn)數(shù)據(jù)配合,便于后續(xù)定位問題或進(jìn)行數(shù)據(jù)統(tǒng)計(jì) |
rversion |
captcha-sdk.min.js 版本號(hào) |
返回結(jié)果重點(diǎn)看 captcha-sdk.min.js
文件地址,如下圖所示有個(gè) v1.0.4-171
,本文中我們稱 v1.0.4
為大版本,171
為小版本,小版本不定時(shí)會(huì)更新,版本號(hào)不斷升高。
然后就是 register
接口,不同類型,返回的數(shù)據(jù)都大同小異,其中 bg
是背景圖片,fg
是滑塊,文字點(diǎn)選、空間推理中 order
是提示信息,k
、l
、rid
三個(gè)參數(shù)后續(xù)會(huì)用到。
最后就是 fverify
驗(yàn)證接口,有類似下圖紅框中的 12 個(gè)參數(shù),都是通過 JS 生成的,其參數(shù)名會(huì)根據(jù) captcha-sdk.min.js
的變化而變化,其中有個(gè)最長(zhǎng)的類似于下圖的 ep
值,包含了軌跡加密。返回值里參數(shù)解釋:
參數(shù) | 含義 |
---|---|
code |
1100 :成功;1901 :QPS超限;1902 :參數(shù)不合法;1903 :服務(wù)失?。?code>9101:無權(quán)限操作 |
riskLevel |
處置建議,PASS :正常,建議直接放行;REJECT :違規(guī),建議直接攔截 |
逆向分析
跟棧會(huì)發(fā)現(xiàn)核心邏輯在 captcha-sdk.min.js
里,這個(gè) JS 類似于 OB 混淆(以前的文章介紹過,此處不再細(xì)說):
這里可以自己寫 AST 還原一下,為了方便我們直接使用 v_jstools 解混淆:
然后替換掉原來的 captcha-sdk.min.js
,如果你測(cè)試的是官網(wǎng)的體驗(yàn)頁面,使用 Fiddler 替換時(shí)要注意可能有跨域問題,需要利用 Filters 功能,設(shè)置響應(yīng)頭 Access-Control-Allow-Origin
字段值為當(dāng)前域名:
如果你沒注意到這個(gè)跨域問題,可能會(huì)替換之后發(fā)現(xiàn)沒替換成功,原因是數(shù)美的資源有四個(gè)域名,其中一個(gè)宕了便會(huì)啟用另一個(gè),你替換其中一個(gè)報(bào)錯(cuò)了就會(huì)自動(dòng)跳轉(zhuǎn)另一個(gè),所以看起來你并沒有替換成功:
PS:若替換的 JS 格式化了,那么你在網(wǎng)頁上滑動(dòng)也是校驗(yàn)失敗的,因?yàn)?JS 里檢測(cè)了格式化,將 JS 壓縮成一行再替換即可,具體檢測(cè)的位置后文會(huì)講到。
captchaUuid
直接搜索關(guān)鍵詞下斷點(diǎn),經(jīng)過多次調(diào)試會(huì)發(fā)現(xiàn)第一個(gè)出現(xiàn) captchaUuid
的地方是在 smcp.min.js
,如下圖所示:
這里的棧并不多,來回跟棧也沒發(fā)現(xiàn)是哪里生成的,此時(shí)可以從初始位置也就是 embed.html
初始化驗(yàn)證碼的地方開始單步跟:
單步跟進(jìn)去會(huì)發(fā)現(xiàn)一個(gè) getCaptchaUuid()
的方法,將此方法扣出來即可。
function generateTimeFormat() {
var e = new Date()
, t = function(n) {
return +n < 10 ? "0" + n : n.toString();
};
return ((e.getFullYear().toString() + t(e.getMonth() + 1)) + t(e.getDate()) + t(e.getHours()) + t(e.getMinutes())) + t(e.getSeconds());
}
function getCaptchaUuid() {
var c = "";
var o = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
var s = o.length;
for (var a = 0; a < 18; a++) {
c += o.charAt(Math.floor(Math.random() * s));
}
return generateTimeFormat() + c;
}
12 個(gè)加密參數(shù)
直接跟棧就很容易找到,如下圖所示的位置,D 就是生成的所有參數(shù),此外,也可以通過搜索關(guān)鍵字 getEncryptContent
或者直接搜索參數(shù)名稱來定位。
可以發(fā)現(xiàn)上圖里就有四個(gè)加密參數(shù),都用到了 getEncryptContent
這個(gè)加密方法,加密方法傳入兩個(gè)參數(shù),一個(gè)是待加密參數(shù),一個(gè)是 DES Key,這四個(gè)待加密參數(shù)分別為 appId
值、channel
值、lang
值和一個(gè) getSafeParams
方法。
重點(diǎn)跟進(jìn) getEncryptContent
方法看看,一個(gè)控制流,挑幾個(gè)重點(diǎn)的講一下,第一步是獲取一個(gè) key
,這個(gè) key
是在前面設(shè)置的,后續(xù)會(huì)講到,實(shí)際上這個(gè) key
沒啥用。
然后會(huì)有一個(gè) isJsFormat
的格式化檢測(cè)函數(shù),正常應(yīng)該是 false 的,如果你格式化了就為 true,也就會(huì)導(dǎo)致 f 的值為時(shí)間戳加數(shù)美的域名,這個(gè) f 值后續(xù)是 DES 的 Key,不對(duì)的話自然怎么滑都不會(huì)通過。
然后就是 DES 加密了,這個(gè) DES 是標(biāo)準(zhǔn)的加密算法,下圖中傳入的 1 和 0 表示的是加密,0 和 0 則表示解密,解密的情況也有,后續(xù)會(huì)遇到,mode
為 ECB
,padding
為 ZeroPadding
,不需要 iv
,可以直接扣代碼,或者直接引庫即可。
var CryptoJS = require("crypto-js")
function DESEncrypt(key, word) {
var key_ = CryptoJS.enc.Utf8.parse(key);
var srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.DES.encrypt(srcs, key_, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.ZeroPadding
});
return encrypted.toString();
}
function DESDecrypt(key, word) {
var key_ = CryptoJS.enc.Utf8.parse(key);
var decrypt = CryptoJS.DES.decrypt(word, key_, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.ZeroPadding
});
return decrypt.toString(CryptoJS.enc.Utf8);
}
這里的四個(gè)值就分析完了,還有八個(gè)值是在前面生成的,如下圖所示 x 的值即為其他八個(gè)值,往前看是一個(gè)函數(shù)生成的,往里面跟即可。
跟進(jìn)來是一個(gè) getMouseAction
方法,里面先是挨個(gè)取值,后續(xù)會(huì)對(duì)這些值進(jìn)行 DES 加密,下圖中的 a、c 參數(shù)就是 register
接口返回的 k、l 值,s 參數(shù)是對(duì) register
接口返回的 k 值進(jìn)行解密操作:
上圖中 u = this._data
里面的值,根據(jù)滑塊、點(diǎn)選、無感模式的不同,也有所差異,以下代碼中,以 baseData
來表示 this._data
的值,根據(jù)模式的不同,可分為三類,大致構(gòu)成如下:
滑塊(slide
):
/*
track:滑動(dòng)軌跡(x, y, t),distance:滑動(dòng)距離,randomNum:生成兩數(shù)之間的隨機(jī)值,示例:
var track = [[0, -2, 0], [62, 1, 98], [73, 4, 205], [91, 3, 303], [123, -3, 397], [136, 8, 502], [160, 0, 599], [184, 0, 697], [169, 0, 797]]
var distance = 169
*/
var baseData = {}
baseData.mouseData = track
baseData.startTime = 0
baseData.endTime = track[track.length - 1][2] + randomNum(100, 500)
baseData.mouseEndX = distance
baseData.trueWidth = 300
baseData.trueHeight = 150
baseData.selectData = []
baseData.blockWidth = 40
滑塊軌跡生成代碼:
def get_sm_track(distance):
track_length = random.randint(4, 10)
track = [[0, -2, 0]]
m = distance % track_length
e = int(distance / track_length)
for i in range(track_length):
x = (i + 1) * e + m + random.randint(20, 40)
y = -2 + (random.randint(-1, 10))
t = (i + 1) * 100 + random.randint(-3, 5)
if i == track_length - 1:
x = distance
track.append([x, y, t])
else:
track.append([x, y, t])
logger.info("track: %s" % track)
return track
點(diǎn)選類(文字點(diǎn)選 select
、圖標(biāo)點(diǎn)選 icon_select
、語序點(diǎn)選 seq_select
、空間推理 spatial_select
):
/*
coordinate:點(diǎn)選坐標(biāo)(x, y),randomNum:生成兩數(shù)之間的隨機(jī)值,示例:
var coordinate = [[171, 101], [88, 102], [138, 109], [225, 100]]
*/
var baseData = {}
var time_ = new Date().getTime()
coordinate.forEach(function(co) {
co[0] = co[0] / 300
co[1] = co[1] / 150
co[2] = time_
time_ += randomNum(100, 500)
})
baseData.mouseData = coordinate
baseData.startTime = time_ - randomNum(800, 20000)
baseData.endTime = coordinate[coordinate.length - 1][2]
baseData.mouseEndX = 0
baseData.trueWidth = 300
baseData.trueHeight = 150
baseData.selectData = coordinate
baseData.blockWidth = undefined
無感(auto_slide
):
/*
randomNum:生成兩數(shù)之間的隨機(jī)值
*/
var baseData = {}
baseData.mouseData = [[0, 0, 0]]
baseData.startTime = 0
baseData.endTime = randomNum(100, 500)
baseData.mouseEndX = 260
baseData.trueWidth = 300
baseData.trueHeight = 150
baseData.selectData = []
baseData.blockWidth = 40
這些值生成完了之后,就是挨個(gè)通過 getEncryptContent
進(jìn)行加密,前面已經(jīng)分析過,實(shí)際上就是 DES 加密,可以看到分為點(diǎn)選、滑塊和無感三類,其中 DES Key 也是會(huì)每隔一段時(shí)間變化的:
再往下走還有三個(gè)加密參數(shù),待加密值是定值,然后將 s 的值(也就是前面 register
接口返回的 k 經(jīng)過 DES 解密后的值賦值給了 this._data.__key
)。
至此所有加密參數(shù)就搞完了。
結(jié)果驗(yàn)證
AST 獲取動(dòng)態(tài)參數(shù)
前面說了,/v1.0.4-171/captcha-sdk.min.js
文件地址,我們稱 v1.0.4
為大版本,171
為小版本,小版本每隔一段時(shí)間會(huì)更新,版本號(hào)會(huì)不斷升高,具體更新周期是多少?這里推薦一個(gè)方法 document.lastModified
,該方法記錄的是物理網(wǎng)頁的最后修改時(shí)間,我們直接訪問 JS 地址,就可以直接查看不同版本的 JS 是啥時(shí)候更新的了,多對(duì)比幾個(gè)版本,發(fā)現(xiàn)更新間隔時(shí)間并沒有太明顯的規(guī)律,如下圖所示:
不同版本里面的 12 個(gè)加密參數(shù)的名稱和 DES 加密的 Key 都不一樣,我們可以利用 AST 來動(dòng)態(tài)獲取這 12 個(gè)參數(shù),經(jīng)過測(cè)試,以下版本均可正常提?。?/p>
-
v1.0.4-148
~v1.0.4-171
-
v1.0.3-147
~v1.0.3-171
-
v1.0.1-147
~v1.0.1-171
截止本文發(fā)布,小版本 171
為最新,v1.0.4
小版本從 148
開始,v1.0.3
、v1.0.1
在 147
以前沒有混淆,可自行正則匹配,暫未發(fā)現(xiàn)其他大版本,如有遇到不能適配的,可聯(lián)系我瞅瞅,完整的代碼在公眾號(hào) k哥爬蟲
中,有需要的可以點(diǎn)擊下方鏈接。
【驗(yàn)證碼逆向?qū)凇繑?shù)美驗(yàn)證碼全家桶逆向分析以及 AST 獲取動(dòng)態(tài)參數(shù)文章來源:http://www.zghlxwxcb.cn/news/detail-436593.html
PS:此 AST 代碼僅實(shí)現(xiàn)對(duì)動(dòng)態(tài)參數(shù)的提取,并非還原所有的混淆,提取出來的結(jié)果是有序、未去重的,后續(xù)按索引取就行。文章來源地址http://www.zghlxwxcb.cn/news/detail-436593.html
到了這里,關(guān)于【驗(yàn)證碼逆向?qū)凇繑?shù)美驗(yàn)證碼全家桶逆向分析以及 AST 獲取動(dòng)態(tài)參數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!