Remote Code Execution in PHP Explained - Part 1
This is a two part article about code execution in PHP. It’s a very detailed article and contains references from other sources as well. I will discuss about some of the mistakes done by PHP developers which result in Remote Code Execution Vulnerability. It’s no secret that PHP is an easy to code language; however a lot of new PHP developers lack the knowledge of basic security principles which results in to new poorly written web-application often introducing critical vulnerabilities.
PHP Vulnerable Functions
Let’s take a look at the very common class of functions which when used insecurely result in a remote code execution. Any untrusted input passed through one of these functions without sanitization would result in an arbitrary code being executed. eval() , system(), exec(), shell_exec()The first fair case I would say is using the eval function. Web-developers usually want to evaluate desired code with some dynamic changes. Let’s take a look at the following example:
<?phpIn this case variable will be treated as PHP code, so contents of $name will be evaluated
eval("echo $name;");
?>
<?php
eval('echo $name;');
?>
In second one value of $name will be simply echoed. So, if your intention was second case, there is no reason to use double quotes for any calls.
As you can see, sanitizing eval can be a big waste of time and there is no function designed in php to properly escape eval. Mostly this kind of issues occur with scripts like:
<?php
$name = $_GET[‘name’]
system(“echo $name”);
?>
So seeing from the above code, whatever code we gave it, the developer thinks it will just print it out. It’s a right conclusion but with a wrong angle of view, an attacker can give values like
“Paulos;ls –la” or “Paulos && dir” for windows systems
And execute the ls –la command, since ‘;’ means to execute that line and to execute a new one, i.e ls -la
So the output would be “Paulos” with the list of the current directory.
Similarly other functions such as shell_exec, exec would result in the same vulnerability.
Regex
One popular case leading to code evaluation is regex. Regexps are used widely because it is often easier to write regex than to individually do it. A lot of web application filters and firewalls use rules that are based upon regex.
PHP has support of the Perl Compatible Regex; there is availability of ‘e preg_replace_eval’ modified in regex for functions. Like preg_replace() for example, When a is match found, it then will be executed.
<?php$name='<p>phpinfo()</p>';preg_replace("/<p>(.*?)<\/p>/e",'addslashes(\\1)',$name);?>
It’s obvious the intention of the developer was to sanitize the input with addslashes(). Even if there is no ‘e’ modifier, sometimes it is possible to evaluate code. It can be achieved by writing some regular expression with the help of our dear friend, the null byte.
<?php $replace=$_GET['re'];$name='<p>phpinfo()</p>';preg_replace("/<p>(.*?)$replace<\/p>/",'\\1',$name);?>
This example is an easy one and native but, the aim is to show how null-byte attack could work. Now consider that vulnerable script accepts request like this:
http://localhost/index.php?re=<\/p>/e
Function Tasks
The function tasks are one of the other ways how code execution could occur, let’s take a look at the following example:
<?php $name=$_GET[‘name’];$argument=$_GET['argument'];$name($argument);?>
In case if register_globals flag is set to enabled, the previous code is equivalent to:
<?php $name($argument);?>
From here the exploitation is piece of cake:
http://localhost/index.php?name=eval&argument=phpinfo
The $name becomes name of function and $argument is the argument of name. It should be clear what it could do.
In another case with create_function(), it is possible to create veiled function. For example:
<?php $name=$_GET['name'];$create =create_function('$name',"echo $name;");$name('');?>
Then following request would give out result phpinfo()
http://localhost/index.php?name=phpinfo()
In eval() it was equivalent to something like:
<?php eval("function this_is_so_safe() { echo phpinfo(); }");this_is_so_safe();?>
Inclusion
In PHP there are some functions that are used to dynamically include the PHP code inside the page, if an untrusted input is used to dynamically include files inside of a page, it would result into a file inclusion vulnerability.
Here is the list of some functions that need to be handled with care - include(), iclude_once(), require(), require_once() etc
Best way to be preserved from this kind of attacks is to avoid using dynamic file paths. If this is not possible, then the usage of this should be limited and checked by a list of allowed files to be included. Also try to use absolute path rather than relative. But if the PHP directive include path is able to be modified, you can never know where the script with defined partial path comes from. Good approach is to use file inclusion as follows:
<?php define('MY_FILE_PATH','/var/www/htdocs/');require_once(APP_PATH .'lib.php');?>
Let’s now take a look at another example, consider the following page:
http://localhost/index.php?file=page1
page1 is the file that is dynamically included into the webpage, by looking at the above url, we can assume that the backend would be using the following code:
<?php $page_to_include=$_GET['file'];require_once($page_to_include.'.html');?>
And now imagine that attacker changes value of variable “file” to following:
http://localhost/index.php?file=data:text/plain,<?php phpinfo();?>
LFI can easily be converted to remote code execution (RCE) in one way more. This new data protocol has appeared in PHP 5.2.0 and in older versions will not work. Also PHP will argue and would not allow to use it if allow_url_include=off which results in a full path disclosure.
There are other possibilities how code can be injected and later evaluated; via apache log files, using “/proc” and others. Without a doubt, inappropriate usage of functions like file_get_contents(), readfile(), input wrappers like php://input and others represent a threat as well. However, the exploitation part is a subject of another article.
Variables
Register_globals is a php setting that allows variables to be registered as global, the register_globals has lead to security issues such as file inclusion discussed above , as a result of which register_globals is by default switched off in 4.2 and will remove it in php version 6.0. Let's take a look at the following code, assuming that register_globals flag is turned on.
<?php
foreach($_GET as $key=>$name){
$$key=$name;
}
// ...
if(logged_in()||$authenticated){
// ... logged area
}
?>
The above code takes each user input, then if the variable authenticated is true, or the function is true, it will execute admin codes, so when register globals is on, we can modify every variable as a global using post and get requests.
Thus when we make the variable globally true using a get request, the if statement becomes true and executes its code:
http:// localhost/index.php?authenticated=true.
Even if $authenticated is an integer variable. It means we can pass something like http:// localhost/index.php?authenticated=1 since 1 is true and 0 is not so much. so either we gave it 1 or true, it still gets code executed..
Hope you have enjoyed the first article, we would continue the series and present some other scenarios that lead to arbitrary code execution inside the next part.
References
- http://www.php-security.org/2010/05/20/mops-submission-07-our-dynamic-php/index.html
Thus when we make the variable globally true using a get request, the if statement becomes true and executes its code:
http:// localhost/index.php?authenticated=true.
Even if $authenticated is an integer variable. It means we can pass something like http:// localhost/index.php?authenticated=1 since 1 is true and 0 is not so much. so either we gave it 1 or true, it still gets code executed..
Hope you have enjoyed the first article, we would continue the series and present some other scenarios that lead to arbitrary code execution inside the next part.
About The Author
This following article is a guets post by Paulos Yibelo. Yibelo is the newest member of RHA family. He is a full time PHP coder and most of his research is involved with application security. In his free time he loves writing articles related to application security at http://paulosyibelo.blogspot.com/About The Editor
This article was edited by "Fatima Hanif", a student at NED university. She is responsible for editorial work at RHA infosec.References
- http://www.php-security.org/2010/05/20/mops-submission-07-our-dynamic-php/index.html