Referer Redirection and Its Inconspicuous Danger

getrequestRecently I noticed some peculiar behavior on web application. I observed that in certain situations, the webpage would openly redirect to the ‘Referer’ header defined in the request. In this particular instance, the web application required some data from the user to perform that page’s function. When that data was not present, it would redirect back to the ‘Referer’. At first I thought that the redirection seemed pretty harmless, but after recognizing it as unsanitized input, I was determined to come up with a use-case as for when this behavior could be used for evil. The rest of this blog post will be talking about this use-case and how something as inconspicuous as a redirect based on a ‘Referer’ can be used for evil.

The Use-Case Theory

cheapzerodayzLet’s say there is a e-commerce site that has a page that handles payment. Hypothetically, this payment page takes all of the transaction metadata about this payment in the form of an encoded and encrypted blob in a GET parameter. If this data is present, it will pre-populate the various forms with the transaction information (total, account details, items, etc.) and may ask for additional information (credit card number, shipping address, etc.) before it can complete the payment transaction. This page’s main purpose and function will not work without passing in that transaction information. If a user visits this page and doesn’t present this information, there is nothing for the page to do. From a developmental standpoint it makes sense to redirect a user back to where they came from if they visit such a page in such circumstances, hence the redirect based on a ‘Referer’ header.

If we flip on our evil bit, we can see how this could be used for naughty things. This is a tad challenging because the victim’s ‘Referer’ header is not forgeable by an attacker. However, if an attacker created a link or controlled a link that is used by users to access this page, the ‘Referer’ header would be set to a page they control. The attacker could then modify the previously mentioned link to be striped of the needed transaction data and cause a redirect back to themself. If they track this user’s movement, in the form of a cookie, they could be cognizant of the redirect and spoof the intended payment page upon redirection. This is crafty because the link a user clicked is a valid URL from a trusted domain. If they are not aware of the redirection or the URL change, they may not notice and haphazardly enter their information into the spoofed page, which could then be harvested by the attacker.

Show Me Some Code!

I went ahead and made a mock payment page of this very nature, as seen above. In my use case, the blob in the URL is a simple base64 encoded JSON object that specifies what is being bought and how much it costs. Clearly this is not a secure method of handling this type information and is only done this way for proof of concept.dataobj

If this data is present at load time, JavaScript will parse and populate that information on the webpage. If the data is not present, JavaScript will redirect based on the Referer. Again, clearly this is not a secure way to handle this information. This logic should be handled server-side in a production setup, but is done here in JavaScript for proof of concept. This code can be seen here:

function displayOrRedirect() {
    // grabs data param from URL
    var dataParam = location.search.split('data=')[1]

    // if data exists, parse and update page
    if (dataParam) {
        var dataJson = JSON.parse(atob(dataParam));
        document.getElementById("itemforsale").innerHTML = dataJson.exploitName;
        document.getElementById("total").innerHTML = dataJson.cost;
        document.getElementById("total2").innerHTML = dataJson.cost;

    // if data does not exists, redirect to REFERER
    } else {
        window.location = document.referrer;
    }
}

With the basic payment page up and running, we can now write an exploit for it. We need to make an exploit page that simply shows a link to the payment page the first time the user visits and displays a phishing page after the user is redirected. To do this, we need to keep track of users with a cookie. When a first-time-visiting user visits the exploit page, we need to set a cookie and present them with a specially crafted link to the vulnerable payment page that does not contain the needed transaction data. If they click the link, they will visit the valid and trusted domain briefly. However, they will be be redirected back to the exploit page. The difference is that this time around, they have a cookie set, so the exploit page knows to spoof the vulnerable page instead of displaying a link like before. This can all be done via JavaScript and the exploit code can be seen below:

function checkCookie() {
    var beenHere=getCookie("myEvilCookie");
    if (beenHere == 1) {
        //cookie is already set, direct victim to local spoofed page
        window.location.href = "payment.html";
    } else {
        //cookie not set, setting cookie and presenting crafted link
        document.cookie = "myEvilCookie=1";
        document.write('Please fill out payment information here: <a href="http://cheapzerodayz.com/payment.html">http://cheapzerodayz.com/payment.html</a>');
    }
}

Now with our exploit page up and running, we need to spoof the valid and trusted page. This can most easily be done with TrustedSec’s Social Engineering Toolkit (see video for example). Since our proof of concept page is doing it’s “server-side” functionality in JavaScript, its important to remove this section of code from our newly spoofed site, otherwise you might end up in a infinite loop of redirection. Totes don’t know that from experience… ? Additionally, since the data blob is being stripped, it is important to modify our spoof’d page to statically contain any data the would normally get dynamically added from the data blob.

That’s it! Here’s a link to all of my proof of concept code on GitHub and here’s a video of it all in action.

The easiest way to mitigate this sort of technique is to display an error page instead of redirecting. That being said, if a developer insists on redirection, he or she could add some input sanitation of the ‘Referer’ header before redirecting to it. For example, only allow redirection if the ‘Referer’ is something from a list of trusted domains.

I enjoyed the challenge of coming up with this attack vector and its amazing how seemingly benign functionality can be leveraged to do evil. Thanks for reading.