Disable Functions Bypass - dl Function

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

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.

Ovo je stvarna tehnika, ali na modernim ciljevima znatno je ređa nego što stariji writeup-i sugerišu.

Why this bypass is uncommon today

Glavni razlozi su:

  • dl() mora postojati i ne sme biti onemogućen
  • enable_dl mora i dalje dozvoljavati dinamičko učitavanje
  • Ciljni SAPI mora podržavati dl()
  • Payload mora biti validan PHP extension kompajliran za isti target ABI
  • Extension mora biti dostupan iz konfigurisane extension_dir

Službeni PHP manual je najvažnija provera realnosti ovde: dl() je dostupan samo za CLI i embed SAPIs, i za CGI SAPI kada se pokreće iz komandne linije. To znači da tehnika obično nije dostupna u normalnim PHP-FPM/mod_php web zahtevima, pa proverite SAPI pre nego što trošite vreme na izgradnju payload-a.

Takođe imajte na umu da je enable_dl INI_SYSTEM podešavanje i, od PHP 8.3.0, PHP ga dokumentuje kao deprecated, tako da obično ne možete promeniti to u runtime-u iz PHP koda pod kontrolom napadača.

Ako dl() nije izvodljiv, vratite se na širi spisak module/version dependent bypasses.

Brza trijaža sa footholda

Pre nego što bilo šta izgradite, prikupite tačne parametre koje modul mora da zadovolji:

<?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 is fpm-fcgi or apache2handler, dl() is usually a dead end for web exploitation
  • extension_dir: payload must be loaded from here
  • PHP Version, architecture, debug/non-debug, and ZTS/non-ZTS: your module must match them
  • disable_functions: confirm whether dl is 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

Ovo je najveća prepreka.

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_dir is 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

Klasičan put i dalje važi:

  1. Rekreirajte build ciljne instance što tačnije
  2. Koristite phpize, ./configure, i make da izgradite shared extension
  3. Exportujte PHP funkciju kao bypass_exec($cmd) koja obavija native izvršavanje komandi
  4. Otpremite kompajlirani modul u extension_dir
  5. Učitajte ga pomoću dl() i pozovite exportovanu funkciju

Napad je star, ali i dalje relevantan jer changelogi PHP 8.x i dalje uključuju ispravke padova specifičnih za dl(). Primitiv i dalje postoji; težak deo je pronaći deployment gde je dostupan i gde možete postaviti odgovarajući modul.

Minimal workflow

On the attacker box

mkdir bypass && cd bypass
phpize
./configure
make

Rezultujući shared object obično će se nalaziti u modules/.

Ako gradite u drugačijem okruženju nego cilj, tretirajte proizvedeni fajl kao nacrt dok ne potvrdite da ABI odgovara ciljnoj mašini.

Učitavanje i korišćenje ekstenzije

Ako cilj zaista podržava dl() i modul se nalazi unutar extension_dir, runtime strana je jednostavna:

<?php
if (!extension_loaded('bypass')) {
dl('bypass.so'); // use the correct filename for the target platform
}
echo bypass_exec($_GET['cmd']);
?>

Na Windows sistemima ime fajla obično će biti .dll, dok će na Unix-like ciljevima obično biti .so.

Beleške napadača

  • Ne pretpostavljajte da ovo radi na daljinu samo zato što function_exists("dl") vraća true u nekoj dokumentaciji ili starom writeup-u; validirajte aktivni SAPI
  • Neuspešan pokušaj dl() može ubiti PHP worker ako modul nije kompatibilan
  • Od PHP 8 nadalje, onemogućene funkcije se uklanjaju iz tabele funkcija, pa se userland enumeracija može razlikovati od starijih postova
  • Ako ne možete pisati u extension_dir, ova tehnika je obično manje praktična od FPM/FastCGI, LD_PRELOAD, ili module-specific bypasses koji su već obrađeni u ovom odeljku

References

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks