2007年的時候,我在印度最大的國有銀行中的一家注冊了一個賬號,這個國家的銀行(政府或者民營)普遍所使用的技術與當前水平相比至少落后了10年。
2015年末,我賬號所在的銀行與外包公司合作,開發了一款手機銀行應用,分為安卓版和IOS版。這是一個典型的瑞典冬天的周末,沒有陽光的跡象,所以我決定留在室內,并研究一下這個應用。
0×00
我一開始是打算用安卓來進行測試的,但是一想起上次在安卓上安裝一個自簽名證書(用于Burp監聽)所遇到的挫折,我果斷選擇了iPhone6作為測試平臺。當你在安卓上安裝自簽名證書時,安卓會一直提醒你“第三方證書已被添加到您的設備的信任庫”,但是因為成本的關系你有時候不得不這么做(在企業環境或者測試環境中),再加上測試的過程中會一直看到討厭的提醒信息“您的通信可能被監控”,所以IOS是最好的選擇,我在MacBook Pro上運行Burp用來作為代理服務器。
0×01
Burp攔截到的初始請求顯示了與app進行通信的主機名和端口,這是一個中間件應用程序,之所以會這樣,那是因為銀行通常會從大型廠商購買軟件,比如說TCS 的Bancs、Infosys 的Finacle,、Oracle Finance 的Flexcube。因為這個手機銀行app是由多個不同的外包公司合作開發的,所以能夠有效的阻止核心API的曝光。在對OpenSSL進行研究之后,我發現這個中間件使用的是SSL3.0,并且可以被迫降到SSL2.0。
我嘗試通過Burp添加一個自簽名證書用來抓取請求/響應中的明文數據,結果發現很成功的就抓到數據了,這說明app沒有使用“證書鎖定”。考慮到這是一個銀行的手機應用,沒有使用“證書鎖定”就是一個史詩級的錯誤!
0×02
這顯然是一個不符合規范的架構或者說是不夠到位的代碼審查的案例。這個app的初始請求是向服務器確認是否有可用的更新,而這個請求是發生在你登錄前的。
這個更新請求會產生一個session ID,這個session ID可被重復使用來發起真正的請求(比如說查詢賬戶余額,存款名單),而這樣的行為是只有用戶登錄后才能發起的,這等于說是繞過了密碼驗證。下圖是我在未驗證登錄的情況下通過構造數據包來進行賬戶查詢的圖像。而且我說了這個session ID是不會失效的,請繼續往下閱讀。
0×03
當我在把玩這個app時,前端彈出了一個窗口(操作時間即將到期?),詢問我是否要重新登錄或者退出當前窗口。這樣的處理行為是正確的,我想知道這個計時是不是只在前端進行的,而后端卻沒有處理。
我的直覺是對的,后端并沒有設置會話失效控制,所以除非客戶端調用API銷毀session,否則你的會話IDs永不失效。
0×04
我測試了一下該app中接收賬戶的驗證控制的有效性。我發現接收賬戶必須存在于收款人列表中,如果這個賬戶不在收款人列表中,轉賬時屏幕就會彈出錯誤,要求你將接收賬戶添加至收款列表中。而添加一個新的接收賬號到收款列表中會要求輸入PIN(MPTIN會在0×05提到)。
事實上我一點都不會對“這個驗證是在前端進行”的這件事感到驚奇,
所以直接通過CURL調用轉賬的API就能繞過接收人/受益人賬戶驗證,我就能夠將錢轉賬到不在我的受益人列表中的賬戶。原本我還想測試其他的關鍵的流程(轉賬中的余額驗證,轉賬限制),但是這可能是違法的,所以我只能跳過了。
(從收到的來自銀行的響應數據,似乎能看出我上面提到的關鍵流程的驗證都是在前端驗證的)。
0×05
從上面提到的這些漏洞就可以寫一個嚴重程度為中高的POC了。在0×02和0×03中,只需要5行代碼就能枚舉所有用戶的記錄(當前賬戶余額和存款)。
我決定挖掘的更深一點。
在我挖掘的更深之前,我要先解釋一下此應用程序的身份驗證機制。
這里有兩個PINs(身份認證PIN[MPIN],交易授權PIN[MTPIN])。從名字來看就知道你可以用MPIN來進行登錄,用MTPIN來對重要的操作進行驗證,比如添加一個接收賬號到受益人名單中,轉義資金,創建一個新的定期存款,關閉現有的定期存款。這個應用中的用戶名為你的用戶ID[CID]。
一個有效的轉賬請求如下:
"mobileAppVersion=x.x.x&MTPIN==XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&channel=rc&entityId=XXX&beneficiaryAccount=123456789&serviceID=fundTransfer&appID=XXXXXXXX&txn_amount=100000&customerId=1337&transferType=XXXX&appVer=x.x.x&platform=iPhone&mobPlatform=iPhone&remarks=tt&accountNo=987654321"
在上面的請求中,發送者(ccountNo:987654321)正嘗試將100,000轉賬給受益人(beneficiaryAccount:123456789)。
當請求被反序列化后,會傳遞給如下的函數處理:
你發現錯誤了嗎?
問題出現在,這個validateAuthenticator方法會驗證MTPIN與用戶ID對應的MTPIN是否匹配,這兩者的值都是由用戶提交的,但是卻沒有驗證提交的用戶ID或者MTPIN是否屬于當前發送者。所以通過使用我的用戶ID和我對應的MTPIN,我能夠實現在任意賬戶間進行金額互轉。我用我們家庭中的賬戶進行了測試,發現甚至一些沒有開通網上銀行或者手機銀行的用戶也能通過這種手段進行轉賬。
如下面的圖片,1303是我的用戶ID的后4位,列表中是我賬戶關聯的其他用戶的ID。(SB-存款賬號,RIP-定期存款)。
如下是我做的一個成功的交易。你可以看到我構造了一個請求,請求中用到的是我的用戶ID和我的MTPIN,但是發送者賬戶(6254)卻不是我的。(= = 作者的圖掛了,各位腦補下吧!)
我快速的用bash寫了一個13行的代碼,供給銀行或者外包進行測試。
0×06
用手機銀行進行轉賬時,銀行會給當前賬號綁定的手機號發送短信即時通知,問題是在這里他們又處理錯了。
發送提醒短信的代碼和上面的代碼是類似的:
和0×05相似,要發送提醒短信的手機號碼是從客戶ID中獲取的,而不是賬戶號碼。因此,當攻擊者竊取了受害者的資金后,提醒短信會發送到攻擊者那,而不是受害者。(作者的圖掛了,各位就再腦補一次吧!)
0×07
我很快速的寫了一個poc,然后在2015.11.3號將此poc發給了該銀行的一堆總經理、副總經理、IT經理、部門經理,一個禮拜過去了都沒有收到任何回復。8天后,我收到了該銀行的一個非官方的確認信息(該銀行的一個中層經理)說他們正在調查這個問題。大概第9/10天左右,開發該app的外包公司的副總裁訪問了我的linkedIn主頁。最后在第12天的時候,我收到了來自該銀行的副總經理的官方回復,他們基本上采用了我提交的漏洞修復建議。這讓我有點驚喜的同時也讓我感到害怕,他們居然用了12天的時間來回應我,并且就像在說“嘿,你的數十億身價存款有風險”,真是太令人吃驚了。
我回信詢問漏洞何時會被修復以及是否會為此漏洞提供賞金,鑒于這家銀行有將近250億美元的存款(2015年的數據),為什么不嘗試著要點賞金呢,但是就如預期的一樣,他們沒有再回復任何信息了。
所以這就是印度,這么大的漏洞0賞金!