应用攻击性逆向工程于Facebook Gameroom
去年年底,我受邀参加Facebook的Bountycon活动,这是一个仅限邀请的应用安全会议,包含实时黑客攻击环节。虽然参与者可以提交任何Facebook资产的漏洞,但Facebook邀请我们重点关注Facebook Gaming。之前测试过Facebook的资产,我知道这将是一个艰巨的挑战。多年来,他们的安全控制越来越严格——即使是跨站脚本这样的简单漏洞也很难找到,这就是为什么他们为这些漏洞支付如此高的奖金。因此,顶尖的白帽黑客倾向于从第三方软件角度接近Facebook,比如Orange Tsai著名的MobileIron MDM漏洞利用。
由于时间有限(由于管理问题我也开始得晚),我决定避开全面的漏洞研究,专注于对Facebook Gaming访问控制的简单审计。然而,移动和Web应用程序都得到了很好的保护,正如人们所期望的那样。经过一番挖掘,我发现了Facebook Gameroom,这是一个用于玩Facebook游戏的Windows原生客户端。我开始了一段启发性的旅程,将攻击性逆向工程应用于原生桌面应用程序。
Facebook Gameroom,这是谁?
如果你没听说过Facebook Gameroom,可能不止你一个人。Gameroom于2016年11月发布,被吹捧为支持Unity、Flash以及最近HTML5游戏的Steam竞争对手。然而,近年来Facebook已将注意力转向其移动和Web平台,尤其是随着流媒体的兴起。事实上,Gameroom计划于今年6月退役。幸运的是,在活动期间它仍然活跃。
我注意到的第一件事是Gameroom不需要任何提升权限即可安装。它似乎是一个分阶段安装程序,其中最小安装程序从Web拉取其他文件,而不是单体安装程序。确实,我很快在C:\Users\<USERNAME>\AppData\Local\Facebook\Games
找到了安装目录,因为大多数用户级应用程序都放在C:\Users\<USERNAME>\AppData
文件夹中。该文件夹包含许多.dll文件以及几个可执行文件。有几件事引起了我的注意:
- Gameroom自带捆绑的7zip可执行文件(7z.exe和7z.dll),可能已过时且易受攻击。
- Gameroom在Cookies SQLite数据库中存储用户会话数据,这对攻击者来说是一个有吸引力的目标。
- Gameroom包含CefSharp库(CefSharp.dll),经过进一步研究,发现这是一个用于C#的嵌入式基于Chromium的浏览器。
第三点表明Gameroom是用.NET框架编写的。.NET框架允许程序编译成通用中间语言(CIL)代码而不是机器代码,这些代码可以在通用语言运行时应用程序虚拟机中运行。这样做有几个好处,包括更大的互操作性和.NET应用程序的可移植性。然而,由于它们被编译为CIL而不是纯机器代码,将这些应用程序反编译回近源代码也容易得多。
对于.NET程序集,DNSpy是事实上的标准。逆向工程师可以轻松使用DNSpy调试和分析.NET应用程序,包括实时修补它们。我将FacebookGameroom.exe放入DNSpy并开始工作。
徒劳的追逐:搜索易受攻击的函数
我开始搜索易受攻击或危险的函数,比如不安全的反序列化。如果你参加过Offensive Security高级Web攻击和利用课程,你会非常熟悉反序列化攻击。我不会在这里详细讨论它们,但要知道它涉及将数据类型转换为易于传输的格式并转换回来,如果处理不当,可能导致严重漏洞。例如,Microsoft在其代码质量分析器中警告不要使用BinaryFormatter,并明确表示BinaryFormatter不安全且无法使其安全。
不幸的是,BinaryFormatter出现在我对“Deserialize”字符串的搜索中。
然而,我需要找到易受攻击的代码路径。我右键单击搜索结果,选择“Analyze”,然后沿着“Used By”链向上查找Gameroom使用BinaryFormatter.Deserialize的位置。
最终,这引导我到了System.Configuration.ApplicationSettingsBase.GetPreviousVersion(string)
和System.Configuration.ApplicationSettingsBase.GetPropertyValue(string)
函数。Gameroom在启动时使用反序列化函数检索其应用程序设置——但从哪里?回顾安装文件夹,我找到了fbgames.settings
,结果是一个序列化的blob。因此,如果我将恶意的反序列化有效负载注入此文件,我可以获得代码执行。然而,在此之前,我需要找到一个反序列化小工具。基于已知反序列化小工具列表进行更多搜索后,我发现Gameroom使用了WindowsIdentity类。
有了这个,我制定了一个代码执行概念验证:
- 使用ysoserial反序列化攻击工具,我生成了代码执行有效负载:
ysoserial.exe -f BinaryFormatter -g WindowsIdentity -o raw -c "calc" -t > fbgames.settings
。 - 接下来,我将
fbgames.settings
复制到C:\Users\<YOUR USERNAME>\AppData\Local\Facebook
并替换原始文件。不需要管理员权限,因为它位于用户目录中。 - 最后,我打开了Facebook Gameroom,计算器弹出了!
尽管获得代码执行令人兴奋,但与Facebook团队进一步讨论后,我们一致认为这不符合他们的威胁模型。由于Gameroom作为用户级应用程序执行,没有机会提升权限。此外,由于覆盖文件需要某种程度的访问权限(例如通过恶意Facebook游戏,需要批准才能公开列出),没有可行的远程攻击向量。
我在原生应用程序带来的不同威胁形势中学到了重要一课——在深入研究代码级漏洞之前,先寻找可行的远程攻击向量。
策划成功之路
你是否曾点击电子邮件中的链接并神奇地启动了Zoom?幕后到底发生了什么?你刚刚使用了一个自定义URI方案,它允许你像打开Web上的任何其他链接一样打开应用程序。例如,Zoom注册了zoommtg:
URI方案并解析像zoommtg:zoom.us/join?confno=123456789&pwd=xxxx&zc=0&browser=chrome&uname=Betty
这样的链接。
类似地,我注意到Gameroom使用自定义URI方案在点击Web浏览器中的链接后自动打开Gameroom。在搜索代码后,我意识到Gameroom在FacebookGames\Program.cs
中检查fbgames:
URI方案:
|
|
如果Gameroom已使用fbgames://
URI打开,它将在SchemeHelper类中解析它:
|
|
如果URI具有gameid
主机,它将使用SchemeHelper.SchemeType.Game
解析它。如果它使用launch_local
主机,它将使用SchemeHelper.SchemeType.LaunchLocal
解析它。我从有希望的launch_local
路径开始,追踪到FacebookGames.SchemeHelper.GenLocalLaunchFile(Uri)
:
|
|
不幸的是,尽管我可以通过像fbgames://launch_local/C:/evilapp.exe
这样的URI启动系统中的任何任意文件(如Facebook文档所述),但这会被确认对话框阻止。我尝试使用格式字符串和非标准输入绕过此对话框,但找不到方法。
我回到了gameid
路径,它基于URI中的游戏ID打开Facebook URL。例如,如果你想在Gameroom中启动Words With Friends,你将在浏览器中访问fbgame://gameid/168378113211268
,Gameroom将在原生应用程序窗口中打开https://apps.facebook.com/168378113211268
。
然而,我意识到GetGameSchemeId
(从URI中提取ID以添加到apps.facebook.com
URL)并没有实际验证slug是否是有效ID。因此,攻击者可以将原生应用程序窗口重定向到Facebook上的任何其他页面。
|
|
例如,fbgame://gameid/evilPage
会将Gameroom窗口重定向到https://apps.facebook.com/evilPage
。
但我如何重定向到Gameroom中攻击者控制的代码?有几种选择,包括滥用apps.facebook.com
上的开放重定向。不幸的是,我当时手头没有。另一种方法是重定向到允许嵌入带有自定义代码的iframe的Facebook页面或广告。
此时,我遇到了障碍。重新审视GetGameSchemeId
的代码,它只获取URI路径中的第一个slug,因此fbgame://gameid/evilPage/app/123456
会将原生应用程序窗口定向到https://apps.facebook.com/evilPage
并丢弃/app/123456
。
幸运的是,还有额外的代码小工具我可以使用。Gameroom中使用的Chrome版本非常过时:63.0.3239.132——当时的当前版本是86.0.4240.75。因此,它不支持新版本的Facebook页面。经典Facebook页面版本接受一个sk参数,使得https://apps.facebook.com/evilPage?sk=app_123456
指向带有攻击者控制代码的自定义标签页https://apps.facebook.com/evilPage/app/123456
!
但我如何在我的自定义方案中注入额外的查询参数?记住Gameroom会丢弃第一个URL slug之后的任何内容,包括查询参数。或者真的吗?回顾FacebookGames/SchemeHelper.cs
,我找到了GetCanvasParamsFromQuery
:
|
|
在传递自定义URI之前,GetCanvasParamsFromQuery
会查找canvas_params
查询参数,将其序列化为JSON字典,并将其转换为新URL中的查询参数。
这引导我到了最终的有效负载方案。fbgames://gameid/evilPage?canvas_params={"sk":"app_123456"}
将被Gameroom解析为原生应用程序浏览器窗口中的https://apps.facebook.com/evilPage/app/123456
,然后执行我的自定义JavaScript代码。
如前所述,原生应用程序的威胁形势与Web应用程序非常不同。通过将嵌入式Chrome原生窗口重定向到攻击者控制的Javascript,攻击者可以继续对3年旧的嵌入式Chromium浏览器执行已知漏洞利用。尽管尚未公开发布完整的漏洞利用,但我能够利用CVE-2018-6056概念验证代码通过类型混淆漏洞使Chrome引擎崩溃。
或者,攻击者可以创建本质上是合法原生MessageBox的弹出框来执行网络钓鱼攻击,或尝试读取缓存的凭据文件。幸运的是,与集成Node.JS API的Electron应用程序不同,CefSharp限制了API访问。然而,它仍然容易受到Chromium和第三方库漏洞的影响。
总结
Facebook将其评为高危并随后修补了该漏洞,将我推入Bountycon的前10名排行榜。尽管Gameroom即将关闭,但它肯定给我留下了一些美好的回忆(和实践)在基本的攻击性逆向工程中。对于应用程序逆向工程的新手来说,Electron、CefSharp和其他基于浏览器的框架是一个很好的起点,用于测试Web相邻的弱点,如跨站脚本和开放重定向,同时利用仅限桌面的代码执行向量。