極驗驗證碼破解
[國家企業信用資訊公示系統為例]
一、網站http://www.gsxt.gov.cn滑動驗證碼概述
二、極驗驗證碼破解-抓包分析
三、極驗驗證碼破解-搭建本地驗證碼服務
四、極驗驗證碼破解-分析geetest.js,得到所需參數
五、極驗驗證碼破解-Track的擷取
六、極驗驗證碼破解-擷取背景圖檔及缺口距離d的計算
七、極驗驗證碼破解-總結
參考文獻
運作截圖
一、網站http://www.gsxt.gov.cn滑動驗證碼概述
(對滑動驗證碼了解的朋友請跳過本章節)
1. 浏覽器打開目标站點,将會出現圖示搜尋框。
- 在搜尋框中輸入待查詢企業名(如:百度),點選查詢,将會出現如圖所示驗證碼。
上述滑動驗證碼即為http://www.geetest.com/(極驗驗證)所提供的驗證碼服務。該滑動驗證碼号稱利用機器學習和神經網絡建構線上線下的多重靜态、動态防禦模型,具體描述可參見http://www.geetest.com/feature.html。
3. 拖動驗證碼中的滑塊,首先看失敗時的效果。
拖動滑塊到缺口位置,驗證成功效果如下:
4. 以上為對目标網站滑動驗證碼的一些基本描述,下面章節将會詳細講解如何使用計算機程式(爬蟲)來對該驗證碼進行破解。
二、極驗驗證碼破解-抓包分析
-
為了分析伺服器如何驗證用戶端是否成功拖動滑塊至缺口(即完成驗證),我們啟動浏覽器(我使用的是360安全浏覽器)-工具-開發人員工具(F12),在輸入框輸入“百度”,點選查詢。在開發者工具-Network中,我們可以看到如下資料包。
(PS:若資料包的數量較少,可先啟動開發者工具F12,重新整理頁面)
- 我們象征性的拖動滑塊,可以看見Network選項下多出一個資料包 ajax.php?gt=…&challenge=…,如下圖所示: 滑鼠點選上述資料包,可在右側檢視該資料包的詳細資訊。點選Response可檢視伺服器響應資訊,如下所示: 顯然,伺服器傳回該驗證碼驗證失敗:fail。
- 為了檢視驗證成功時的伺服器響應資訊,我們拖動滑塊至缺口處,已同樣方式檢視最新的ajax.php頁面,我們發現此時ajax.php?資料包的Response變為如下資訊:
有上述可知,當伺服器檢測到用戶端驗證成功時,傳回validate(可看作是一串長字元串密碼)和其他success資訊。
(PS:為防止驗證成功時頁面快速切換至查詢結果頁面,可在Network頁籤下将Preserve log選項勾選,如下圖所示:)
- 當驗證成功時,頁面跳轉至查詢結果頁面,如下所示: 通過分析Network下的資料包可以發現,在最新的驗證成功的ajax.php?資料包下面,有一個crop-query-search-1.html資料包,如下所示:
通過檢視該項的Response,我們可以發現,該Response的内容即為浏覽器頁面上展示的内容,亦即我們所需爬取的内容。
為了擷取該Response内容,我們将模拟請求該url,我們檢視該請求的頭部headers資訊,如下所示:
從Headers中我們發現,該請求為POST請求,同時發送Form Data給伺服器。接下來我們将分析該Form Data是如何得到的,其中geetest_challenge和geetest_validate是關鍵資訊,geetest_seccode是由geetest_validate後加上“|jordan”。Form Data相當于密碼,浏覽器通過向伺服器請求頁面,并發送Form Data,伺服器端驗證該密碼正确,将傳回頁面資訊。
接下來我們将逆向探索如何得到geetest_challenge和geetest_validate。(實驗證明:tab可為空或’ent_tab’,不影響結果,token可設一相同長度的随機數,不影響結果,searchword為查詢關鍵詞)
- 回憶上述3中驗證成功時,ajax.php?的Response資訊可知,validate的值是由該請求獲得。 我們将模拟該請求,以獲得validate資訊,構造geetest_validate和geetest_seccode。
- 為了模拟請求ajax.php?,我們檢視該資料包的Headers資訊: 從上圖可以看出,此請求附帶7個參數。首先,我們可以大膽猜測passtime應該是拖動驗證碼的時間,imgload應該是驗證碼圖檔載入時間,callback應該是“geetest_”+目前時間的時間戳,如下: 關于passtime,我們知道驗證碼圖檔在不同的機器上受網速影響,加載時間是不同的,是以該項可暫考慮設為一個0-1000ms的随機數或固定值。
- 我們知道極驗驗證是根據使用者拖動滑鼠的軌迹來判斷是人為操作還是機器的。Userresponse和imgload從參數名上可猜測是跟拖動滑塊的軌迹(使用者行為)來生成的。參數a最為複雜,我們先看gt和challenge是如何生成的。
- 分析Network下的資料包(ajax.php?之前的包),我們發現除去一些css、png等無關緊要的東西外,有個get.php?gt=…還是挺顯眼的,大膽點進去,如下: 從該資料包的Response中可以發現,”gt”: …,對比發現,這就是我們要的gt啊啊啊! “fullbg”也暗示着我們,它表示驗證碼的背景圖檔。此時,可以感覺到該Response的資訊量之大,繼續往後檢視,可以發現: “challenge”出現了,對比發現,這也是我們要的challenge!!!
- 為了得到上述大量資訊,我們模拟請求get.php?,檢視該包的Headers如下:
我們發現,該請求的參數還有一個gt和challenge(真實一個接着一個…)。除了gt和challenge,其它6個參數看起來沒什麼價值,可直接保留,我們來分析gt和challenge的生成。
繼續檢視Network中的資料包(get.php?之前的),我們可以發現SearchItemCaptcha?v=…這個包的Response如下:
驚呆.jpg!比較發現這裡的gt和challenge就是我們需要的值。輕按兩下 可以打開頁面,重新整理發現每次頁面展示的傳回值中challenge都在變化。這是因為該api的參數v是根據請求時間動态變化的,是以我們也可以将v設為目前時間的時間戳。 - OK!至此我們可以按照SearchItemCaptcha?v=… get.php? ajax.php?crop-query-search-1.html的順序請求資料。關鍵問題是如何構造ajax.php?參數中的userresponse、passtime和a。passtime從名稱可以看出是拖動滑塊的時間,userresponse和a應該是根據拖動滑塊的軌迹進行加密的。接下來我們将在本地搭建一個簡易的web server,修改相關js源碼,使得拖動滑塊時輸出滑鼠軌迹資訊Track。并分析js源碼,找出根據Track得到的userresponse和a的算法。
三、極驗驗證碼破解-搭建本地驗證碼服務
- https://github.com/GeeTeam/gt-python-sdk從上述連結下載下傳SDK并按教程安裝。
- 打開static/index.html。 可以發現,該頁面請求的gt.js是來自geetest遠端伺服器的。我們要想修改js源碼,列印相關資訊,必須使得請求的js來自本地,是以我們搭建簡單的檔案伺服器。
- https://pan.baidu.com/s/1c26btBE從上述連結下載下傳HFS軟體。運作軟體,按圖示搭建檔案夾(所需檔案從Network下載下傳): 修改index.html中gt.js的來源,如下所示(位址為hfs的位址): 從http://1ocalhost:8000/下抓包發現,gt.js的确來自本地hfs:
- 打開gt.js。 我們發現geetest.js是由gt.js調用,修改static_server為本地位址: 抓包發現,geetest.js的确來自本地hfs: (ps.圖檔等其他本地沒有的資源将會繼續請求源伺服器)。 至此,我們已搭建好本地驗證碼服務,下面我們将分析geetest.js,找出相關參數userresponse和a的加密過程。