針對(duì)某APP的漏洞挖掘(抓包+逆向=挖到大漏洞)
寫(xiě)在前面
本人學(xué)習(xí)滲透測(cè)試(主要是Web方向)有幾個(gè)月了,現(xiàn)在算是剛剛?cè)腴T(mén)?;叵肫饘W(xué)習(xí)漏洞挖掘的過(guò)程,除了看一些經(jīng)典書(shū)籍外,最想看的就是大牛們挖漏洞的詳細(xì)過(guò)程,比如如何尋找目標(biāo),從哪里入手,遇到問(wèn)題怎么解決。但是,網(wǎng)上介紹知識(shí)的多,敘述過(guò)程的少(也可能是我的搜索姿勢(shì)不對(duì)……)。除了在烏云上有幾個(gè)大神有時(shí)會(huì)分享一些具體的挖洞思路外,大部分人還是“有圖有真相,一圖勝千言”。對(duì)于老司機(jī)來(lái)說(shuō),瞄一眼就知道是怎么回事了,但對(duì)于新手來(lái)說(shuō),往往是一頭霧水。因此,本人分享一下最近的一次挖洞過(guò)程,希望能夠拋磚引玉,大家踴躍分享自己的挖洞經(jīng)驗(yàn)。
PS:作為一個(gè)有操守的白帽子,本文重在分享思路與過(guò)程,細(xì)節(jié)處還是要打碼處理,畢竟不是來(lái)提交漏洞的。
尋找目標(biāo)
這次是針對(duì)我常用的一個(gè)手機(jī)APP(下文簡(jiǎn)稱(chēng):某APP)進(jìn)行漏洞挖掘,說(shuō)起來(lái)選擇某APP作為目標(biāo)也是挺偶然的。因?yàn)槲抑饕歉鉝eb滲透測(cè)試的,并沒(méi)有挖過(guò)手機(jī)APP的漏洞。有一天,在看別人分享Burp Suite的使用技巧的文章時(shí),發(fā)現(xiàn)通過(guò)Burp還能夠進(jìn)行手機(jī)APP抓包(畢竟Too young……)。光說(shuō)不練假把式,還是要自己動(dòng)手操練一番。先把Burp設(shè)置一下,在Proxy中Options下的Proxy Listeners中,點(diǎn)擊Edit,把Bind to address設(shè)置為All interfaces。
然后手機(jī)和電腦處于同一局域網(wǎng)中,給手機(jī)設(shè)置代理服務(wù)器,IP為電腦的IP地址,端口為Burp中的設(shè)置的端口,默認(rèn)為8080。這時(shí)候,就可以用Burp抓取手機(jī)的請(qǐng)求包了。
山重水復(fù)
這時(shí)候我就打開(kāi)某APP,執(zhí)行常見(jiàn)的操作,Burp中就記錄了大量的HTTP數(shù)據(jù)報(bào)文。然后,就是對(duì)Burp中截獲的報(bào)文進(jìn)行分析了。沒(méi)多久,一個(gè)請(qǐng)求就引起了我的注意。這是一條GET請(qǐng)求,請(qǐng)求的URL是類(lèi)似下面這種格式:
- http://www.example.com/path/get_some_data.jsp?id=1234567¶m1=value1¶m2=value2
直覺(jué)告訴我,這里很有可能會(huì)有越權(quán)漏洞。于是,我用瀏覽器打開(kāi)這個(gè)URL,果然直接就看到了用戶(hù)數(shù)據(jù)。換個(gè)id再試一下,把id加1,結(jié)果也是一樣的,都爆出用戶(hù)數(shù)據(jù)了。因此,到這里已經(jīng)確定某APP存在越權(quán)漏洞。
確定這個(gè)越權(quán)漏洞存在后,稍微平復(fù)一下心情,然后就發(fā)現(xiàn)這個(gè)漏洞造成的后果并不嚴(yán)重。因?yàn)檫@里通過(guò)帳號(hào)越權(quán)查看到的用戶(hù)數(shù)據(jù)中,并沒(méi)有包含一些比較敏感的數(shù)據(jù),比如姓名、手機(jī)號(hào)、身份證等。簡(jiǎn)單地說(shuō),就是可以越權(quán)查看到他人的數(shù)據(jù),但是“他人”是誰(shuí)并不知道,這樣來(lái)說(shuō)看到數(shù)據(jù)只是一堆無(wú)意義的數(shù)字而已。只釣到一條小魚(yú)有點(diǎn)不甘心,于是就繼續(xù)挖,應(yīng)該還有其他的漏洞存在。
繼續(xù)查看Burp捕獲的報(bào)文,這次重點(diǎn)查看登錄過(guò)程中提交的請(qǐng)求和返回的響應(yīng),想從這里入手深入挖掘一番。登錄的報(bào)文如下,可以看到,只有一個(gè)POST參數(shù)params,其值經(jīng)過(guò)了URL編碼。
把params的值解碼之后,發(fā)現(xiàn)是json格式的一串?dāng)?shù)據(jù),基本內(nèi)容如下:
其中,讓人感興趣的就是userId字段和body字段了,目測(cè)應(yīng)該分別對(duì)應(yīng)登錄的用戶(hù)名和密碼。然后我用相同的用戶(hù)名和不同的密碼、不同的用戶(hù)名和同樣的密碼分別登錄、抓包,然后解碼對(duì)比發(fā)現(xiàn),相同的用戶(hù)名對(duì)應(yīng)的userId值相同,相同的密碼對(duì)應(yīng)的body值也相同,這就證實(shí)了我的推測(cè)。進(jìn)一步分析發(fā)現(xiàn),userId和body的值都是十六進(jìn)制的數(shù)字串,userId的長(zhǎng)度為32位(這里指32個(gè)十六進(jìn)制字符,下同),body的長(zhǎng)度為128位。這就說(shuō)明userId和body的值都經(jīng)過(guò)了加密處理。對(duì)于userId,我首先想到是不是經(jīng)過(guò)了MD5?不過(guò)經(jīng)過(guò)計(jì)算用戶(hù)名的MD5和userId并不相等,也就是說(shuō),即便是MD5也加了salt。
分析到這里,暫時(shí)沒(méi)辦法繼續(xù)深入了。那就先放一放,分析一下登錄過(guò)程中返回的數(shù)據(jù)包,下圖是登錄成功之后返回的數(shù)據(jù)包。
一看返回的數(shù)據(jù)包直接傻眼了,明顯是經(jīng)過(guò)加密的。不過(guò),這里還是要注意一下返回的數(shù)據(jù)包長(zhǎng)度,因?yàn)槲夜室廨斎脲e(cuò)誤的密碼進(jìn)行登錄時(shí)(如下圖所示),返回的數(shù)據(jù)包長(zhǎng)度居然相差無(wú)及!并且也能看到,有許多相同的字符。很顯然,這里有很大的可能是有問(wèn)題的。
柳暗花明
到目前為止,雖然已經(jīng)把登錄過(guò)程中的請(qǐng)求報(bào)文結(jié)構(gòu)都分析清楚了,但是由于報(bào)文中的關(guān)鍵數(shù)據(jù)都進(jìn)行了加密處理,所以到現(xiàn)在幾乎仍然是一籌莫展。事實(shí)上我在這里卡了兩天,也沒(méi)什么好的辦法,甚至還想到過(guò)分析一下別人帳號(hào)登錄過(guò)程中的數(shù)據(jù)包然后破解出密碼的想法。不過(guò)仔細(xì)一想就覺(jué)得這個(gè)想法太不現(xiàn)實(shí),又不是密碼學(xué)專(zhuān)家,僅僅通過(guò)幾條密文就想破解加密過(guò)程,這怎么可能成功!盡管想法有點(diǎn)荒唐,但是還真給我?guī)?lái)了靈感:既然某APP發(fā)送的報(bào)文和返回的報(bào)文都是加密的,那肯定是在某APP中進(jìn)行了加密和解密的操作,那么如果能夠分析一下某APP的源碼,應(yīng)該就能夠搞清楚其中的加解密過(guò)程。那么問(wèn)題來(lái)了,哪里能得到某APP的源碼呢?
思來(lái)想去,最方便、最有可能的辦法就是將某APP進(jìn)行反編譯得到源碼。ios版的我就不想了,畢竟也沒(méi)搞過(guò)ios開(kāi)發(fā),直接去逆向肯定是不現(xiàn)實(shí)的。但是安卓版的還是有搞頭的,因?yàn)橹翱催^(guò)別人進(jìn)行APK逆向的文章,也寫(xiě)過(guò)Java代碼。說(shuō)干就干,網(wǎng)上搜一搜安卓逆向教程一大堆,畢竟咱只是想分析源代碼,并不是要搞脫殼破解,入門(mén)級(jí)的教程就能夠滿(mǎn)足要求,這里就不多說(shuō)了??傊?,將某APP反編譯之后,發(fā)現(xiàn)代碼進(jìn)行了混淆,但是并不影響分析,稍微費(fèi)點(diǎn)勁而已。經(jīng)過(guò)分析,果然有收獲。
首先,發(fā)現(xiàn)加解密使用了AES算法,并且加解密所用的密鑰是16位的。
繼續(xù)分析發(fā)現(xiàn),開(kāi)發(fā)人員居然把密鑰“幾乎”硬編碼在代碼中!密鑰總共16位,前面幾位是網(wǎng)站域名,再加上devId的前幾位,湊夠16位即是密鑰。而devId在登錄的請(qǐng)求包中是以明文出現(xiàn)的,這樣一來(lái),相當(dāng)于加密算法和密鑰我們都得到了。
到目前為止,分析的過(guò)程基本上就已經(jīng)結(jié)束了,是時(shí)候?qū)懘a驗(yàn)證一下分析結(jié)果了。用Python寫(xiě)了AES加解密的代碼,將userId和body進(jìn)行解密之后發(fā)現(xiàn),userId果然就是登錄的用戶(hù)名,而body的值則是如下json格式的字符串:
很明顯,password的值也經(jīng)過(guò)了加密,這里有可能就是計(jì)算了MD5,不過(guò)有可能加了salt。繼續(xù)分析源代碼,找到了對(duì)密碼進(jìn)行處理的過(guò)程,果然是加了salt的MD5!并且,salt也是硬編碼……
拿自己的密碼進(jìn)行驗(yàn)證,證實(shí)了上述分析。
意外驚喜
到現(xiàn)在為止,已經(jīng)可以偽造數(shù)據(jù)包進(jìn)行模擬登錄過(guò)程了。事實(shí)上,我最初的想法也是想偽造數(shù)據(jù)包模擬登錄進(jìn)行暴力破解的。不過(guò),在進(jìn)行暴破之前,還是先把返回的響應(yīng)報(bào)文解密看看。按照之前的分析,返回的報(bào)文肯定是有問(wèn)題的。
將響應(yīng)報(bào)文解密之后,果然帶來(lái)了更大的驚喜!前邊已經(jīng)提到,登錄成功返回的數(shù)據(jù)包長(zhǎng)度和失敗時(shí)返回的數(shù)據(jù)包長(zhǎng)度很接近,解密之后發(fā)現(xiàn),何止是長(zhǎng)度接近,內(nèi)容也有九成是一樣的!當(dāng)然,這都不是重點(diǎn),重點(diǎn)是不論登錄是否成功,都返回了用戶(hù)的真實(shí)數(shù)據(jù),包括姓名、手機(jī)號(hào)、身份證號(hào)以及正確密碼的哈希值,密碼完全就是形同虛設(shè)。不枉費(fèi)我一番心思,總算釣到大魚(yú)!
總結(jié)
漏洞挖掘的過(guò)程基本上結(jié)束了,之后提交漏洞的過(guò)程我就不廢話(huà)了。整個(gè)過(guò)程寫(xiě)起來(lái)有點(diǎn)像流水賬,但是卻把我挖掘漏洞的過(guò)程和思路寫(xiě)清楚了,總結(jié)起來(lái)就是:
多看多想多動(dòng)手實(shí)踐,有事沒(méi)事多抓包分析
Web方面的挖洞思路和軟件逆向相結(jié)合,帶來(lái)意想不到的驚喜
不要總想著暴力破解,那是沒(méi)有辦法的辦法
最后,希望此文能夠拋磚引玉,大家都能把自己的挖洞思路分享出來(lái)。挖漏洞有時(shí)候確實(shí)需要一點(diǎn)靈感,多學(xué)習(xí)一下別人的挖洞思路,肯定能夠?qū)ψ约河兴鶈l(fā)。