Эксплуатируемые функции PHP

Я пытаюсь создать список функций, которые можно использовать для выполнения произвольного кода. Цель не состоит в том, чтобы перечислить функции, которые должны быть помещены в черный список или иначе запрещены. Скорее, я хотел бы иметь grep -able список ключевых слов с красным флагом, удобный при поиске взломанного сервера для бэкдора.

Идея состоит в том, что если вы хотите создать многоцелевой вредоносный PHP-скрипт, такой как скрипт "веб-оболочки", такой как c99 или r57, вам придется использовать одну или несколько из относительно небольшого набора функций. где-то в файле, чтобы позволить пользователю выполнить произвольный код. Поиск этих функций поможет вам быстрее сузить стог из десятков тысяч PHP-файлов до относительно небольшого набора сценариев, которые требуют более тщательного изучения.

Ясно, например, что любое из следующего будет считаться вредоносным (или ужасным кодированием):

<? eval($_GET['cmd']); ?>

<? system($_GET['cmd']); ?>

<? preg_replace('/.*/e',$_POST['code']); ?>

и так далее.

Просматривая взломанный веб-сайт на днях, я не заметил части вредоносного кода, потому что не осознавал preg_replace может стать опасным при использовании /e флаг (который, серьезно? Почему это даже там?). Есть ли другие, которые я пропустил?

Вот мой список пока:

Shell Execute

  • system
  • exec
  • popen
  • backtick operator
  • pcntl_exec

PHP Выполнить

  • eval
  • preg_replace/e модификатор)
  • create_function
  • include [ _once ] / require [ _once ] (см. ответ Марио для деталей об эксплойтах)

Также может быть полезно иметь список функций, которые могут изменять файлы, но я думаю, что в 99% случаев код эксплойта будет содержать хотя бы одну из указанных выше функций. Но если у вас есть список всех функций, способных редактировать или выводить файлы, опубликуйте его, и я включу его здесь. (И я не считаю mysql_execute, так как это часть другого класса эксплойтов.)

23 ответа

Решение

Для построения этого списка я использовал 2 источника. Этюд в Скарлет и РАТС. Я также добавил некоторые свои собственные в микс, и люди в этой теме помогли.

Изменить: После публикации этого списка я связался с основателем RIPS, и на данный момент этот инструмент ищет PHP-код для использования каждой функции в этом списке.

Большинство из этих вызовов функций классифицируются как Sinks. Когда испорченная переменная (например, $_REQUEST) передается в функцию приемника, вы получаете уязвимость. Такие программы, как RATS и RIPS, используют функцию, подобную grep, для идентификации всех приемников в приложении. Это означает, что программисты должны проявлять особую осторожность при использовании этих функций, но если они будут заблокированы, вы не сможете сделать многое.

" С большой силой приходит большая ответственность ".

- Стэн Ли

Выполнение команды

exec           - Returns last line of commands output
passthru       - Passes commands output directly to the browser
system         - Passes commands output directly to the browser and returns last line
shell_exec     - Returns commands output
`` (backticks) - Same as shell_exec()
popen          - Opens read or write pipe to process of a command
proc_open      - Similar to popen() but greater degree of control
pcntl_exec     - Executes a program

Выполнение кода PHP

Помимо eval Есть и другие способы выполнения кода PHP: include / require может использоваться для удаленного выполнения кода в виде уязвимостей Local File Include и Remote File Include.

eval()
assert()  - identical to eval()
preg_replace('/.*/e',...) - /e does an eval() on the match
create_function()
include()
include_once()
require()
require_once()
$_GET['func_name']($_GET['argument']);
$func = new ReflectionFunction($_GET['func_name']); $func->invoke(); or $func->invokeArgs(array());

Список функций, которые принимают обратные вызовы

Эти функции принимают строковый параметр, который можно использовать для вызова функции по выбору злоумышленника. В зависимости от функции атакующий может иметь или не иметь возможность передавать параметр. В этом случае Information Disclosure функционировать как phpinfo() может быть использован.

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() это определенно уязвимость.

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

Другой

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, каждая из этих функций файловой системы может быть использована для направления и атаки на другой хост через ваш сервер.

// open filesystem handler
fopen
tmpfile
bzopen
gzopen
SplFileObject->__construct
// write to filesystem (partially in combination with reading)
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
// read from filesystem
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($tmp), а также require(HTTP_REFERER) и *_once. Если скрипт эксплойта может записать во временный файл, он может просто включить это позже. В основном двухступенчатый eval.

