瑞数(裁判文书)js的加密分析
抓了半年多的裁判文書突然停了,查看log發現HTTP響應碼全是202,分析頁面發現原網站在cookie上做了加密。經分析正確的請求流程如下
1. 請求首頁,返回兩個set-cookie響應頭,cookie名稱分別為FSSBBIl1UgzbN7N80S,?FSSBBIl1UgzbN7N80T,響應碼為202。響應體中有三段不明代碼
?
?
<html> <head> <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"> </head> <!--?1.?meta['content']意義不明?--> <body><meta?name="renderer"?content="webkit"><meta?id="9DhefwqGPrzGxEp9hPaoag"?content="{qqqqqr0.YUQeBgClraT6.dA28Ej3I1UKSbXlJ8NIUKxHc2UmGAqqkknLqqqqhvefgTey0JSvqkxJqkqLWqqqqk130r0HMvpQpmzDUlrUpmQ83oYJA2wDVVYY1mrWY0f3s2ptVlNp1aqqqqt1073741856VIJRJg9UB18SE49UPp8fH8h5lq2Y8psLYtXTCqAg2iGacfA3Tt9GOFqTs8GTGDCQwHGz5oKqQHAe4oO7h8mEBKcWqqqqhTrB4MbBgeoxqKGKR2zkG8iNtX0bwqfYF_uGc80qqqqr0qqDe5191aqqqqhb6rmecbj1Zrr4q{WYozbAKrlMPE9mOVpEiZygKFg3hxX_u.SidW64uobWi227DF_MXET5u6NJI74gv.axiEcePMvHIL_qqqqYDUvHttHp6whZmAp7KOQtW}{tPgKp0pIU0AtpYJcsagEUlJps2JlmANpsGAEYVpUpYTioaNA1TxHIAGCFAr7xGAWwAl8k67pUumcIlQ.D6xnhSSgVfzZDmg4DfzoD6a5KcrDWfEURnTmlm9dRn2PWS7TAOwGmVRXKcx9JULM3rRrHpLfrkJrlK3DlPwMrl9cF0gtD07cUaLUV20v8YShrYWSMSRZD90l8OSvxbzc8saEAG|qqU7aWVE0A9yYlv7CMX9T4THtVhmE4UX0Fjfh_vIdsiNUgCd3JJSPa6hZsZfcgVuLJzRXgkkhAWrC4uoKF82V.vbXKITtyVsSpIJvy9.SY5zYeuUlWzJG_lkrJwYoaucRQQg6y96Ch5rsnbU71HJ.nkkD85xjOoscMWRbGCiHUXy74mDJRW00e0.UV8f7ZDsBQIzOfuDJYjeBdCbXMhlCyCjW8hzMPlbWR_w.LKKFwywal7445"><!--[if?lt?IE?9]><script>document.createElement("section")</script><![endif]--> <!--?2.?意義不明的js文件?--> <script?type="text/javascript"?src="4QbVtADbnLVIc/c.FxJzG50F.js%3FD9PVtGL=e5191a"></script> <script?type="text/javascript"> <!--?3.?主要加密js代碼,省略?--> </script> <script?type='text/javascript'?r='m'> _$hr('ZoA8'); </script> <!--?4.?這段代碼的作用是重新請求當前頁面,分析時注釋掉 <script?type="text/javascript">window.οnlοad=function(){var?_$n6=document.getElementById(_$fv('ondoal'));_$nR(_$n6.name,_$vD(_$n6,_$zb('HvzED2ExKa')));};</script> --> </body> </html> <script?type="text/javascript">_$e3();</script>?
2. 瀏覽器帶著兩個cookie再次請求原網頁,響應碼為200,得到正常頁面,這次請求中cookieFSSBBIl1UgzbN7N80T的值與響應頭中設置的值不一樣,并且在一段時間后會自動更新。另外修改響應,刪除Set-Cookie: FSSBBIl1UgzbN7N80T=...,瀏覽器在新的請求中仍會有FSSBBIl1UgzbN7N80T的cookie,猜測這個cookie的值是通過js計算得到,且會定時刷新。
?
也就是說只要破解cookie FSSBBIl1UgzbN7N80T的算法就可以了。
另外網上有人說這是用的瑞數的產品,介紹里有這樣一段話
>通過對服務器網頁底層代碼的持續動態變換,令攻擊者無法讀懂攻擊目標
?
也就是說這個產品只提供了動態混淆功能,真實的加密代碼還是源網站實現的。也就是說只要提取出原來的加密邏輯就可以了。
?
## 準備工作
### 搭建離線分析環境
因為加密Js代碼每次請求變量名都不一樣,在線分析會很不方便,所以需要將文件離線下載到本地,再進行分析。
wget --mirror --page-requisites --adjust-extension --no-parent --convert-links http://wenshu.court.gov.cn/Index
python -m SimpleHTTPServer 8081
之后在瀏覽器中訪問http://localhost:8081進行分析。
?
### 修改頁面
為了分析方便,我們把加密js提取成獨立的文件(保存為outer.js, 并在文件開頭加上debugger;代碼下斷點), 并注釋跳轉代碼。修改后Index.html代碼如下
<!DOCTYPE?html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Transitional//EN"?"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"> </head> <body><meta?name="renderer"?content="webkit"><meta?id="9DhefwqGPrzGxEp9hPaoag"?content="{qqqqqr0.YUQeBgClraT6.dA28Ej3I1UKSbXlJ8NIUKxHc2UmGAqqkknLqqqqhvefgTey0JSvqkxJqkqLWqqqqk130r0HMvpQpmzDUlrUpmQ83oYJA2wDVVYY1mrWY0f3s2ptVlNp1aqqqqt1073741856VIJRJg9UB18SE49UPp8fH8h5lq2Y8psLYtXTCqAg2iGacfA3Tt9GOFqTs8GTGDCQwHGz5oKqQHAe4oO7h8mEBKcWqqqqhTrB4MbBgeoxqKGKR2zkG8iNtX0bwqfYF_uGc80qqqqr0qqDe5191aqqqqhb6rmecbj1Zrr4q{WYozbAKrlMPE9mOVpEiZygKFg3hxX_u.SidW64uobWi227DF_MXET5u6NJI74gv.axiEcePMvHIL_qqqqYDUvHttHp6whZmAp7KOQtW}{tPgKp0pIU0AtpYJcsagEUlJps2JlmANpsGAEYVpUpYTioaNA1TxHIAGCFAr7xGAWwAl8k67pUumcIlQ.D6xnhSSgVfzZDmg4DfzoD6a5KcrDWfEURnTmlm9dRn2PWS7TAOwGmVRXKcx9JULM3rRrHpLfrkJrlK3DlPwMrl9cF0gtD07cUaLUV20v8YShrYWSMSRZD90l8OSvxbzc8saEAG|qqU7aWVE0A9yYlv7CMX9T4THtVhmE4UX0Fjfh_vIdsiNUgCd3JJSPa6hZsZfcgVuLJzRXgkkhAWrC4uoKF82V.vbXKITtyVsSpIJvy9.SY5zYeuUlWzJG_lkrJwYoaucRQQg6y96Ch5rsnbU71HJ.nkkD85xjOoscMWRbGCiHUXy74mDJRW00e0.UV8f7ZDsBQIzOfuDJYjeBdCbXMhlCyCjW8hzMPlbWR_w.LKKFwywal7445"><!--[if?lt?IE?9]><script>document.createElement("section")</script><![endif]--><script?type="text/javascript"?src="4QbVtADbnLVIc/c.FxJzG50F.js%3FD9PVtGL=e5191a"></script> <script?type="text/javascript"?src="outer.js"> </script> <script?type='text/javascript'?r='m'> _$hr('ZoA8'); </script> <!-- <script?type="text/javascript">window.οnlοad=function(){var?_$n6=document.getElementById(_$fv('ondoal'));_$nR(_$n6.name,_$vD(_$n6,_$zb('HvzED2ExKa')));};</script> --> </body> </html> <script?type="text/javascript">_$e3();</script>?
### function hook
js中有幾段很長的雜亂字符串,猜測可能是加密的js代碼。而一般釋放加密的js代碼都是通過eval函數,所以我們需要hook它。在console面板中執行如下代碼
?
orig?=?window.eval; window.eval=function(str){debugger;orig(str);} //?這段代碼防止反hook的檢測 window.eval.toString?=?function?(){return?orig.toString();}?
另外為了分析meta#9DhefwqGPrzGxEp9hPaoag的content屬性,執行如下代碼添加斷點
var?dom_get_element?=?document.getElementById; document.getElementById?=?function(id){if(id=="9DhefwqGPrzGxEp9hPaoag")?debugger;?dom_get_element(id);}?
### 監視cookie變動
在Watch面板中添加document.cookie監視cookie的變動。
?
## 分析過程
### 釋放變量替換表
在瀏覽器中打開http://localhost:8081/wenshu.court.gov.cn/, 運行到out.js第一行會在debugger處觸發斷點。單步跟進,在第18行觸發了eval函數
?
_$tU[_$xH(101,?118,?97,?108)](_$bY(_$fv('mScBdId1eg4by76`TeugShBfzo.rNcva2COdfAI`wtMiRgUsYisepuH`Juhsxro_m`karh`l0gGtJSFr}ne`oremihar[o)elavpnyisclut`acslre?`allcdlwvt`?phnt`moOacienmrtnCop`JehTdmPo`tlsston`epvTls$lt#`_omatSeooaee`___suger@eeaaultv`.hprrtSgetcijeIntmeeb``SOBe`nr`ao``rcttt`p:`oxtcdconriSiene?esyaokopppyirdAxAfSOFjrcb.un`emtTdec`iAtaecaeuatl`vd`beg$M`tt`bos`uo`tcilg`fnorCsatCedo`rphl``opli``tsneltNfNizeU?liBhScFiutoe`a5`Za_lgrCp0aneafXn7tjoLeba9(P{Gn8tQvFc3dK]V`1xAzi5WFtqEcDlt___`rgmrvtIlec`l_sc_a`sayretcIneo`euwe3ixtysgmbd6aV`_owtCc`latce'),?_$fv('fMXn49KE26OfLRGSmXasroZMmPl16kBsoQjPPs8oqAhSbglTjrijvsmkkafjulimrcbkhgmmemcnavgjgplhmafjpiqkahdk')));?
這會在瀏覽器中釋放如下代碼
?
var?_$mM="FSSBBIl1UgzbN7N",_$gn="length",_$k9="floor",_$cE="charCodeAt",_$m6="string",_$lf="slice",_$uO="uu",_$i2="substr",_$rK="_$",_$b4="Math",_$hX="log",_$mf="toString",_$jZ="fromCharCode",_$ir="apply",_$va="split",_$mm="assert?failed?with?condition:?",_$kG="stack",_$fL="pop",_$jR="indexOf",_$aS="Object.InjectedScript.evaluate",_$kX="@debugger",_$ss="evaluate",_$jo="charAt",_$rM="getTime",_$el="number",_$cb="FSSBA",_$ah="Array",_$gq="prototype",_$g8="execScript",_$lP="eval",_$hs="call",_$po="replace",_$jA="functioneval(){[nativecode]}",_$vS="FxJzG50F",_$ng="qrcklmDoExthWJiHAp1sVYKU3RFMQw8IGfPO92bvLNj.7zXBaSnu0TC6gy_4Ze5d",_$mT="document",_$kP="location",_$h1="random",_$kk="setTimeout",_$is="setInterval",_$jQ="$_ts",_$aP="localStorage",_$mj="___ts___",_$fo="removeItem",_$pB="__#classType",_$q6="console",_$al="wP3dxhyJgpbC6tVm_ewcCO",_$dm="match";我們將這段釋放的代碼保存到文件reference_map.js。
?
### 釋放inner.js
在out.js中刪除第18行釋放代碼,并把得到的reference_map.js引用進Index.html。繼續調試,在180行有如下代碼
var?_$n6?=?_$zk[_$vS]; if?(_$n6)?{_$zk[_$vS]?=?false;_$tM(_$n6); }其中_$n6的值為4QbVtADbnLVIc/c.FxJzG50F.js中那段很長的字符串。猜測_$tM函數將對這個字符串解密并釋放。
在440行代碼(_$tM函數中)_$mc(_$eG(_$qh.join('')));執行后,會發現cookie值被更新了。
分析發現_$eG(_$qh.join(''))的返回值一段文本形式的js代碼,而_$mc函數的作用就是執行這段js。我們將這段js保存到文件inner.js。
?
### 調試inner.js
在Index.html中引入inner.js,去掉outer.js的斷點并注釋掉440行代碼,調試inner.js, 發現inner.js釋放了一個更大的變量替換表,其中cookie引用_$f0 = "cookie", 通過在inner.js搜索該變量,在所有更改cookie的地方下斷點,進行調試可以找出cookie的計算邏輯。
cookie的值通過解密meta#9DhefwqGPrzGxEp9hPaoag的content屬性得到。
在804行的 _$oc函數中有如下代碼
?
function?_$oc()?{_$fM(_$sw,?_$g9,?_$u9);_$fM(_$sw,?_$da,?_$v9);_$fM(_$sw,?_$kp,?_$bV);_$fM(_$sw,?_$aE,?_$wV);_$fM(_$sw,?_$vL,?_$xm);_$fM(_$sw,?_$sS,?_$ta);_$fM(_$sw,?_$s3,?_$hb);_$fM(_$sw,?_$an,?_$xx);_$fM(_$sw,?_$bJ,?_$tI);_$fM(_$sw,?_$qB,?_$wE);_$fM(_$tU,?_$is,?_$sz);if?(_$sw[_$bo])?{_$fM(_$sw,?_$tf,?_$sz);_$fM(_$sw,?_$cl,?_$sz);_$fM(_$sw,?_$vQ,?_$sz);}_$fM(_$tU,?_$sl,?_$vu);//?window.addEventListener('load',?_$tk),?即在頁面加載完畢后更新一次cookie_$fM(_$tU,?_$is,?_$tk);//?每50秒更新一次cookie_$tU[_$hD](function()?{_$uD(10);},?50000);根據變量替換表得出,這些代碼注冊了各種監聽事件,并且通過interval定時更新cookie。
?
#### url中的MmEwMD參數
在每個請求的url后面都有個MmEwMD參數,
在console面板中執行
var?xhr?=?new?window.XMLHttpRequest(); xhr.open('POST','/hello',true); xhr.send('abc');會在請求的Url后面自動添加上這個參數
http://localhost:8081/hello?MmEwMD=1zXMRFfiFy00rBpdSoJ2cJ4EvS6mQ1dvl5jZLrqB…oRVu5t.x8Y3GVQLmqdG.lmuE2snbEk.YHif4rmHwOtKQoTiHpODCa6HikgWg1X2S._aq8rKTLr
猜測當前頁面中的xhr被hook了。
通過查找inner.js釋放的變量替換表并分析,定位到inner.js的8107行代碼
function?_$xc(_$v8,?_$vz)?{var?_$xB?=?[];var?_$mE?=?_$qS(6);if?(_$mE)?{_$xB?=?_$xB[_$lt](_$vz);_$xB.push(_$c9(_$v8)???1?:?0);var?_$vT?=?_$h6()?+?_$mE?+?_$cR(_$xB);_$vT?+=?_$tc(_$vT);return?_$y5?+?'='?+?_$vT;}?elsereturn?_$y5?+?'='; }這段代碼的作用是計算請求url中的MmEwMD參數值。通過hook XMLHttpRequest的open與send函數,在發起異步請求時在url后面自動添加這個參數。
function?_$dJ()?{var?_$v8?=?_$tU[_$ld];var?_$v8?=?window.XMLHttpRequest;if?(_$v8)?{var?_$vz?=?_$v8['prototype'];if?(_$vz)?{_$jv?=?_$vz['open'];_$ca?=?_$vz['send'];//?hook?open函數,在調用open時計算token并保存到sig屬性_$vz['open']?=?function()?{arguments[1]?=?_$aY(arguments[1]);this['sig']?=?arguments[1];return?_$jv['apply'](this,?arguments);};//?調用?send發起異步請求時,將sig添加到url。_$vz['send']?=?function()?{arguments[0]?=?_$uG(arguments[0],?this['sig']);return?_$ca['apply'](this,?arguments);};} }## 總結
網站的加密邏輯大致如下:
1. outer.js釋放加密參數,并解密c.FxJzG50F.js文件,得到靜態混淆的js代碼(inner.js)
2. 執行inner.js,解密標簽meta#9DhefwqGPrzGxEp9hPaoag的content屬性得到一個數組,再加上outer.js計算的兩個參數計算FSSBBIl1UgzbN7N80T的值;
注冊load事件在加載完畢后添加interval定時,根據已有的cookie值計算得到新cookie值(通過_$tk函數);
hook XMLHttpRequest的open與send函數,為頁面中的請求自動添加token。
?
?
繞過方案:
因為cookie是通過定時自動更新的,而且請求的token也是通過hook在發起請求時自動添加的,所以如果讓瀏覽器先加載首頁,在首頁中使用xhr異步請求,請求的cookie值與token會自動帶上。所以我們可以找到一個可編程的瀏覽器就行了。
總結
以上是生活随笔為你收集整理的瑞数(裁判文书)js的加密分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Pyppeteer库之四:Pyppete
- 下一篇: 某数加密的流程与原理简析