學(xué)語言我個(gè)人還是覺得首先了解他的特點(diǎn)和適用場(chǎng)景,然后就是動(dòng)手干(官方文檔+g出來的一大堆ref)。寫慣Java的人,一旦介入到動(dòng)態(tài)語言,就會(huì)覺得一身輕松。Python可以采用交互的命令行工具,即時(shí)寫,即時(shí)看,也可以搞個(gè)eclipse插件和Java一樣寫。用了urllib庫和cookielib庫,幾句話就可以提交請(qǐng)求和保持cookie了。
接下來就是去看需要登錄網(wǎng)站的登錄模式。看了一下這個(gè)網(wǎng)站沒有走https,但是也不是很簡(jiǎn)單的明文傳輸,那么就要用個(gè)工具看看怎么回事了。Chrome和firefox + firebug都是極佳的工具(以前在IE下搞過破解版的httpwatch,太麻煩了),后面就用chrome來做介紹,它內(nèi)置的控制臺(tái)還是很強(qiáng)大的,包括我這里沒有介紹的性能檢測(cè)部分的功能。
首先你需要記錄下你進(jìn)入這個(gè)登錄首頁時(shí)候所有的http請(qǐng)求,不是說一定只記錄臨門一腳的提交請(qǐng)求就可以了,現(xiàn)在為了防范CSRF等攻擊,都會(huì)做一些安全方面的preload page,下面就一張圖一些描述來說明這個(gè)過程:
這張圖是用chrome來記錄進(jìn)入頁面到點(diǎn)擊提交過程中所有的請(qǐng)求,其中紅色圈圈中的那個(gè)紅色點(diǎn)就是記錄所有的請(qǐng)求,就算當(dāng)前頁面被重新載入或者302跳轉(zhuǎn)到其他地方去,前面的記錄依然存在,這很有必要,不然登錄成功后就找不到前面的記錄了。可以看到紅色的圈中有一個(gè)prelogin的頁面,當(dāng)然現(xiàn)在還不好確定干啥用,接著往下看。
選中這個(gè)prelogin頁面,然后看到右面就會(huì)出現(xiàn)其相關(guān)內(nèi)容,可以選擇content看看它的范圍,結(jié)果是有范圍的,返回了三個(gè)值,其中nonce(隨機(jī)數(shù))常常被用于防CSRF攻擊或者防重放。至此還看不出什么端倪,接著看
Login.php是post類型的,多半就是提交驗(yàn)證的(當(dāng)然后面談到仔細(xì)去看兩個(gè)來回交互的js就可以很清楚的知道點(diǎn)擊的那個(gè)超鏈接的btn就是觸發(fā)這個(gè)提交)
選中login.php的這個(gè)post請(qǐng)求,直接看它的Form Data,里面就是所有提交的參數(shù),可以發(fā)現(xiàn)nonce,servertime都在此列,同時(shí)看password已經(jīng)被加密,而下面有個(gè)關(guān)鍵詞“wsse”,其實(shí)當(dāng)年在做webservice接觸的比較多,是一種避免用戶密碼明文傳遞的驗(yàn)證加密算法,有興趣的同學(xué)可以直接搜索一下,有一個(gè)pdf很清楚的說明了一切。其實(shí)這個(gè)頁面我反復(fù)不同的密碼請(qǐng)求了幾次,相同的密碼請(qǐng)求了幾次,最后確定哪些內(nèi)容是動(dòng)態(tài)變化的,哪些是固定的,最后其實(shí)就是password,nonce,servertime是變化的,其他都是固化的。這下就簡(jiǎn)單了,首先模擬請(qǐng)求prelogin,這直接看看prelogin的get中url便知如何請(qǐng)求,然后將結(jié)果拼湊到下一次post到login的請(qǐng)求中,但最后就是password怎么計(jì)算出來,先嘗試了直接用標(biāo)準(zhǔn)的模式來生成base64(sha(password+nonce+servertime)),結(jié)果不行,那么就要仔細(xì)看看js代碼了,其實(shí)從剛才到現(xiàn)在都是從現(xiàn)象來猜一些問題,真的不行的時(shí)候還是要靠看代碼。
找到了對(duì)應(yīng)的Dom元素,看到login_submit_btn是個(gè)超鏈接,然后用了一個(gè)啥都不做的js(很多網(wǎng)站都用這種模式,采用動(dòng)態(tài)add event listener的方式),這下就要找js代碼了。因?yàn)?/span>wsse機(jī)制就是在本地做好簽名,然后發(fā)送簽名到服務(wù)端,服務(wù)端做同樣的簽名,由于不可逆,所以保證了安全性和身份有效性,因此只要找到提交的js代碼,然后看清楚里面的簽名算法就可以搞定了。
網(wǎng)站的同學(xué)寫的很規(guī)范,都在head里面放了幾個(gè)js,其中sso顧名思義就是用來做登錄的,遂直接下載看看,結(jié)果:
由于上次仔細(xì)搞js還是4年多以前的事情了,現(xiàn)在完全落伍,看到這樣的代碼,以為就是直接用document.write執(zhí)行以下就可以了(原本以為就是用來壓縮的,其實(shí)還有混淆的功能,解也不能這么簡(jiǎn)單的解開),當(dāng)然此時(shí)我對(duì)于詞語的敏感最后還是幫助了我(我紅色標(biāo)注的地方),其實(shí)很多時(shí)候?qū)τ谝恍┈F(xiàn)象和詞語的敏感可以直接幫你在Google中找到答案。
用那種自以為可以的方式解開后卻發(fā)現(xiàn)還有一些js函數(shù)居然沒有出現(xiàn)@_@,一頭汗阿,此時(shí)反復(fù)去刷頁面看現(xiàn)象的時(shí)候,突然發(fā)現(xiàn)原來在另外一個(gè)浮起登陸的頁面提交登陸時(shí)候是明文的,就是去掉了pwencode=wsse和nonce及servertime,測(cè)試了一把,成功登錄并且進(jìn)入群頁面獲得了自己的所有群中信息。本來到此也就算了,因?yàn)槟康倪_(dá)到了,但是對(duì)于js混淆及調(diào)試心里還是有些不甘,所以停下原本要做的事,繼續(xù)摸索。
這是用chrome在線調(diào)試js的界面,你可以在右邊Event listener breakpoints中設(shè)置鼠標(biāo)點(diǎn)擊事件的debug,當(dāng)然也可以設(shè)置其他的方式,但是由于混淆和壓縮的緣故,左邊的js都是一條語句,調(diào)試很困難,不過可以看到右邊的call stack就好比java的調(diào)用堆棧輸出(當(dāng)然沒java那么強(qiáng)大)local可以觀察每次進(jìn)入不同的請(qǐng)求或者閉包時(shí)一些內(nèi)部變量的變化,總的來說調(diào)試正常的js一定是很強(qiáng)大的。
由于調(diào)試不成功,只好仔細(xì)的去看幾個(gè)js,幸好整個(gè)頁面就4個(gè)js,其中兩個(gè)一看就可以過濾掉,另外一個(gè)名字取得很怪,里面卻做了它不該做的事情,包括對(duì)于事件監(jiān)聽器的增加,頁面結(jié)構(gòu)的輸出等等,最后調(diào)用了sso那個(gè)js,又進(jìn)入死循環(huán)了。
想起了js壓縮混淆的事情,想了想花了太多時(shí)間了,感覺也許真的很難搞(我也咨詢了我們的前端專家,談到如果沒有源碼,光調(diào)試想搞清楚混淆的js工作會(huì)很困難),不過出于對(duì)混淆和壓縮原理的好奇心,就去搜索了一下(本來就是為了學(xué)習(xí)一下基礎(chǔ),也許哪天可以用在Java中),可前面提到的對(duì)參數(shù)使用(p,a,c,k,e,r)的敏感最后讓我看到了js壓縮比較出名的作品,同時(shí)他的blog也收錄囊中(以后慢慢看),最后自然找到了破解之法,翻譯出了那段混淆的編碼,得到了寶貴的算法,在微博中喊了一句:爽,hex_sha1("" + hex_sha1(hex_sha1(b)) + j.servertime + j.nonce),結(jié)束了這次前端探索之旅,下面是最后一個(gè)圖:
對(duì)于前端的內(nèi)行來說,這點(diǎn)雕蟲小技算不上什么,當(dāng)然從開頭我就寫了,記錄這個(gè)只是想說一些學(xué)東西的思維,要做深,這樣是遠(yuǎn)遠(yuǎn)不夠的,需要更加沉下心來積累很多背后的故事(比如說看完那個(gè)高手的blog,了解數(shù)據(jù)壓縮和混淆的機(jī)制,自己寫一個(gè)反混淆的代碼)。