И даже можно скрыть удаленный код с помощью обходных путей, таких как:

 include("data:text/plain;base64,$_GET[code]");

Кроме того, если ваш веб-сервер уже был взломан, вы не всегда увидите незакодированное зло. Часто оболочка эксплойта кодируется в gzip. Думать о include("zlib:script2.png.gz"); Эвала здесь нет, все тот же эффект.

Это не ответ сам по себе, но вот кое-что интересное:

$y = str_replace('z', 'e', 'zxzc');
$y("malicious code");

В том же духе, call_user_func_array() может использоваться для выполнения запутанных функций.

Я удивлен, что никто не упомянул echo а также print как точки безопасности эксплуатации.

Межсайтовый скриптинг (XSS) - это серьезный эксплойт безопасности, потому что он даже более распространен, чем эксплойты на стороне сервера.

Я бы особенно хотел добавить unserialize() в этот список. У него долгая история различных уязвимостей, включая выполнение произвольного кода, отказ в обслуживании и утечка информации в памяти. Он никогда не должен вызываться на предоставленных пользователем данных. Многие из этих выпусков были исправлены в выпусках за последние годы росы, но в настоящее время в них сохраняется пара неприятных выпусков.

Для получения дополнительной информации о хитроумных функциях / использовании php посмотрите проект Hardened PHP Project и его рекомендации. Также последний Месяц безопасности PHP и Месяц ошибок PHP 2007 года.

Также обратите внимание, что при проектировании несериализация объекта вызовет выполнение функций конструктора и деструктора; Еще одна причина, чтобы не вызывать его на предоставленных пользователем данных.

Мой VPS настроен на отключение следующих функций:

root@vps [~]# grep disable_functions /usr/local/lib/php.ini
disable_functions = dl, exec, shell_exec, system, passthru, popen, pclose, proc_open, proc_nice, proc_terminate, proc_get_status, proc_close, pfsockopen, leak, apache_child_terminate, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid

В PHP достаточно потенциально разрушаемых функций, поэтому ваш список может быть слишком большим для поиска. Например, в PHP есть chmod и chown, которые можно использовать для простой деактивации сайта.

РЕДАКТИРОВАТЬ: Возможно, вы захотите создать сценарий bash, который ищет файл для массива функций, сгруппированных по опасности (плохие функции, худшие функции, функции, которые никогда не должны использоваться), а затем рассчитывает относительную опасность что файл накладывается в процентах. Затем выведите это в дерево каталога с процентами, помеченными рядом с каждым файлом, если они превышают порог, скажем, 30% опасности.

Также имейте в виду класс "уязвимостей прерывания", которые позволяют произвольным ячейкам памяти считываться и записываться!

Они влияют на такие функции, как trim(), rtrim(), ltrim(), explode(), strchr(), strstr(), substr(), chunk_split(), strtok(), addcslashes(), str_repeat() и другие., Это во многом, но не исключительно, из-за функции передачи по ссылке во время разговора языка, который устарел в течение 10 лет, но не отключен.

Для получения дополнительной информации см. Доклад Стефана Эссера об уязвимостях прерывания и других низкоуровневых проблемах PHP на бумаге для слайдов BlackHat USA 2009

Эта статья / презентация также показывает, как dl () может использоваться для выполнения произвольного системного кода.

Специфичные для платформы, но и теоретические векторы исполнения:

  • dotnet_load ()
  • новый COM("WScript.Shell")
  • новая Java ("java.lang.Runtime")
  • event_new () - очень рано

И есть еще много способов маскировки:

  • proc_open - псевдоним для popen
  • call_user_func_array ("exE".chr (99), массив ("/usr/bin/mage", "--all"));
  • file_put_contents ("/ cgi-bin / nextinvocation.cgi") && chmod (...)
  • PharData:: setDefaultStub - еще немного работы для изучения кода в файлах.phar
  • runkit_function_rename ("exec", "innocent_name") или APD rename_function

Отдельно от eval В языковой конструкции есть еще одна функция, которая позволяет выполнять произвольный код: assert

assert('ex' . 'ec("kill --bill")');

Один источник интересных подвигов не был упомянут. PHP позволяет иметь строки 0x00 байтов в них. Базовые (libc) функции обрабатывают это как конец строки.

