Disable Functions Bypass - dl Function
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
dl() lets PHP load a shared extension at runtime. If you can make it load an attacker-controlled module, you can register a new PHP function that internally calls execve, system, or any other native primitive and therefore bypass disable_functions.
This is a real primitive, but on modern targets it is far less common than older writeups suggest.
Why this bypass is uncommon today
The main blockers are:
dl()must exist and must not be disabledenable_dlmust still allow dynamic loading- The target SAPI must support
dl() - The payload must be a valid PHP extension compiled for the same target ABI
- The extension must be reachable from the configured
extension_dir
The official PHP manual is the most important reality check here: dl() is only available for CLI and embed SAPIs, and for the CGI SAPI when run from the command line. That means the technique is usually not available in normal PHP-FPM/mod_php web requests, so check the SAPI before spending time building a payload.
Also note that enable_dl is an INI_SYSTEM setting and, as of PHP 8.3.0, PHP documents it as deprecated, so you usually cannot flip it at runtime from attacker-controlled PHP code.
If dl() is not viable, go back to the broader list of module/version dependent bypasses.
Fast triage from a foothold
Before building anything, collect the exact parameters that the module must match:
<?php
phpinfo();
echo "PHP_VERSION=" . PHP_VERSION . PHP_EOL;
echo "PHP_SAPI=" . php_sapi_name() . PHP_EOL;
echo "ZTS=" . (PHP_ZTS ? "yes" : "no") . PHP_EOL;
echo "INT_BITS=" . (PHP_INT_SIZE * 8) . PHP_EOL;
echo "enable_dl=" . ini_get("enable_dl") . PHP_EOL;
echo "extension_dir=" . ini_get("extension_dir") . PHP_EOL;
echo "disabled=" . ini_get("disable_functions") . PHP_EOL;
?>
What you care about:
PHP_SAPI: if this isfpm-fcgiorapache2handler,dl()is usually a dead end for web exploitationextension_dir: the payload must be loaded from herePHP Version, architecture, debug/non-debug, and ZTS/non-ZTS: your module must match themdisable_functions: confirm whetherdlis absent because it is disabled or because the SAPI does not support it
Practical exploitation constraints
1. You normally need write access to extension_dir
This is the biggest bottleneck.
dl() takes the extension filename, and PHP loads it from extension_dir. In practice, this means that a normal arbitrary file upload to /var/www/html/uploads is not enough. You still need a path to place a .so/.dll where PHP will actually load extensions from.
Realistic situations where this becomes exploitable:
- CTFs or intentionally weak labs where
extension_diris writable - Shared-hosting or container mistakes that expose a writable extension path
- A separate arbitrary file write primitive that already reaches
extension_dir - Post-exploitation scenarios where you already escalated enough to drop files there
2. The module must match the target build
Matching only PHP_VERSION is not enough. The extension also needs to match:
- OS and CPU architecture
- libc/toolchain expectations
ZEND_MODULE_API_NO- debug vs non-debug build
- ZTS vs NTS
If those do not match, dl() will fail or crash the process.
3. open_basedir is not the main defense here
Once you can place the module in extension_dir and call dl(), the extension code executes inside the PHP process. At that point the relevant barrier was not open_basedir, but the ability to land a valid shared object in the extension loading path.
Building the malicious extension
The classic route is still valid:
- Recreate the victim build as closely as possible
- Use
phpize,./configure, andmaketo build a shared extension - Export a PHP function such as
bypass_exec($cmd)that wraps native command execution - Upload the compiled module into
extension_dir - Load it with
dl()and call the exported function
The attack is old, but still relevant because PHP 8.x changelogs continue to include dl()-specific crash fixes. The primitive still exists; the hard part is finding a deployment where it is reachable and where you can land a matching module.
Minimal workflow
On the attacker box
mkdir bypass && cd bypass
phpize
./configure
make
The resulting shared object will usually be under modules/.
If you are building on a different environment than the target, treat the produced file as a draft until you verify that the ABI matches the victim.
Loading and using the extension
If the target really supports dl() and the module is inside extension_dir, the runtime side is simple:
<?php
if (!extension_loaded('bypass')) {
dl('bypass.so'); // use the correct filename for the target platform
}
echo bypass_exec($_GET['cmd']);
?>
On Windows the filename will typically be a .dll, while on Unix-like targets it will usually be a .so.
Attacker notes
- Do not assume this works remotely just because
function_exists("dl")returns true in some documentation or old writeup; validate the live SAPI - A failed
dl()attempt may kill the PHP worker if the module is incompatible - From PHP 8 onward, disabled functions are removed from the function table, so userland enumeration may differ from older posts
- If you cannot write to
extension_dir, this technique is usually less practical than FPM/FastCGI,LD_PRELOAD, or module-specific bypasses already covered in this section
References
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.


