Saturday, September 10, 2011

Saving the World, One Vulnerability at a Time

?
x00 - Intro
Hey there, I was going to make a video going over this information but when I got around to it, it seemed like a boring subject to watch. Anyways I wanted to go over a few different techniques to help prevent some of the more common web vulnerabilities that are seen; such as: Cross-Site Scripting, Full Path Discplosure, Local/Remote File Inclusion, SQL Injection, Cross-Site Request Forgery. Each of the techniques I plan to cover are geared towards securing PHP source code, so if you code in Perl, ColdFusion, ASP, or some other web language this probably isn't going to help much.

0x01 - Cross-Site Scripting (XSS)
Hopefully you already know about XSS and how the attacks work. As of PHP version 4.x.x there was a feature called "magic_quotes_gpc"; though magic_quotes was actually made to prevent SQL vulnerabilities it also helps with XSS because this feature adds slashes (\) anytime a quotation (") is present in either the GET, POST, or COOKIE fields hence the "gpc." Although magic_quotes is a nice feature to have as of PHP version 5.3.0 it is now considered deprecated, and actually as of 6.0.0 its removed completely, so as a web developer we need a new method of adding slashes. We can do this with a function called...you guessed it addslashes() so what these features would do if an attacker used alert("test"); the output generated would be alert(\"test\"); though this is easy to get around with the javascript function fromCharCode(). A possibilities to help this vulnerability is regular expressions such as preg_match or preg_replace. Another simple form of XSS comes into play when the developers use the PHP_SELF variable; which is vulnerable by default. Developers could make a script such as

Code

   echo(\"You have viewing: \" . $_SERVER['PHP_SELF']);
?>



and the attacker would simply append "/" onto end of the url for example:

http://site/index.php/alert("test");

A solution to this problem is a function called basename(). basename() is set to what ever text is placed after the final forward slash (/) which in our attackers case would be "script>" so now even though our script is still not functioning properly it is no longer vulnerable to the attack. Another important function to keep in mind is the htmlspecialchars(), this function converts characters into their html entities for instance < becomes <

0x02 - Full Path Discolsure (FPD)
Full path discolsures happen when error reporting is enabled for web applications and there is actually a pretty easy fix for it. In the php.ini file there is an option for "display_errors" which as of PHP 5.2.4 has three possibilities: on, off, stderr. STDERR displays errors for applications other than web, so stderr and off are both safe. Another way to set this option is the PHP function ini_set() which could look like ini_set("display_errors",0).

0x03 - Remote File Inclusion (RFI)
In order to fix the RFI vulnerability you can simply turn off the allow_url_include option in the php.ini file much like we did with the FPD. Although once the allow_url_include is off LFI comes into play and needs to be avoided.

0x04 - Local File Inlusion (LFI)
Local file inclusion vulnerabilities can be performed with functions such as but not limited to:
include()
include_once()
require()
require_once()
virtual()
readfile()
fread()
fgets()
file_get_contents()
highlight_file()

There are a few simple techniques to patch a LFI vulnerabiltiy, setting open_basedir either at runtime with ini_set() or in the php.ini or httpd.conf files, you could also use a switch statment or if/elseif statement. open_basedir is not completely safe though; when using this method the script is restricted when using other files to the give path. Although, if the path is incorrectly set an attacker would still be able to possibly perform the LFI attack on our files. There are a few somewhat complex ways of bypassing SAFE_MODE/open_basedir; although by the time an attacker can attempt these it will already be too late for you because they are on the inside already. Example: lets say as the developer we issue open_basedir to only allow access to our website's root folder "/home/oursite/www/public_html/". This will restrict an attack so they will not be able to inject php code in our access/error log files or use /proc/self/environ and include a shell from our script, it will also restrict the attacker from viewing any other sites hosted on the server if any are present. This does not however protect the files within our website such as a config.php which could include our sql server information.

Vulnerable code could look like:
Code

   inlcude(\"./\" . $_GET['file']);
?>



it can easily be fixed

open_basedir:
Code

   // open_basedir restricts the php script from accessing file and directories outside of the given scope
   ini_set(\"open_basedir\", \"/home/oursite/www/public_html/\");
   include(\"./\" . $_GET['file']);
?>



Switch:
Code

   switch($_GET['file'])
   {
      case \"index.php\":
         include(\"./index.php\");
         break;
      .
      .
      .
   }
}




if/elseif:
Code

   $file = $_GET['file'];
   if($file == \"index.php\")
   {
      include(\"./index.php\");
   }
   elseif($file == \"users.php\")
   {
      include(\"./users.php\");
   }
   else
   {
      include(\"error.php\");
   }
?>



As you can see the open_basedir solution is easier but creating a whitelist using a switch or if statements as more effective. You could also use regular expressions to check for directory transversal, but this can typically be bypassed fairly easily which is why its not given as a solution.

0x05 - SQL Injection
As said during the XSS section, magic_quotes_gpc was created to help prevent sql attacks as well as the addslashes() function. Another function geared towards protecting the site's database is mysql_real_escape_string(). mysql_real_escape_string escapes special characters such as \x00,\n,\r,\,'," and \x1a; so the developer could create a query that is vulnerable:
Code

$id = $_GET['id'];
$query = \"SELECT * FROM products WHERE id = $id\";



this can be secured with the previous function
Code

$id = mysql_real_escape_string($_GET['id']);



If your user input variable is suppose to only be a number, like the previous example, you could also use is_numeric() which obviously checks whether the variable is a number.
Code

$id = $_GET['id'];
if(is_numeric($id))
{
   $query = \"SELECT * FROM products WHERE id = $id\";
}



0x06 - Cross-Site Request Forgery (CSRF)

Keep Rocking, Keep Hacking

No comments:

Post a Comment