Это учитывает ситуации, когда (плохо реализованная) проверка работоспособности в PHP может быть одурачена, например, в такой ситуации:

/// note: proof of principle code, don't use
$include = $_GET['file'];
if ( preg_match("/\\.php$/",$include) ) include($include);

Это может включать любой файл - не только те, которые заканчиваются на .php - по телефону script.php?file=somefile%00.php

Поэтому любая функция, которая не подчиняется длине строки PHP, может привести к некоторой уязвимости.

Как насчет опасных синтаксических элементов?

" Переменная переменная" ($$var) найдет переменную в текущей области с именем $var. Если используется неправильно, удаленный пользователь может изменить или прочитать любую переменную в текущей области. В основном слабее eval,

Пример: вы пишете код $$uservar = 1;затем удаленный пользователь устанавливает $uservar в "админ", вызывая $admin быть установленным на 1 в текущем объеме.

Я думаю, вы не сможете действительно найти все возможные эксплойты, анализируя ваши исходные файлы.

  • также, если здесь есть действительно хорошие списки, вы можете пропустить функцию, которая может быть использована

  • там еще может быть "скрытый" злой код, как этот

$ myEvilRegex = base64_decode ('Ly4qL2U =');

preg_replace ($ myEvilRegex, $ _POST ['code']);

  • Теперь вы можете сказать, я просто расширяю свой сценарий, чтобы соответствовать этому

  • но тогда у вас будет этот "возможно злой код", который, кроме того, находится вне контекста

  • так что, чтобы быть (псевдо) безопасным, вы должны действительно написать хороший код и прочитать весь существующий код самостоятельно

Я знаю move_uploaded_file было упомянуто, но загрузка файлов в целом очень опасна. Просто наличие $_FILES должен вызвать некоторое беспокойство.

Вполне возможно встроить код PHP в любой тип файла. Изображения могут быть особенно уязвимы с текстовыми комментариями. Проблема особенно проблематична, если код принимает расширение, найденное в $_FILES данные как есть.

Например, пользователь может загрузить действительный файл PNG со встроенным кодом PHP как "foo.php". Если скрипт особенно наивный, он может скопировать файл как "/uploads/foo.php". Если сервер сконфигурирован так, чтобы разрешать выполнение скриптов в пользовательских каталогах загрузки (часто это бывает, и ужасный недосмотр), тогда вы можете мгновенно запустить любой произвольный код PHP. (Даже если изображение сохранено в формате.png, возможно, можно будет выполнить код с помощью других недостатков безопасности.)

(Неисчерпывающий) список вещей, которые нужно проверить при загрузке:

  • Обязательно проанализируйте содержимое, чтобы убедиться, что выгрузка соответствует типу
  • Сохраните файл с известным безопасным расширением, которое никогда не будет выполнено
  • Убедитесь, что PHP (и любое другое выполнение кода) отключено в пользовательских каталогах загрузки

Давайте добавим pcntl_signal а также pcntl_alarm к списку.

С помощью этих функций вы можете обойти любое ограничение set_time_limit, созданное в php.ini или в скрипте.

Этот скрипт, например, будет работать в течение 10 секунд, несмотря на set_time_limit(1);

