A lot of requendations about security are “don’t browse sites that you don’t know”. People can ask why is that. How visiting a website that i don’t fully trust can compromise me or other sites that I use.

Today I embarked on a quest to try to show people (and some shitty computer security firms that don’t consider this a vulnerability) why that’s absolutely wrong. Shortly I will setup an environment and perform the attack on a small lab to show you how to use it and how to defend against it. CSRF or cross-site request forgery is an attack that where a website makes an HTTP request to other site and triggers an action. This action can be, changing a password, creating a new user on the application (useful if there is an administration panel). This vulnerability appears on many security devices and the attacker can exploit them to whereas extent it wants, however some criteria are required for it to be successful: The attacker must know the complete address of the service The parameters for the call should be known, or at least, deterministic The victim should be already logged in

The first criteria could be met or by inside knowledge or OSINT (Open Source Intelligence) or scanning. A simple way is, imagine you are a pentester and you already are on the network and see a known security appliance that has a CSRF vulnerability to add users that will allow you to control, with high privileges the network perimeter. You know the appliance (Software), the version and the address, so it’s should be fairly straight forward to attack.

The second criteria comes with the first one, when you identify the software its easy to find the request that will trigger the attack. You can setup Burp to intercept the requests of the browser or you can simple use the developers tools on the main browsers (Chrome/Firefox) and navigate to the ‘Network’ Tab and inspect the traffic generated by a Web Application. By clicking on the request you can inspect all the parameters and check if there is any “csrf_token” parameter that will block our attack.

The third criteria is a bit of chance. If its a portal that we know the victim uses we will probably achieve our goal, otherwise we may not. Other techniques could be used link traffic inspection to check if its communicating with the server (if we check for the destination IP in a SSL/TLS connection).

In some environments with federal authentication (or similar) where the login is the same for all the Web applications on the same domain even if the victim didn’t login on the specific portal the session cookie still exists and can be used to access the portal nevertheless. I say can since some federal authentication services may require a confirmation before allowing the specific web application to continue.

Now with that in mind lets begin with our scenario. We have two Web sites the official site (at 192.168.155.114)and the attackers website (at 192.168.155.133). The official site is a site where a user has to login to make a transaction. For sake of brevity the official website has a predefined login with the username being “victim” and the password “pass”, by requesting the transaction a session variable is stored and saved not allowing any more submissions. Please disregard the other vulnerabilities on the site like the username and password being submitted via GET request we are not focusing on that right now. Here is the code for the official WebSite:

session_start();

if(!isset($_SESSION['logedin'])){

    if( isset($_GET["username"]) && isset( $_GET["password"])){
        if( $_GET["username"]==='victim' &&  $_GET["password"]==='pass'){
            $_SESSION['logedin']=true;

        }

    }else{
        echo '<form action="/bankpage/index.php">
	  Username:<br>
	  <input type="text" name="username"><br>
	  Last name:<br>
		  <input type="password" name="password">
	<input type="submit">
		</form>
			';
    }
}

if (isset($_SESSION['logedin']) && $_SESSION['logedin']==true)
{
    if(isset($_SESSION['transactions'])){
        echo 'Transaction
		<br>';
        echo $_SESSION['transactions'];

    }else{
        if(isset($_GET['transaction_number'])){
            $_SESSION['transactions']='Transaction Made='.$_GET['transaction_number'];
            header("Refresh:0");
        }

        else{
            echo 'No transactions have been made';


            //Make transaction
            echo '
	<form action="/bankpage/index.php">
	<input type="text" name="transaction_number" />
	<input type="Submit" value="Submit" />
	</form>
	';
        }

    }
}
#DONT FORGET THE PHP TAGS!

The attackers website is the one that, once visited, makes the cross site request and triggers the transaction. It’s just simple as that, just visit the website and before you know it, the attack has already been done. And here is the code for the attackers site:

<body>
<h1> ATACCKERS </h1>

<img src="http://192.168.155.114/bankpage/index.php?transaction_number=1337" width="0" height="0" border="0">
</body>

The attack procedes as follows, the victim accesses the website and logins in it.

Official Website

As we see in the next image, there are no transaction done.

After the login

By visiting the attacker website and triggering the attack we go back then to the official site and see a transaction that we haven’t done knowingly. Attack

When we refresh the official page we now see the transaction that has been made.

Attack Done

Now for the fun part. There are a lot of ways to do this easily. The first one is by creating and img tag and point the source for the address to attack. If we need a POST request we can create a form with it and when the page is loaded it triggers the event and submit the form. One thing that you should have in mind is that browsers nowadays are more “intelligent” than a few years back and when submitting and AJAX request it will be blocked. The reason for this is CORS (Cross Origin Resource Sharing). This HTTP header tries to block requests to other sites that don-t specially specifies the origin host. Some sites provide an external API where the website makes requests to and that API should implement CORS for modern browsers to work. This isn’t valid for some HTML tags since almost everyone uses, for images at least, external resources.

To detect this attack on you website you could simple check for external HTTP Referer on the logs for your API. If a website that you know is used for this attack or suspect its being used it will show as a different Referer.

To fully mitigate this issue we should employ CSRF_TOKEN verification in all forms that will trigger some action in the database. Solutions build in django, for instance, already required to add the token by default in every form, for Apache lovers we can use mod_csrf (mod_csrf) or in code (PHP_CSRF_GUARD). Ultimately the web developer should use this by default while developing the Web Application. Since the attacker can’t have the token easely he can’t submit the form.

References: OWASP CSRF

Happy New Year for everyone!