Disable Functions Bypass - dl Function
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos 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.
Triage rapido da una foothold
Prima di costruire qualsiasi cosa, raccogli i parametri esatti che il modulo deve soddisfare:
<?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: se questo èfpm-fcgioapache2handler,dl()è solitamente una strada morta per lo sfruttamento webextension_dir: il payload deve essere caricato da quiPHP Version, architettura, debug/non-debug, e ZTS/non-ZTS: il tuo module deve corrispondere a questidisable_functions: conferma sedlè assente perché è disabilitato o perché la SAPI non lo supporta
Practical exploitation constraints
1. You normally need write access to extension_dir
Questo è il collo di bottiglia principale.
dl() prende il nome del file dell’estensione, e PHP lo carica da extension_dir. In pratica, questo significa che un normale upload arbitrario di file in /var/www/html/uploads non è sufficiente. Hai ancora bisogno di un percorso per posizionare un .so/.dll dove PHP effettivamente caricherà le estensioni.
Situazioni realistiche in cui questo diventa sfruttabile:
- CTFs o lab intenzionalmente deboli dove
extension_dirè scrivibile - Errori di shared-hosting o container che espongono un percorso di estensioni scrivibile
- Un diverso primitive di scrittura arbitraria che raggiunge già
extension_dir - Scenari di post-exploitation dove hai già scalato abbastanza per posizionare file lì
2. The module must match the target build
Corrispondere solo a PHP_VERSION non basta. L’estensione deve anche corrispondere a:
- OS e architettura CPU
- aspettative di libc/toolchain
ZEND_MODULE_API_NO- build debug vs non-debug
- ZTS vs NTS
Se questi non corrispondono, dl() fallirà o causerà il crash del processo.
3. open_basedir is not the main defense here
Una volta che puoi posizionare il modulo in extension_dir e chiamare dl(), il codice dell’estensione viene eseguito all’interno del processo PHP. A quel punto la barriera rilevante non era open_basedir, ma la capacità di far atterrare un oggetto condiviso valido nel percorso di caricamento delle estensioni.
Building the malicious extension
La strada classica è ancora valida:
- Ricrea la build della vittima il più fedelmente possibile
- Usa
phpize,./configure, emakeper costruire un’estensione condivisa - Esporta una funzione PHP come
bypass_exec($cmd)che incapsula l’esecuzione nativa di comandi - Carica il modulo compilato in
extension_dir - Caricalo con
dl()e chiama la funzione esportata
L’attacco è vecchio, ma ancora rilevante perché i changelog di PHP 8.x continuano a includere fix per crash specifici di dl(). Il primitive esiste ancora; la parte difficile è trovare un deployment dove è raggiungibile e dove puoi far atterrare un modulo corrispondente.
Minimal workflow
On the attacker box
mkdir bypass && cd bypass
phpize
./configure
make
Il file shared object risultante si troverà solitamente in modules/.
Se stai compilando in un ambiente diverso da quello del target, considera il file prodotto come una bozza finché non verifichi che l’ABI corrisponda a quello della vittima.
Caricamento e utilizzo dell’estensione
Se il target supporta realmente dl() e il modulo si trova dentro extension_dir, il lato runtime è semplice:
<?php
if (!extension_loaded('bypass')) {
dl('bypass.so'); // use the correct filename for the target platform
}
echo bypass_exec($_GET['cmd']);
?>
Su Windows il nome del file sarà tipicamente .dll, mentre su target Unix-like sarà solitamente .so.
Attacker notes
- Non dare per scontato che questo funzioni da remoto solo perché
function_exists("dl")restituisce true in qualche documentazione o vecchio writeup; verifica la SAPI in esecuzione - Un tentativo fallito di
dl()può terminare il PHP worker se il modulo è incompatibile - Da PHP 8 in poi, disabled functions vengono rimosse dalla function table, quindi la userland enumeration potrebbe differire rispetto ai post più vecchi
- Se non puoi scrivere in
extension_dir, questa tecnica è solitamente meno pratica rispetto a FPM/FastCGI,LD_PRELOAD, o bypass specifici per moduli già trattati in questa sezione
Riferimenti
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.


