Some Interesting URI Parsing Quirks and Open Redirects

Parsing the “relativeness” of a URI seems to be a pretty browser specific thing, and doing some quick tests there are several quirks that might be useful/dangerous. The Tangled Web (which is an awesome book) aludes to some of these.

Some URI Quirks

Let’s look at some tests with the URIs grabbed from the location header. The browsers I’m testing right now are IE9, Chrome 17 something, and Firefox 11.

All browsers are happy with this, and go to google.com

header(“Location: //google.com”);

Both Firefox and chrome truncate extra slashes
So

header(“Location: http:///////////////////////google.com“);

is completely happy.

IE is interesting, as it will be equally happy with and /

header(“Location: https:\\google.com\“); <– this works

The spacing doesn’t seem to matter, so all browsers are happy with:

header(“Location:                        http://google.com“);

as well as

header(“Location:http://google.com&#8221;);

My favorite is this. In chrome and Firefox

header(“Location: http:google.com”);

will redirect to a relative URI, but for whatever reason

header(“Location: https:google.com“);

will redirect to google.com. wtf?

Same Domain Redirect

These parsing quirks can be useful for several attacks, and the first thing that came to mind for me was open redirects.  It’s a pretty common scenario to want to allow sites  redirecting based on the parameter as long as it’s in the same domain. It can be expensive to whitelist every URI (which would be ideal), so although that’s a great solution, I also think allowing redirects to your own domain is sometimes better than nothing …despite there being some risks associated with it, like giving an attacker a way to bypass the IE8 XSS filter http://packetstorm.wowhacker.com/papers/general/msie-xssbypass.pdf.

So, below are some (broken) examples of websites trying to accomplish this, allowing a redirect but only to their own site.

Broken Example 1 – startswith /

One naive way to try to perform arbitrary on-site local redirects would be something like the following, which takes the redir query parameter and make sure it starts with a slash:

$redir = $_GET['redir'];
#if redir starts with /
if (strpos($redir, "/", 0) === 0)
header("Location: " . $redir);

Obviously, this can be bypassed in all browsers with //google.com

Broken Example 2 – No Semicolons, Can’t start with /, and in fact, don’t start with // either

This PHP tries to prevent off-site redirects with the following snippet

$redir = $_GET['redir'];
#make sure redir doesn't have slashes, and doesn't have semicolons
if ((strpos($redir, "/", 0) != 0) and (strpos($redir, "/", 1) != 1) and (strpos($redir, ":") === false))
{
header("Location: " . $redir);
}

Because you can prepend spaces, one way to bypass this is to send the following:

redir=%20%20//google.com

Broken Example 3 – No Slashes at all

Ok, what if there are no slashes are allowed at all? You can’t very well have http://blah.com without a slash, after all, so this intuitively might make sense. The code for this might look something like:

$redir = $_GET['redir'];
#if no / in the string
if (strpos($redir, "/") === false)
  header("Location: " . $redir);

However, using the quirks above, this can be bypassed by using redir=https:google.com in FF and chrome, and it can be bypassed in IE with redir=\google.com

Broken Example 4 – Built in Libraries:

Surely there are libraries that solve this problem. Well, maybe there are, but there are certainly libraries people use to try to solve this problem, but they don’t do it as people expect (e.g. a library might call a URI relative when a browser treats it as absolute). Making a library that works well is a fundamentally tough problem because all these browsers have quirks and the library has to match all browsers. So is a library supposed to call https:google.com a relative or a full uri? (it’s relative in IE but full in chrome and FF)

Here’s one C# example where someone might try to figure out if a URI is relative URI using the IsAbsoluteUri property in .net system.Uri.

        static void Main(string[] args)
        {

            String[] uriArray = new String[] {
                "//google.com/test.html",                 //relative
                "\\google.com\test.html",              //relative
                "/////////google.com/test.html",          //relative
                "https:google.com",                       //relative
                "http://google.com",                      //absolute
                "http:///////////////////google.com",     //absolute
                "           http://google.com"            //absolute
            };

            foreach (String uriString in uriArray)
            {
                try
                {
                    Uri uri = new Uri(uriString, UriKind.Relative); //works
                    if (!uri.IsAbsoluteUri)
                    {
                        Console.WriteLine("is a relative URI: {0}", uriString);
                    }
                }
                catch (UriFormatException e)
                {
                    Console.WriteLine("not a relative URI: {0}", uriString);
                }
            }
        }

Broken Example 5 – startswith Whitelisted Domain

This is a classic example. Even though it doesn’t have much do do with parsing quirks, it can be subtle and illustrates an important point.  So say an application does the following to make sure the redirect is on the correct domain.

String redir = Request["redir"];
if (redir.StartsWith("http://goodsite.com"))
{
	Response.Redirect(redir);
}

Can an attacker still exploit this? The answer is yes, by setting redir=http://goodsite.com.badsite.com/

What’s the Right Way to do on-domain Redirects?

So open redirects are in the owasp top ten, and they have some guidance here: https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards. However, to summarize, it basically says to whitelist and don’t redirect. I do agree, but again, what if you want to do on-domain redirects? The best I can think of is to do something like this:

startswith(http://goodsite.com/ || https://goodsite.com/)

Note the trailing slash, which prevents broken example #5.  I don’t think it’s possible to redirect off-site with this type of code… but if someone knows otherwise, I’d definitely be interested in how to do it :)

browsing with firefox, tor, refcontrol, and noscript on ubuntu

This is a topic that’s been covered a lot. However, it took a bit of research to find a solution that worked for me, so I thought I’d write about it here.

I am doing some research that involves a *lot* of google searches. Because this research involves a significant number of directed queries, it seems logical to hide this information as much as practical. If there is a web host who notices sequential names in a Google referer URL repeatedly, this might raise suspicion or alter behavior which could skew results. Similarly, it is desirable to hide IP information from both the web host (for similar reasons) and possibly even search engines.

First, to avoid any changes to usual browsing, a new firefox profile was created using:

firefox -ProfileManager

Additionally, to run both firefox profiles at once, the first was run as normal, which the second has the additional options:

firefox -P <new-profile> -no-remote

I add this to my taskbar alongside the regular old firefox %u so I can choose a profile with a click.

To hide the HTTP referer, a firefox extension called RefControl was selected  https://addons.mozilla.org/en-US/firefox/addon/953. This simply replaces the referer for every query with one that is configurable. Although this is certainly possible with a more traditional proxy (like paros), RefControl’s ease of use is essential with the shear number of queries that were performed for this research. For this research, I changed the referer passed several times from names like “yahoo.com”, “cnn.com”, etc. Although the traffic patterns may still seem suspicious to an administrator who carefully monitors his logs, it reveals virtually no information about what it is that is being searched for.

To obfuscate the IP address, tor and privoxy were used. Tor bounces the HTTP requests around a distributed network of relays all around the world. An in depth discussion of Tor is out of the context here, but in a nutshell “it prevents somebody watching your Internet connection from learning what sites you visit, and it prevents the sites you visit from learning your physical location” http://www.torproject.org/. Privoxy is additionally used to prevent applications like flash or dns from leaking information. Since both privoxy and tor are required, you need to install these:

apt-get install tor privoxy

and to get privoxy to work with tor, I uncommented the following line (if it’s not there just add it):

forward-socks4a / localhost:9050 .

Despite the advantages, this did make browsing for names quite slow. I really like torbutton. In the not so distant future I remember having to modify proxy settings every time I wanted to go back and forth using tor. With tor

Lastly, the noscript firefox plugin was used to mitigate all javascript based attacks that might be used to obtain IP information http://noscript.net/.

HTTP over SSH

It’s easier than you might think.

socks is actually built into openSSH, so its really a trivial matter to setup a local proxy.

$ ssh -D 12345 myuser@remote_ssh_server

will open up the port 12345 on localhost as a socks proxy and all your traffic can be specified to go through the tunnel and out of remote_ssh_server

For firefox 3, go to Edit->Prefrences->Advanced->Network->Settings

and set it to use a Manual Proxy, localhost, port 12345 socksv5