tags:

views:

860

answers:

17

Ok so me and a friend are doing a mini presentation on PHP security (I'm not really into PHP though) and he asked me to find some examples of vulnerable PHP code (one that is prone to SQL injections and all other types of attacks). I was wondering are there any websites with both good and bad pieces of code showing how you should and shouldn't code?

Basically I will put them into our website and he will try to hack it, then we will show the "proper" website and he will try to hack it again.

+14  A: 

SQL injection is easy:

$var = $_POST['var'];
mysql_query("SELECT * FROM sometable WHERE id = $var");

This is easily solved by:

$var = mysql_real_escape_string($_POST['var']);

The other common one is XSS (cross site scripting):

$var = $_POST['var'];
echo "<div>$var</div>\n";

allows you to inject Javascript that is run from your site. There are several ways of dealing with this, for example:

$var = strip_tags($_POST['var']);

and

$var = filter_var($_POST['var'], FILTER_SANITIZE_STRING);
cletus
Yep, essentially you can never trust user input, treat it all as malicious input and escape it with `addslashes()`, `strip_tags()` or `htmlspecialchars()` .
Rob
`strip_tags` is not sufficient to stop HTML injection (think attribute value injection). Munging the request array with FILTER_SANITIZE_STRING is a terrible hack that should never be used. Instead, avoid HTML injection by calling `htmlspecialchars` on every string you place into HTML content.
bobince
you could parse it with a regex...
nickf
Now that's not fair nickf, you know that sets off the uncontrollable twitching in my left eye.
bobince
Would like to point out the `htmlspecialchars(..., ENT_QUOTES)` option for use within HTML attributes.
gahooa
Calling htmlspecialchars is not enough if, for example, you are accepting a URL that you are going to put into an image src attribute. src="javascript:attack();"
David Dorward
all this proves is that there is no one easy fix. You actually have to understand the vulnerabilities and _think_ when you implement so that you apply the correct fix to the specific problem you have.
rmeador
The provided code is _still_ vulnerable to SQLi.
rFactor
Kaitsuli is right. What if `$_POST['var']` is set to `UNION SELECT name, password...(you get the idea) FROM users WHERE id=3`?
Franz
I disagree with the solution of SQL Injections as the easy fix only because I'd much rather see people move to PDO and use its prepared statements. It takes a little more adjusting to switch, but will hopefully encourage people to learn good habits early, instead of retraining people after they learn about injection the hard way.
acrosman
+3  A: 

Another example of a sql-injection-vulnerable login script. This is unfortunately very common among new programmers.

$username = $_POST["username"];
$password = $_POST["password"];
$query = "SELECT username, password 
          FROM users 
          WHERE (username = '{$username}') 
            AND (password = '{$password}')";
Jonathan Sampson
Not to mention storing passwords in plaintext.
Vilx-
+11  A: 

A really common beginner's mistake is forget to terminate script execution after a redirect.

<?php
if ($_SESSION['user_logged_in'] !== true) {
    header('Location: /login.php');
}

omg_important_private_functionality_here();

The solution:

if ($_SESSION['user_logged_in'] !== true) {
    header('Location: /login.php');
    exit();
}

This can be missed when testing in a normal browser, because browsers usually follow the Location header without rendering any of the output of the script.

Ben James
Maybe its too early in the morning for me still, but what is the vulnerability here?
Jakub
The header could be ignored, and the php script is still executing. The private function still executes, even if the user is not logged in.
Ikke
The header() redirect may not come immediately into effect, or can be deliberately ignored, revealing the private data below.
Pekka
+1  A: 

Check out the Open Web Application Security Project. They have explanations and examples of lots of different kinds of attacks. http://www.owasp.org/index.php/Category:Attack

txyoji
+4  A: 

I've seen code like this written in the past:

foreach ($_REQUEST as $var => $val) {
    $$var = $val;
}

It's a way to simulate the maligned register_globals option. It means you can access your variables like this:

$myPostedVar

rather than the terribly more complicated:

$_POST['myPostedVar']

The security risk pops up in situations like this:

$hasAdminAccess = get_user_access();

foreach ($_REQUEST as $var => $val) {
    $$var = $val;
}

if ($hasAdminAccess) { ... }

Since all you'd have to do is add ?hasAdminAccess=1 to the url, and you're in.

nickf
The feature this is simulating is `register_globals`
Ben James
ah thanks! it's one of those things I'd blocked from my mind. The horror... the horror...
nickf
+6  A: 

Bobby Tables

alt text

Bobby Tables is a page devoted to detailing the ways that a script can be vulnerable via SQL injection. This is not unique to PHP, however, SQL injection is the cause of many web page vulnerabilities.

It might be someting you want to include in your presentation.

Jon Winstanley
A: 

The WRONG way to do templates.

<?php

  include("header.php");
  include($_GET["source"]); //http://www.mysite.com/page.php?source=index.php
  include("footer.php");

?>
Jonathan Sampson
You should also show what's the rigt way to do templates.
Ikke
The question was for vulnerable examples, not proper examples.
Jonathan Sampson
A: 

XSS vulnerabilities are easy to show. Just create a page that puts the value of the GET variable "q" somewhere on the page and then hit the following URL:

http://mysite.com/vulnerable_page.php?q%3D%3Cscript%20type%3D%22javascript%22%3Ealert(document.cookie)%3B%3C%2Fscript%3E

This will cause the user's cookies to be displayed in an alert box.

ctford
A: 

Allowing upload and not checking extension. Observe:

Site A allows image uploading and displays them.

Cracker guy uploads a file and tricks you to believe its an image file (via HTTP mimetypes). This file has PHP extension and contains malicious code. Then he tries to see his image file and because every PHP extesioned file is executed by PHP, the code is run. He can do anything that apache user can do.

Cem Kalyoncu
+7  A: 

Oh boy, you won't be short of examples. Just Google PHP tutorial and every single one of them has enough holes to fill the Albert Hall.

Result 1, w3schools. What's their first example to include user input?

Welcome <?php echo $_POST["fname"]; ?>!<br />

Bzzt. HTML injection, repeated throughout every piece of example code. What's their first database query?

$sql="INSERT INTO Persons (FirstName, LastName, Age) VALUES ('$_POST[firstname]','$_POST[lastname]','$_POST[age]')";

Bzzt. SQL injection, you lose. Next.

Result 2, official PHP tutorial. What's the first example of outputting a variable?

echo $_SERVER['HTTP_USER_AGENT'];

Bzzt. HTML injection. Not an easily-exploitable one, but still, bad practice of the sort that is repeated throughout php.net's learning materials.

Result 3, tizag.com. What's the first example of echoing user input?

echo "You ordered ". $quantity . " " . $item . ".<br />";

Bzzt.

Result 4, freewebmasterhelp.com. Too basic to include much, but still manages:

print "Hello $name"; // Welcome to the user

Bzzt.

Result 5, learnphp-tutorial.com.

<title><?= $greeting ?> World!</title>

Bz...

I could go on.

Is it any wonder the general quality of PHP code in the wild is so disastrous, when this woeful rubbish is what coders are learning?

bobince
"holes to fill the Albert Hall"? Good one. +1
Franz
And you're right. It's quite funny to see example code showing you how to test your code for that and that introducing/missing/leaving out other vulnerability examples...
Franz
My favourite is the Apress book “Pro PHP Security”. The author does a brief tour of common vulnerabilities and proposes a solution to each (often a quite inappropriate one like mapping POST through an SQL escape). And then in the rest of the examples for solving other vulnerabilities he gets it wrong again, giving code that suffers from the vulnerabilities he just warned us about last chapter. The XSS chapter even has XSS vulnerabilities in its examples of how to avoid slightly-different XSS vulnerabilities. And quite terrifying sections on using `eval` and `system`. “Pro” security indeed.
bobince
+1  A: 

CSRF for the win.

<?php
$newEmail = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$pdoStatement = $pdoDb->prepare('UPDATE user SET email=:email WHERE ID=:id');
$pdoStatement->execute(array(':email'=>$newEmail, ':id'=>$_SESSION['userId']));

You feel safe with this kind of code. All is good your users can change their emails without injecting SQL because of your code. But, imagine you have this on your site http://siteA/, one of your users is connected. With the same browser, he goes on http://siteB/ where some AJAX does the equivalent of this code :

<form method="post" action="http://site/updateMyAccount.php"&gt;
  <p>
    <input name="email" value="badguy@siteB"/>
    <input type="submit"/>
  </p>
</form>

Your user just got his email changed without him knowing it. If you don't think this kind of attack is dangerous, ask google about it

To help against this kind of attacks, you can either :

  • Check your user REFERER (far from perfect)
  • Implement some tokens you had to your forms and check their presence when getting your data back.

Another one is session hijacking. One of the methods to do it is piggybacking. If your server accepts non cookie sessions, you can have URLs like http://siteA/?PHPSESSID=blabla which means your session ID is blabla.

An attacker can start a session and note his session ID, then give the link http://siteA/?PHPSESSID=attackerSessionId to other users of your website. When these users follow this link, they share the same session as your attacker : a not logged session. So they login. If the website does not do anything, your attacker and your user are still sharing the same session with the same rights. Bad thing if the user is an admin.

To mitigate this, you have to use session_regenerate_id when your users credentials change (log in and out, goes in administration section etc.).

Arkh
+1  A: 

Today's DailyWTF:

if(strstr($username, '**')) {

    $admin = 1;
    $username = str_replace('**', '', $username);
    $_SESSION['admin'] = 1;

} else {

    $admin = 0;

}
R. Bemrose
just read it on thedailywtf. that code hurts …
knittl
...and the one who wroted call himself a programmer?!
DaNieL
+2  A: 

HTTP Response Splitting attack

If web application is storing the input from an HTTP request in cookie let's say

<?php setcookie("author",$_GET["authorName"]); ?>

It is very prone to HTTP response splitting attack if input is not validated properly for "\r\n" characters.

If an attacker submits a malicious string,such as "AuthorName\r\nHTTP/1.1 200 OK\r\n..",then the HTTP response would be split into two responses of the following form:

HTTP/1.1 200 OK
...
Set-cookie: author=AuthorName

HTTP/1.1 200 OK ...

Clearly,the second response is completely controlled by the attacker and can be constructed with any header and body content instead

Naga Kiran
Hmm, I think that's PHP version related. PHP 5 seems to encode all special characters into percent encoding.
rFactor
HTTP response splitting has been addressed for quite some time. http://php.net/releases/5_1_2.php
The Pixel Developer
+2  A: 

Email header injection attacks are a much bigger pain in the neck then you might suspect (unless you've had to deal with them).

This is very bad:

$to = '[email protected]';
$subject = $_POST["subject"];
$message = $_POST["message"];
$headers = "From: ".$_POST["from"];
mail($to,$subject,$message,$headers);

(code copied from the second reference above.)

acrosman
A: 

Ok guys I knew would be of great help, now the project will be cake. Thanks a bunch.

Zenzen
A: 

Basic (often security sensitive) operations not working as expected, instead requiring the programmer to use a second "real" version to get non-broken functionality.

The most serious one of these would be where an actual operator is affected: The "==" operator does not work as one would expect, instead the "===" operator is needed to get true equality comparison.

One of the big 3 PHP forum packages was affected by a vulnerability in it's "stay logged in" code. The cookie would contain the user's ID and their password hash. The PHP script would read and cleanse the ID, use it to query the user's correct hash in the database, and then compare it with the one in the cookie to see if they should be automatically logged in.

However the comparison was with ==, so by modifying the cookie, an attacker use a hash "value" of boolean:true, making the hash comparison statement useless. The attacker could thus substitute any user ID to log in without a password.

David
A: 

Allowing people to upload files, whether that API is supposed to be used by users or not. For example, if a program uploads some files to a server, and that program will never upload a bad file, that's fine.

But a hacker could trace what is being sent, and where to. He could find out that it is allowing files to be uploaded.

From there, he could easily upload a php file. Once that's done, it's game over. He now has access to all your data and can destroy or change anything he wants.

Another common mistake is allowing flooding. You should put some sane limits on your data. Don't allow users to input nonsensical data. Why is a user's name 2MB in length? Things like that make it so easy for someone flood your database or filesystem and crash the system due to out of space errors.

boytheo