Case study – Open Redirect
Most of us are familiar with the ‘Open Redirect’ vulnerability; an OWASP top 10 vulnerability that takes advantage of a situation in which the application receives a parameter from the client and uses it to build the URL location to which the user is redirected, without performing sufficient validation on the received input.
Typically, attackers can exploit vulnerable applications in order to perform phishing attacks, redirecting the victims to phishing sites that look exactly (or partially) like the vulnerable application. The victims tend to believe they are still in the original website, and provide their credentials in order to perform the required login. Unfortunately, these credentials are sent directly to the attacker.
A Classic Open Redirect Scenario
The following image demonstrates a vulnerable website (victim-site.com), which is vulnerable to the common open redirect scenario; a login page that will redirect the user to the page specified in the ‘returnURL’ parameter after successful login (the rectangle outlines the URL of the index page):
In the following code snippet, we can see the outlined vulnerable code, which receives the redirect page from the client, in the ‘returnURL’ parameter, and set it directly to the “Location” header:
The following image shows the client request and response from the server. It is possible to see that the ‘returnURL’ parameter value in the request, is then used in the “Location” header in the response:
Exploit the Vulnerability
An attacker can exploit this vulnerability in order to redirect the victim to malicious phishing website, simply by sending him the following URL: http://victim-site.com/login.php?returnUrl=http://attacker-site.com
(To obfuscate the phishing site, the attacker can use:
%68%74%74%70%3a%2f%2f%61%74%74%61%63%6b%65%72%2d%73%69%74%65%2e%63%6f%6d, which is a URL encoded version of the website).
The phishing website will mislead the victim and lure him to inserting his credentials again and sending them directly to the attacker.
Test ccenario – a Bad solution
In many occasions, the solution to prevent open redirect attacks is against best practice does not completely mitigate the problem.
The following code snippet image outlined the wrong mitigation for open redirect vulnerability that I came across in several applications:
The developer assumed that since the application contains a prefixed string set in the Location header, malicious attackers will not be able to affect the redirected domain. This point of view is actually quite logical at first impression, and as such – this is what happened when trying to exploit it:
We can see that the Location header is redirecting to a non-valid address which includes both the prefix domain and the parameter sent in the returnURL parameter. Therefore, we get:
So… why is it a bad solution?
If we simply add a dingle dot (.) before we add the phishing website, we will make the prefixed domain a subdomain for our phishing address. So, by sending the phishing URL (%2F is a URL encoding for a dot): http://victim-site.com/login.php?returnUrl=%2Fattacker-site.com
The result Location address would be: http://victim-site.com.attacker-site.com and the attacker will only need to create his phishing site under the subdomain victim-site.com instead of www.
Here we can see the server response, containing the prefixed domain as a subdomain to the phishing website, in the Location header:
And the successful redirection to the attacker’s phishing site:
Mitigation
There are a few ways to avoid open redirect attacks:
- The first and preferred solutions is to redirect based on index or UID instead of an actual link. For example, use redirection based on an internal mapping table:
{1:”http://victim-site.com/index.php”, 2:”http://victim-site.com/help.php”, 3:”http://victim-site.com/contact.php“, … }
In the server, accept only URLs that contain IDs of an existing index in the mapping table. For example:
https://victim-site.com/login.php?redirectURL=1
- Another way is to perform input validation in the server, on the received address. For example, using the following Regex:
^https:\/\/([a-z0-9]+\.){0,2}victim-site\.com\/.*$
- If you still prefer to use a prefixed string, remember to add the “/” at the end of it: http://victim-site.com/ to avoid being served as a sub-domain.
Leave a Reply
Want to join the discussion?Feel free to contribute!