(Благодарность идет Себастьяну Бергманну, твит и суть:

<?php
declare(ticks = 1);

set_time_limit(1);

function foo() {
    for (;;) {}
}

class Invoker_TimeoutException extends RuntimeException {}

class Invoker
{
    public function invoke($callable, $timeout)
    {
        pcntl_signal(SIGALRM, function() { throw new Invoker_TimeoutException; }, TRUE);
        pcntl_alarm($timeout);
        call_user_func($callable);
    }
}

try {
    $invoker = new Invoker;
    $invoker->invoke('foo', 1);
} catch (Exception $e) {
    sleep(10);
    echo "Still running despite of the timelimit";
}

Существует множество эксплойтов PHP, которые можно отключить с помощью настроек в файле PHP.ini. Очевидным примером является register_globals, но в зависимости от настроек также может быть возможно включать или открывать файлы с удаленных машин через HTTP, что можно использовать, если программа использует переменные имена файлов для любой из своих функций include() или обработки файлов.

PHP также позволяет вызывать функцию переменной, добавляя () в конец имени переменной - например, $myvariable(); вызовет имя функции, указанное в переменной. Это пригодно для использования; например, если злоумышленник может заставить переменную содержать слово "eval" и может управлять параметром, он может делать все, что захочет, даже если программа фактически не содержит функцию eval().

Эти функции также могут иметь некоторые неприятные последствия.

  • str_repeat()
  • unserialize()
  • register_tick_function()
  • register_shutdown_function()

Первые два могут исчерпать всю доступную память, а последние поддерживают истощение памяти...

Об этом недавно говорилось на security.stackexchange.com.

функции, которые можно использовать для выполнения произвольного кода

Что ж, это немного уменьшает область видимости - но так как "print" может использоваться для внедрения javascript (и, следовательно, кражи сессий и т. Д.), Он все еще несколько произвольный.

не перечислять функции, которые должны быть в черном списке или иным образом запрещены. Скорее, я хотел бы иметь grep-способный список

Это разумный подход.

Однако подумайте над написанием собственного парсера - очень скоро вы обнаружите, что подход на основе grep выходит из-под контроля (awk будет немного лучше). Довольно скоро вы также захотите начать реализовывать белый список!

В дополнение к очевидным, я бы рекомендовал отмечать все, что включает, аргументом чего-либо, кроме строкового литерала. Остерегайтесь __autoload() тоже.

Боюсь, мой ответ может быть слишком негативным, но...

ИМХО, каждая функция и метод там могут быть использованы в гнусных целях. Думайте об этом как о эффекте ручеек гнусности: переменная присваивается пользователю или удаленному вводу, переменная используется в функции, возвращаемое значение функции используется в свойстве класса, свойство класса используется в файловой функции, и так далее. Помните: поддельный IP-адрес или атака "человек посередине" могут использовать весь ваш сайт.

Лучше всего отслеживать от начала до конца любой возможный пользовательский или удаленный ввод, начиная с $_SERVER, $_GET, $_POST, $_FILE, $_COOKIE, include(some remote file) (если allow_url_fopen все остальные функции / классы, связанные с удаленными файлами и т. д. Вы программно строите профиль трассировки стека для каждого значения, предоставленного пользователем или удаленно. Это можно сделать программным путем, получив все повторяющиеся экземпляры назначенной переменной и функций или методов, в которых она используется, затем рекурсивно составив список всех вхождений этих функций / методов и т. Д. Изучите его, чтобы убедиться, что он сначала проходит через надлежащие функции фильтрации и проверки относительно всех других функций, к которым он прикасается. Это, конечно, ручной экзамен, иначе у вас будет общее количество case переключатели, равные количеству функций и методов в PHP (включая определяемые пользователем).

В качестве альтернативы для обработки только пользовательского ввода имейте статический класс контроллера, инициализированный в начале всех сценариев, который 1) проверяет и сохраняет все предоставленные пользователем входные значения в соответствии с белым списком разрешенных целей; 2) стирает этот источник ввода (т.е. $_SERVER = null). Вы можете видеть, где это становится немного нацистским.

Вот список функций, которые мой провайдер отключает в целях безопасности:

  • Exec
  • дл
  • show_source
  • apache_note
  • apache_setenv
  • closelog
  • debugger_off
  • debugger_on
  • define_syslog_variables
  • escapeshellarg
  • EscapeShellCmd
  • ini_restore
  • openlog
  • пройти
  • pclose
  • pcntl_exec
  • POPEN
  • proc_close
  • proc_get_status
  • proc_nice
  • proc_open
  • proc_terminate
  • shell_exec
  • системный журнал
  • система
  • url_exec

Большинство атак в коде используют несколько источников доступа или несколько шагов для выполнения самих себя. Я бы искал не только код или метод, имеющий вредоносный код, но и все методы, выполняющие функции или вызывающие его. Наилучшая защита также будет включать в себя кодирование и проверку данных формы по мере их поступления.

Также следите за определением системных переменных, они могут впоследствии вызываться из любой функции или метода в коде.

Вы можете найти постоянно обновляемый список чувствительных приемников (эксплуатируемых функций php) и их параметров в RIPS /config/sinks.php, статическом анализаторе исходного кода на наличие уязвимостей в приложениях PHP, который также обнаруживает бэкдоры PHP.

Было обнаружено несколько переполнений буфера с использованием функций 4-битных символов, которые интерпретируют текст. htmlentities() htmlspecialchars()

на вершине, хорошая защита - использовать mb_convert_encoding() для преобразования в одну кодировку перед интерпретацией.

Другие вопросы по тегам