Reputation Activity
-
_Dark_ got a reaction from alcone in Голосование и буква Э в немПроверил у нас — создал репутацию с названием ЭЭЭЭээээ, все работает.
-
_Dark_ got a reaction from alcone in Голосование и буква Э в немВозможно.
-
_Dark_ got a reaction from MGHaze in IP.Board 3.1.x, 3.2.x and 3.3.x Security UpdateОткрыть файл core.php и после 4280 строчки вставить:
/**
* Convert russian mounth names to english
*
* @access public
* @param string Date
* @return string Converted date
*/
static public function monthNameRu2En( $text )
{
return str_replace( array('Январь','Февраль','Март','Апрель','Май','Июнь,','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'), array('January','February','March','April','May','June','July','August','September','October','November','December'), $text );
}
[/CODE]
-
_Dark_ got a reaction from RealUser in Как я взлом сайта расследовал.Если вы зашли сюда — будьте готовы к огромному количеству букв, различных терминов, непонятного кода и т.п.
Началось все с темы.
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
Как мы видим, ошибка незаурядная. Само наличие "ololololololo1" уже говорит о многом, а учитывая то, что все это происходит в файле av-128.jpg — вообще интересно. В общем то, только по вот этим признакам уже можно говорить о том, что сайт подвергся взлому. Первым делом были взяты эти два файла и пока отложены на просторы рабочего стола. Т.к. обсуждать все это на форуме было неудобно — списались с в ICQ. Для начала хотелось выяснить, кто это сделал. Файл uploads/profile/av-128.jpg является аватаркой пользователя с ID 128 (пока не будем говорить о том, как вообще в аватарке оказался PHP код), казалось бы нарушитель найден, но проблема в том, что владелец сайта чистил БД от старых записей и аккаунт пользователя удален. Ладно, к черту тогда личность взломщика, давайте разбираться, что произошло. Первое что приходит в голову — запросить у хостера список измененных .php файлов за последнюю неделю. Запрашиваем. Хостер предоставить их не может, но зато он нам любезно включает SSH доступ (это действительно хорошая черта тех.поддержки хостинга — они поняли в чем дело и без лишних разговоров предоставляют нам то, что в наш тарифный план не входит). Отлично, SSH у нас есть. При помощи простой команды find /public_html/ -type f -iname "*.php" -mtime -7[/code] (полный путь к директории вырезан за ненадобностью) получаем: [spoiler] [code]
public_html/cache/cache_clean.php
public_html/cache/globalCaches.php
public_html/cache/furlCache.php
public_html/cache/skin_cache/cacheid_1/skin_register.php
public_html/cache/skin_cache/cacheid_1/skin_profile.php
public_html/cache/skin_cache/cacheid_1/skin_online.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_support.php
public_html/cache/skin_cache/cacheid_1/skin_editors.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox.php
public_html/cache/skin_cache/cacheid_1/skin_stats.php
public_html/cache/skin_cache/cacheid_1/skin_upload.php
public_html/cache/skin_cache/cacheid_1/skin_emails.php
public_html/cache/skin_cache/cacheid_1/skin_promenu.php
public_html/cache/skin_cache/cacheid_1/skin_ipseo.php
public_html/cache/skin_cache/cacheid_1/skin_login.php
public_html/cache/skin_cache/cacheid_1/skin_mod.php
public_html/cache/skin_cache/cacheid_1/skin_search.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox_hooks.php
public_html/cache/skin_cache/cacheid_1/skin_boards.php
public_html/cache/skin_cache/cacheid_1/skin_gms.php
public_html/cache/skin_cache/cacheid_1/skin_messaging.php
public_html/cache/skin_cache/cacheid_1/skin_legends.php
public_html/cache/skin_cache/cacheid_1/skin_cp.php
public_html/cache/skin_cache/cacheid_1/skin_post.php
public_html/cache/skin_cache/cacheid_1/skin_mlist.php
public_html/cache/skin_cache/cacheid_1/skin_modcp.php
public_html/cache/skin_cache/cacheid_1/skin_global_other.php
public_html/cache/skin_cache/cacheid_1/skin_reports.php
public_html/cache/skin_cache/cacheid_1/skin_global.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_clients.php
public_html/cache/skin_cache/cacheid_1/skin_topic.php
public_html/cache/skin_cache/cacheid_1/skin_help.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_emails.php
public_html/cache/skin_cache/cacheid_1/skin_ucp.php
public_html/cache/skin_cache/cacheid_1/skin_global_comments.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_payments.php
public_html/cache/skin_cache/cacheid_1/skin_forum.php
public_html/cache/cache.php
public_html/cache/aq.php
public_html/cache/sd2178.php
public_html/hooks/ipSeoPingTopics_9be3a8f6d34784b16a253af2060440da.php
public_html/hooks/ipSeoAcronymsEditor_f29ecb558858bb04bf957fb505093329.php
public_html/hooks/ipSeoMeta_1dfa8b1e2915158bcd0bc2ca20a90f4f.php
public_html/hooks/dp3_fi_boardsClassActionOverloader_5fee7a7dd42c37cd850eba64e519789d.php
public_html/hooks/cstopspamreg_cea6e736e42ab14fa64581f28c8c08d1.php
public_html/hooks/passwordStrength_skin_7b219a756db0cc9bcbf78cb9b17ad92f.php
public_html/hooks/ipSeoGuestSkin_ceb6061092c92fc4b36e682aabaa5c96.php
public_html/hooks/globalProMenuRemovalTool_f73b5f48f7515d65c93216498d309aac.php
public_html/hooks/cstopspamreg_bstats_99fac0fad97daf26fb18c4e61a46ed90.php
public_html/hooks/topicosrecentes_ucp_8eced785d6487592b493fc683e778f68.php
public_html/hooks/dp3_fi_forumsClassActionOverloader_0317c8e4a356386124447e57d90a0188.php
public_html/hooks/globalProMenuJava_1e4b91655304505004f3429052bc0561.php
public_html/hooks/ipSeoAcronymsBbcodeParser_46716b0eace16d346a426516a5a550ca.php
[/code] [/spoiler] В глаза бросается [code]
public_html/cache/aq.php
public_html/cache/sd2178.php
(названия файлов изменены, т.к. пока незачем их публиковать всем).
[/code] (файл [font=courier new,courier,monospace]public_html/cache/cache.php[/font] я заметил только когда писал это, с ним тоже разберемся). Первый файл оказывается скриптом, значение которого я так и не понял. Второй файл имеет интересное содержание. После небольшой пробежки по Google оказываемся здесь. Все понятно, бэкдор из паблика. Удалять эти файлы как-то банально, сделаем по другому — заставим эти файлы работать на нас. Я не буду приводить код, скажу только, что IP-адрес, а так же информация о системе каждого, кто откроет эти файлы будут сохранены. С этим разобрались. Но очевидно, что "центр" взлома находится не здесь, а вон в тех аватарках с PHP кодом. Нам нужно определить, что этот код делает, чтобы установить, для чего был осуществлен взлом. Для начала берем первый файл — [b]av-128.php[/b]. Открываем его. Смотрим. Это кошмар. Во-первых, сразу видно, что код обфусцирован. Во-вторых, начисто нет форматирования кода. Начинаем с малого, приведем код к читаемому виду, в плане переносов строк. Для этого воспользуемся вот этим прекрасным сервисом, который отформатирует код за нас. Прогоняем код. Получаем результат, смотрим. Красота. Код стал более читабелен, мы можем сразу провести небольшой анализ. В коде нет зарезервированных слов PHP (if, function, for, while, и т.д.). Значит код в том виде, в котором он сейчас использует только стандартные функции PHP, не определяя свои. Из первого пункта получаем, что код обфусцирован несколько раз (почему? Потому что свои функции у скрипта все таки есть, помните ошибку, с которой все начиналось?). Скорее всего деобфусцировать код автоматически не выйдет. Поискав в Google сервисы для деобфускации становится понятно, что все что там есть — ерунда. Ну что ж, будем делать все самостоятельно. [size=5][b]Этап 1.[/b][/size] Бегло взглянув на код и обнаружив множество текстовых строк, а затем одну, которая все их объединяет [code]
$v3IWiBF = // и здесь все эти текстовые строки
[/code] приходим к выводу, что на данной стадии в коде минимум логики. Нужно найти переход с этого уровня кода на более низкий. Смотрим где же используется эта переменная [font=courier new,courier,monospace]$v3IWiBF[/font] с огромным текстом внутри. В коде таких упоминаний одно, это [code]
$lGp2BqP = $Mb8Ze($v3IWiBF, $hFl0_($Jj1U($TjMGm), $Jj1U($VtLjYNP)));
[/code] Ладно, смотрим где встречается собственно [font=courier new,courier,monospace]$lGp2BqP[/font], а это — последняя строка, вот [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Значит переход на более низкий уровень кода находится на последней строке, это означает, что код обфусцирован [i]последовательно[/i], т.е. весь код (а не его отдельные части) был обфусцирован несколько раз. Это упрощает работу, значит нам тоже разбирать код можно последовательно, не пытаясь найти места, с которых начать. [size=5][b]Этап 2.[/b][/size] Есть такие задачки для маленьких детей, где нарисованы какие-то непрерывные линии, их начала и концы указаны и нужно найти какая линия к чему приведет, причем начал больше чем концов. Легче всего это решить пойдя по этим линиям с конца, вот и мы поступим так же. У нас есть функция, которая ведет к переходу на более низкий уровень кода — эта та самая последняя строчка [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Будем работать над ней. Смотрим на образование названия самой функции: [code]
$oWHh = "\160\162";
$zYdUyk = 'eg';
$XqVM = "\137\162";
$PU0b = "\145\160";
$I0Tf = "\154\141";
$qGX8ht = "\143\145";
$d1QZk = $oWHh . $zYdUyk . $XqVM . $PU0b . $I0Tf . $qGX8ht;[/code] Через секунд 10 раздумий в голову приходит, что 160, 162, 137 и т.д. — это ASCII коды и о них нам рассказывали где-то в школе. Ищем таблицу ASCII кодов, открываем, ищем число 160. Находим, это символ [b][size=4]á[/size][/b]. В PHP нет стандартных функций в названиях которых используются такие символы (а на данном уровне кода у скрипта тоже никаких своих функций нет, помните мы выше это выяснили). Значит 160 нам не подходит, но ведь в коде он используется. Вспоминаем синтаксис PHP, черт, ведь там код символа указывается в восьмеричной системе исчисления. Смотрим тогда колонку [i]Oct[/i] (Octal — восьмеричная система исчисления). Находим, это латинская буква [b]p[/b]. Подходит! Смотрим дальше. 162 — это буква [b]r[/b], получаем, что [code]$oWHh = "\160\162";
$zYdUyk = 'eg';[/code] это ни что иное, как [b]preg[/b], т.е. это библиотека для работы с регулярными выражениями в PHP. Смотрим дальше, когда мы получаем[b] preg_r [/b]становится понятно, что вся функция имеет название [b]preg_replace[/b]. Промежуточный результат: [code]preg_replace($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Ну, совсем просто узнаем, что [font=courier new,courier,monospace]$phl6yJ[/font] это [code]/.*/e[/code] . Промежуточный результат: [code]preg_replace('/.*/e', $r6Q7D($lGp2BqP), $PJf4o9);[/code] Смотрим, что такое [font=courier new,courier,monospace]$r6Q7D[/font]. В коде это [code]
$BiDR51n = "\142\141";
$IhcdiCL = 'se';
$Vq5GI = '64';
$ID4o = "\137\144";
$nBHq = 'ec';
$ekeM_1 = "\157\144";
$NViQXn = "\145";
$r6Q7D = $BiDR51n . $IhcdiCL . $Vq5GI . $ID4o . $nBHq . $ekeM_1 . $NViQXn;
[/code] Увидев [font=courier new,courier,monospace]..se64..ec...[/font] машинально вспоминаем [code]base64_decode[/code] Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), $PJf4o9);[/code] [font=courier new,courier,monospace]$lGp2BqP[/font] — это результат работы какой-то функции, которая обрабатывает результат другой функции, пропустим пока. Остается [font=courier new,courier,monospace]$PJf4o9[/font]. Находим [code]
$uRk52 = "";
$PJf4o9 = $uRk52;
[/code] в самом начале файла. Пустая строка. Отлично. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), '');[/code] Теперь будем разбираться с [font=courier new,courier,monospace]$lGp2BqP[/font]. Путем рассуждений которые мы делали выше узнаем, что [font=courier new,courier,monospace]$lGp2BqP [/font]— это [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split($TjMGm), str_split($VtLjYNP)));[/code] Подставляем переменные и получаем [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')));[/code] А [font=courier new,courier,monospace]$v3IWiBF[/font] — это та огромная строка, про которую мы говорили в самом начале. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode(strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')))), '');[/code] [code]'/.*/e'[/code] в регулярном выражении означает выполнение кода, указанного в строке. Значит нам нужно получить эту строку, это основной код скрипта. Выполняем [font=courier new,courier,monospace]base64_decode[/font] и получаем вот это. [b][size=5]Этап 3[/size][/b] Переходим на еще более низкий уровень кода, опять выполнив [font=courier new,courier,monospace]base64_decode[/font]. Результат. Вот мы и добрались до этой функции [font=courier new,courier,monospace]ololololololo1[/font]. Смотрим и видим это [code]\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28'[/code] Это пошли уже HEX коды символов, расшифровав получаем [code]
eval(gzinflate(base64_decode('/* зашифрованный код */')));
[/code] Переходим еще на уровень ниже... [b][size=5]Этап 4[/size][/b] Вот он код, ребята! После небольшой паузы я начал смеяться, нет, правда Мы получили такой же код, как и в файле [code]public_html/cache/sd2178.php[/code] , отличие только в том, что он выполняется, если у пользователя установлена cookie с названием [b]zx[/b]. Получается, мы просто потратили время впустую? Нет. Во-первых, знаете, это вообще клёвое (я вообще никогда не ставлю букву Ё при набирании текста на клавиатуре, это исторический момент) чувство когда делаешь что-то вроде взлома. Ведь в самом деле, мы только что взломали защиту, которую кто-то делал. Во-вторых, лично я получил прекрасный опыт работы с [b]таким[/b] кодом. Можно считать эта была тренировка на умение ориентироваться и разбираться в защищенном коде. В-третьих, я могу сказать владельцу сайта (как писал я уже выше — это [member='Fensmas']), что ничего супер-страшного в этом коде не нашлось (нет, вообще этот скрипт может многое, вплоть до удаления всех файлов сайта, но мы сделали все вовремя). А вообще у нас есть еще один файл — [font=courier new,courier,monospace]uploads/profile/photo-128.jpg[/font], но разбирать его нет смысла. Вспомним ошибку: [CODE]
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
[/code]
Если кратко — код в этом файле является идентичным коду, который мы только что разбирали.
[size=5][b]Итоги[/b][/size]
Каждый сайт подвержен взлому, различия в том, что кто-то менее, кто-то более, зависит это от версий установленных скриптов.
Я помню у нас тут были люди, которые не хотели обновляться "потому что нет ничего нового". Тем не менее обновляться надо всегда!
Так же нельзя не забывать про патчи безопасности, которые тоже необходимо устанавливать.
Учитывая то, что в общем-то код был один и тот же, можно предположить, что через один бэкдор были закачаны все остальные (а не было взлома еще и механизма кэширования IP.Board).
В любом случае, я считаю, что это время я потратил не зря, хотя бы потому что это было интересно.
Спасибо.
Respected: так же можете почитать эту статью:
[size=5][b]UPDATE 09.11.2012[/b][/size]
Способ взлома сайта найден.
Подробности опубликованы в теме.
-
_Dark_ reacted to podvorie in Русский язык для IP. GalleryНазвание: Русский язык для IP. Gallery
Добавил: podvorie
Добавлен: 08 Ноя 2012
Категория: Локализация IP.Board
Полностью переведена клиентская часть. Частично админка.
Остался не переведенным блок public_meta ибо критической информации не имеет. Если будет необходимость переведу и ее.
-
_Dark_ got a reaction from SUAMF in Как я взлом сайта расследовал.Если вы зашли сюда — будьте готовы к огромному количеству букв, различных терминов, непонятного кода и т.п.
Началось все с темы.
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
Как мы видим, ошибка незаурядная. Само наличие "ololololololo1" уже говорит о многом, а учитывая то, что все это происходит в файле av-128.jpg — вообще интересно. В общем то, только по вот этим признакам уже можно говорить о том, что сайт подвергся взлому. Первым делом были взяты эти два файла и пока отложены на просторы рабочего стола. Т.к. обсуждать все это на форуме было неудобно — списались с в ICQ. Для начала хотелось выяснить, кто это сделал. Файл uploads/profile/av-128.jpg является аватаркой пользователя с ID 128 (пока не будем говорить о том, как вообще в аватарке оказался PHP код), казалось бы нарушитель найден, но проблема в том, что владелец сайта чистил БД от старых записей и аккаунт пользователя удален. Ладно, к черту тогда личность взломщика, давайте разбираться, что произошло. Первое что приходит в голову — запросить у хостера список измененных .php файлов за последнюю неделю. Запрашиваем. Хостер предоставить их не может, но зато он нам любезно включает SSH доступ (это действительно хорошая черта тех.поддержки хостинга — они поняли в чем дело и без лишних разговоров предоставляют нам то, что в наш тарифный план не входит). Отлично, SSH у нас есть. При помощи простой команды find /public_html/ -type f -iname "*.php" -mtime -7[/code] (полный путь к директории вырезан за ненадобностью) получаем: [spoiler] [code]
public_html/cache/cache_clean.php
public_html/cache/globalCaches.php
public_html/cache/furlCache.php
public_html/cache/skin_cache/cacheid_1/skin_register.php
public_html/cache/skin_cache/cacheid_1/skin_profile.php
public_html/cache/skin_cache/cacheid_1/skin_online.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_support.php
public_html/cache/skin_cache/cacheid_1/skin_editors.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox.php
public_html/cache/skin_cache/cacheid_1/skin_stats.php
public_html/cache/skin_cache/cacheid_1/skin_upload.php
public_html/cache/skin_cache/cacheid_1/skin_emails.php
public_html/cache/skin_cache/cacheid_1/skin_promenu.php
public_html/cache/skin_cache/cacheid_1/skin_ipseo.php
public_html/cache/skin_cache/cacheid_1/skin_login.php
public_html/cache/skin_cache/cacheid_1/skin_mod.php
public_html/cache/skin_cache/cacheid_1/skin_search.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox_hooks.php
public_html/cache/skin_cache/cacheid_1/skin_boards.php
public_html/cache/skin_cache/cacheid_1/skin_gms.php
public_html/cache/skin_cache/cacheid_1/skin_messaging.php
public_html/cache/skin_cache/cacheid_1/skin_legends.php
public_html/cache/skin_cache/cacheid_1/skin_cp.php
public_html/cache/skin_cache/cacheid_1/skin_post.php
public_html/cache/skin_cache/cacheid_1/skin_mlist.php
public_html/cache/skin_cache/cacheid_1/skin_modcp.php
public_html/cache/skin_cache/cacheid_1/skin_global_other.php
public_html/cache/skin_cache/cacheid_1/skin_reports.php
public_html/cache/skin_cache/cacheid_1/skin_global.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_clients.php
public_html/cache/skin_cache/cacheid_1/skin_topic.php
public_html/cache/skin_cache/cacheid_1/skin_help.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_emails.php
public_html/cache/skin_cache/cacheid_1/skin_ucp.php
public_html/cache/skin_cache/cacheid_1/skin_global_comments.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_payments.php
public_html/cache/skin_cache/cacheid_1/skin_forum.php
public_html/cache/cache.php
public_html/cache/aq.php
public_html/cache/sd2178.php
public_html/hooks/ipSeoPingTopics_9be3a8f6d34784b16a253af2060440da.php
public_html/hooks/ipSeoAcronymsEditor_f29ecb558858bb04bf957fb505093329.php
public_html/hooks/ipSeoMeta_1dfa8b1e2915158bcd0bc2ca20a90f4f.php
public_html/hooks/dp3_fi_boardsClassActionOverloader_5fee7a7dd42c37cd850eba64e519789d.php
public_html/hooks/cstopspamreg_cea6e736e42ab14fa64581f28c8c08d1.php
public_html/hooks/passwordStrength_skin_7b219a756db0cc9bcbf78cb9b17ad92f.php
public_html/hooks/ipSeoGuestSkin_ceb6061092c92fc4b36e682aabaa5c96.php
public_html/hooks/globalProMenuRemovalTool_f73b5f48f7515d65c93216498d309aac.php
public_html/hooks/cstopspamreg_bstats_99fac0fad97daf26fb18c4e61a46ed90.php
public_html/hooks/topicosrecentes_ucp_8eced785d6487592b493fc683e778f68.php
public_html/hooks/dp3_fi_forumsClassActionOverloader_0317c8e4a356386124447e57d90a0188.php
public_html/hooks/globalProMenuJava_1e4b91655304505004f3429052bc0561.php
public_html/hooks/ipSeoAcronymsBbcodeParser_46716b0eace16d346a426516a5a550ca.php
[/code] [/spoiler] В глаза бросается [code]
public_html/cache/aq.php
public_html/cache/sd2178.php
(названия файлов изменены, т.к. пока незачем их публиковать всем).
[/code] (файл [font=courier new,courier,monospace]public_html/cache/cache.php[/font] я заметил только когда писал это, с ним тоже разберемся). Первый файл оказывается скриптом, значение которого я так и не понял. Второй файл имеет интересное содержание. После небольшой пробежки по Google оказываемся здесь. Все понятно, бэкдор из паблика. Удалять эти файлы как-то банально, сделаем по другому — заставим эти файлы работать на нас. Я не буду приводить код, скажу только, что IP-адрес, а так же информация о системе каждого, кто откроет эти файлы будут сохранены. С этим разобрались. Но очевидно, что "центр" взлома находится не здесь, а вон в тех аватарках с PHP кодом. Нам нужно определить, что этот код делает, чтобы установить, для чего был осуществлен взлом. Для начала берем первый файл — [b]av-128.php[/b]. Открываем его. Смотрим. Это кошмар. Во-первых, сразу видно, что код обфусцирован. Во-вторых, начисто нет форматирования кода. Начинаем с малого, приведем код к читаемому виду, в плане переносов строк. Для этого воспользуемся вот этим прекрасным сервисом, который отформатирует код за нас. Прогоняем код. Получаем результат, смотрим. Красота. Код стал более читабелен, мы можем сразу провести небольшой анализ. В коде нет зарезервированных слов PHP (if, function, for, while, и т.д.). Значит код в том виде, в котором он сейчас использует только стандартные функции PHP, не определяя свои. Из первого пункта получаем, что код обфусцирован несколько раз (почему? Потому что свои функции у скрипта все таки есть, помните ошибку, с которой все начиналось?). Скорее всего деобфусцировать код автоматически не выйдет. Поискав в Google сервисы для деобфускации становится понятно, что все что там есть — ерунда. Ну что ж, будем делать все самостоятельно. [size=5][b]Этап 1.[/b][/size] Бегло взглянув на код и обнаружив множество текстовых строк, а затем одну, которая все их объединяет [code]
$v3IWiBF = // и здесь все эти текстовые строки
[/code] приходим к выводу, что на данной стадии в коде минимум логики. Нужно найти переход с этого уровня кода на более низкий. Смотрим где же используется эта переменная [font=courier new,courier,monospace]$v3IWiBF[/font] с огромным текстом внутри. В коде таких упоминаний одно, это [code]
$lGp2BqP = $Mb8Ze($v3IWiBF, $hFl0_($Jj1U($TjMGm), $Jj1U($VtLjYNP)));
[/code] Ладно, смотрим где встречается собственно [font=courier new,courier,monospace]$lGp2BqP[/font], а это — последняя строка, вот [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Значит переход на более низкий уровень кода находится на последней строке, это означает, что код обфусцирован [i]последовательно[/i], т.е. весь код (а не его отдельные части) был обфусцирован несколько раз. Это упрощает работу, значит нам тоже разбирать код можно последовательно, не пытаясь найти места, с которых начать. [size=5][b]Этап 2.[/b][/size] Есть такие задачки для маленьких детей, где нарисованы какие-то непрерывные линии, их начала и концы указаны и нужно найти какая линия к чему приведет, причем начал больше чем концов. Легче всего это решить пойдя по этим линиям с конца, вот и мы поступим так же. У нас есть функция, которая ведет к переходу на более низкий уровень кода — эта та самая последняя строчка [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Будем работать над ней. Смотрим на образование названия самой функции: [code]
$oWHh = "\160\162";
$zYdUyk = 'eg';
$XqVM = "\137\162";
$PU0b = "\145\160";
$I0Tf = "\154\141";
$qGX8ht = "\143\145";
$d1QZk = $oWHh . $zYdUyk . $XqVM . $PU0b . $I0Tf . $qGX8ht;[/code] Через секунд 10 раздумий в голову приходит, что 160, 162, 137 и т.д. — это ASCII коды и о них нам рассказывали где-то в школе. Ищем таблицу ASCII кодов, открываем, ищем число 160. Находим, это символ [b][size=4]á[/size][/b]. В PHP нет стандартных функций в названиях которых используются такие символы (а на данном уровне кода у скрипта тоже никаких своих функций нет, помните мы выше это выяснили). Значит 160 нам не подходит, но ведь в коде он используется. Вспоминаем синтаксис PHP, черт, ведь там код символа указывается в восьмеричной системе исчисления. Смотрим тогда колонку [i]Oct[/i] (Octal — восьмеричная система исчисления). Находим, это латинская буква [b]p[/b]. Подходит! Смотрим дальше. 162 — это буква [b]r[/b], получаем, что [code]$oWHh = "\160\162";
$zYdUyk = 'eg';[/code] это ни что иное, как [b]preg[/b], т.е. это библиотека для работы с регулярными выражениями в PHP. Смотрим дальше, когда мы получаем[b] preg_r [/b]становится понятно, что вся функция имеет название [b]preg_replace[/b]. Промежуточный результат: [code]preg_replace($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Ну, совсем просто узнаем, что [font=courier new,courier,monospace]$phl6yJ[/font] это [code]/.*/e[/code] . Промежуточный результат: [code]preg_replace('/.*/e', $r6Q7D($lGp2BqP), $PJf4o9);[/code] Смотрим, что такое [font=courier new,courier,monospace]$r6Q7D[/font]. В коде это [code]
$BiDR51n = "\142\141";
$IhcdiCL = 'se';
$Vq5GI = '64';
$ID4o = "\137\144";
$nBHq = 'ec';
$ekeM_1 = "\157\144";
$NViQXn = "\145";
$r6Q7D = $BiDR51n . $IhcdiCL . $Vq5GI . $ID4o . $nBHq . $ekeM_1 . $NViQXn;
[/code] Увидев [font=courier new,courier,monospace]..se64..ec...[/font] машинально вспоминаем [code]base64_decode[/code] Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), $PJf4o9);[/code] [font=courier new,courier,monospace]$lGp2BqP[/font] — это результат работы какой-то функции, которая обрабатывает результат другой функции, пропустим пока. Остается [font=courier new,courier,monospace]$PJf4o9[/font]. Находим [code]
$uRk52 = "";
$PJf4o9 = $uRk52;
[/code] в самом начале файла. Пустая строка. Отлично. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), '');[/code] Теперь будем разбираться с [font=courier new,courier,monospace]$lGp2BqP[/font]. Путем рассуждений которые мы делали выше узнаем, что [font=courier new,courier,monospace]$lGp2BqP [/font]— это [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split($TjMGm), str_split($VtLjYNP)));[/code] Подставляем переменные и получаем [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')));[/code] А [font=courier new,courier,monospace]$v3IWiBF[/font] — это та огромная строка, про которую мы говорили в самом начале. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode(strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')))), '');[/code] [code]'/.*/e'[/code] в регулярном выражении означает выполнение кода, указанного в строке. Значит нам нужно получить эту строку, это основной код скрипта. Выполняем [font=courier new,courier,monospace]base64_decode[/font] и получаем вот это. [b][size=5]Этап 3[/size][/b] Переходим на еще более низкий уровень кода, опять выполнив [font=courier new,courier,monospace]base64_decode[/font]. Результат. Вот мы и добрались до этой функции [font=courier new,courier,monospace]ololololololo1[/font]. Смотрим и видим это [code]\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28'[/code] Это пошли уже HEX коды символов, расшифровав получаем [code]
eval(gzinflate(base64_decode('/* зашифрованный код */')));
[/code] Переходим еще на уровень ниже... [b][size=5]Этап 4[/size][/b] Вот он код, ребята! После небольшой паузы я начал смеяться, нет, правда Мы получили такой же код, как и в файле [code]public_html/cache/sd2178.php[/code] , отличие только в том, что он выполняется, если у пользователя установлена cookie с названием [b]zx[/b]. Получается, мы просто потратили время впустую? Нет. Во-первых, знаете, это вообще клёвое (я вообще никогда не ставлю букву Ё при набирании текста на клавиатуре, это исторический момент) чувство когда делаешь что-то вроде взлома. Ведь в самом деле, мы только что взломали защиту, которую кто-то делал. Во-вторых, лично я получил прекрасный опыт работы с [b]таким[/b] кодом. Можно считать эта была тренировка на умение ориентироваться и разбираться в защищенном коде. В-третьих, я могу сказать владельцу сайта (как писал я уже выше — это [member='Fensmas']), что ничего супер-страшного в этом коде не нашлось (нет, вообще этот скрипт может многое, вплоть до удаления всех файлов сайта, но мы сделали все вовремя). А вообще у нас есть еще один файл — [font=courier new,courier,monospace]uploads/profile/photo-128.jpg[/font], но разбирать его нет смысла. Вспомним ошибку: [CODE]
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
[/code]
Если кратко — код в этом файле является идентичным коду, который мы только что разбирали.
[size=5][b]Итоги[/b][/size]
Каждый сайт подвержен взлому, различия в том, что кто-то менее, кто-то более, зависит это от версий установленных скриптов.
Я помню у нас тут были люди, которые не хотели обновляться "потому что нет ничего нового". Тем не менее обновляться надо всегда!
Так же нельзя не забывать про патчи безопасности, которые тоже необходимо устанавливать.
Учитывая то, что в общем-то код был один и тот же, можно предположить, что через один бэкдор были закачаны все остальные (а не было взлома еще и механизма кэширования IP.Board).
В любом случае, я считаю, что это время я потратил не зря, хотя бы потому что это было интересно.
Спасибо.
Respected: так же можете почитать эту статью:
[size=5][b]UPDATE 09.11.2012[/b][/size]
Способ взлома сайта найден.
Подробности опубликованы в теме.
-
_Dark_ reacted to Respected in Статистика IPBMafia.RuЯ имею ввиду только за сегодня столько нафлудим :D
-
_Dark_ got a reaction from Respected in 500 Internal Server Error на главной форумаЕсли это действительно так, то кто-то просто просмотрел патчи и нашел уязвимость, которую они закрывали.
С главной страницей почти так же было и в том случае.
Включите режим производительности в АЦ и посмотрите, что будет.
-
_Dark_ reacted to Respected in Статистика IPBMafia.RuНет, мы не размещаем нигде рекламу. Всё достаточно просто: многолетний опыт работы IP.Board, публикация своих знаний на форуме, дружеское общение пользователей форума, объединение интересов пользователей в один форум, а так же сплочённая команда IPBMafia Целая цепочка получилась)
-
_Dark_ got a reaction from Respected in Ваш браузер?Интересно посмотреть какими браузерами пользуются в основном владельцы сайтов (не зря вы же здесь находитесь).
В первом вопросе укажите один браузер, который вы используете чаще всего, как основной.
Во втором вопросе укажите все браузеры, которые у вас установлены на компьютере.
Если вы выбираете пункт Другой укажите его название в этой теме.
Желательно, если вы еще оставите здесь сообщение с указанием версий браузеров, которые у вас установлены.
У меня:
Firefox 16.0.2
IE 10
Opera 12.10
Chrome 22
-
_Dark_ got a reaction from Riddick in Как я взлом сайта расследовал.Если вы зашли сюда — будьте готовы к огромному количеству букв, различных терминов, непонятного кода и т.п.
Началось все с темы.
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
Как мы видим, ошибка незаурядная. Само наличие "ololololololo1" уже говорит о многом, а учитывая то, что все это происходит в файле av-128.jpg — вообще интересно. В общем то, только по вот этим признакам уже можно говорить о том, что сайт подвергся взлому. Первым делом были взяты эти два файла и пока отложены на просторы рабочего стола. Т.к. обсуждать все это на форуме было неудобно — списались с в ICQ. Для начала хотелось выяснить, кто это сделал. Файл uploads/profile/av-128.jpg является аватаркой пользователя с ID 128 (пока не будем говорить о том, как вообще в аватарке оказался PHP код), казалось бы нарушитель найден, но проблема в том, что владелец сайта чистил БД от старых записей и аккаунт пользователя удален. Ладно, к черту тогда личность взломщика, давайте разбираться, что произошло. Первое что приходит в голову — запросить у хостера список измененных .php файлов за последнюю неделю. Запрашиваем. Хостер предоставить их не может, но зато он нам любезно включает SSH доступ (это действительно хорошая черта тех.поддержки хостинга — они поняли в чем дело и без лишних разговоров предоставляют нам то, что в наш тарифный план не входит). Отлично, SSH у нас есть. При помощи простой команды find /public_html/ -type f -iname "*.php" -mtime -7[/code] (полный путь к директории вырезан за ненадобностью) получаем: [spoiler] [code]
public_html/cache/cache_clean.php
public_html/cache/globalCaches.php
public_html/cache/furlCache.php
public_html/cache/skin_cache/cacheid_1/skin_register.php
public_html/cache/skin_cache/cacheid_1/skin_profile.php
public_html/cache/skin_cache/cacheid_1/skin_online.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_support.php
public_html/cache/skin_cache/cacheid_1/skin_editors.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox.php
public_html/cache/skin_cache/cacheid_1/skin_stats.php
public_html/cache/skin_cache/cacheid_1/skin_upload.php
public_html/cache/skin_cache/cacheid_1/skin_emails.php
public_html/cache/skin_cache/cacheid_1/skin_promenu.php
public_html/cache/skin_cache/cacheid_1/skin_ipseo.php
public_html/cache/skin_cache/cacheid_1/skin_login.php
public_html/cache/skin_cache/cacheid_1/skin_mod.php
public_html/cache/skin_cache/cacheid_1/skin_search.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox_hooks.php
public_html/cache/skin_cache/cacheid_1/skin_boards.php
public_html/cache/skin_cache/cacheid_1/skin_gms.php
public_html/cache/skin_cache/cacheid_1/skin_messaging.php
public_html/cache/skin_cache/cacheid_1/skin_legends.php
public_html/cache/skin_cache/cacheid_1/skin_cp.php
public_html/cache/skin_cache/cacheid_1/skin_post.php
public_html/cache/skin_cache/cacheid_1/skin_mlist.php
public_html/cache/skin_cache/cacheid_1/skin_modcp.php
public_html/cache/skin_cache/cacheid_1/skin_global_other.php
public_html/cache/skin_cache/cacheid_1/skin_reports.php
public_html/cache/skin_cache/cacheid_1/skin_global.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_clients.php
public_html/cache/skin_cache/cacheid_1/skin_topic.php
public_html/cache/skin_cache/cacheid_1/skin_help.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_emails.php
public_html/cache/skin_cache/cacheid_1/skin_ucp.php
public_html/cache/skin_cache/cacheid_1/skin_global_comments.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_payments.php
public_html/cache/skin_cache/cacheid_1/skin_forum.php
public_html/cache/cache.php
public_html/cache/aq.php
public_html/cache/sd2178.php
public_html/hooks/ipSeoPingTopics_9be3a8f6d34784b16a253af2060440da.php
public_html/hooks/ipSeoAcronymsEditor_f29ecb558858bb04bf957fb505093329.php
public_html/hooks/ipSeoMeta_1dfa8b1e2915158bcd0bc2ca20a90f4f.php
public_html/hooks/dp3_fi_boardsClassActionOverloader_5fee7a7dd42c37cd850eba64e519789d.php
public_html/hooks/cstopspamreg_cea6e736e42ab14fa64581f28c8c08d1.php
public_html/hooks/passwordStrength_skin_7b219a756db0cc9bcbf78cb9b17ad92f.php
public_html/hooks/ipSeoGuestSkin_ceb6061092c92fc4b36e682aabaa5c96.php
public_html/hooks/globalProMenuRemovalTool_f73b5f48f7515d65c93216498d309aac.php
public_html/hooks/cstopspamreg_bstats_99fac0fad97daf26fb18c4e61a46ed90.php
public_html/hooks/topicosrecentes_ucp_8eced785d6487592b493fc683e778f68.php
public_html/hooks/dp3_fi_forumsClassActionOverloader_0317c8e4a356386124447e57d90a0188.php
public_html/hooks/globalProMenuJava_1e4b91655304505004f3429052bc0561.php
public_html/hooks/ipSeoAcronymsBbcodeParser_46716b0eace16d346a426516a5a550ca.php
[/code] [/spoiler] В глаза бросается [code]
public_html/cache/aq.php
public_html/cache/sd2178.php
(названия файлов изменены, т.к. пока незачем их публиковать всем).
[/code] (файл [font=courier new,courier,monospace]public_html/cache/cache.php[/font] я заметил только когда писал это, с ним тоже разберемся). Первый файл оказывается скриптом, значение которого я так и не понял. Второй файл имеет интересное содержание. После небольшой пробежки по Google оказываемся здесь. Все понятно, бэкдор из паблика. Удалять эти файлы как-то банально, сделаем по другому — заставим эти файлы работать на нас. Я не буду приводить код, скажу только, что IP-адрес, а так же информация о системе каждого, кто откроет эти файлы будут сохранены. С этим разобрались. Но очевидно, что "центр" взлома находится не здесь, а вон в тех аватарках с PHP кодом. Нам нужно определить, что этот код делает, чтобы установить, для чего был осуществлен взлом. Для начала берем первый файл — [b]av-128.php[/b]. Открываем его. Смотрим. Это кошмар. Во-первых, сразу видно, что код обфусцирован. Во-вторых, начисто нет форматирования кода. Начинаем с малого, приведем код к читаемому виду, в плане переносов строк. Для этого воспользуемся вот этим прекрасным сервисом, который отформатирует код за нас. Прогоняем код. Получаем результат, смотрим. Красота. Код стал более читабелен, мы можем сразу провести небольшой анализ. В коде нет зарезервированных слов PHP (if, function, for, while, и т.д.). Значит код в том виде, в котором он сейчас использует только стандартные функции PHP, не определяя свои. Из первого пункта получаем, что код обфусцирован несколько раз (почему? Потому что свои функции у скрипта все таки есть, помните ошибку, с которой все начиналось?). Скорее всего деобфусцировать код автоматически не выйдет. Поискав в Google сервисы для деобфускации становится понятно, что все что там есть — ерунда. Ну что ж, будем делать все самостоятельно. [size=5][b]Этап 1.[/b][/size] Бегло взглянув на код и обнаружив множество текстовых строк, а затем одну, которая все их объединяет [code]
$v3IWiBF = // и здесь все эти текстовые строки
[/code] приходим к выводу, что на данной стадии в коде минимум логики. Нужно найти переход с этого уровня кода на более низкий. Смотрим где же используется эта переменная [font=courier new,courier,monospace]$v3IWiBF[/font] с огромным текстом внутри. В коде таких упоминаний одно, это [code]
$lGp2BqP = $Mb8Ze($v3IWiBF, $hFl0_($Jj1U($TjMGm), $Jj1U($VtLjYNP)));
[/code] Ладно, смотрим где встречается собственно [font=courier new,courier,monospace]$lGp2BqP[/font], а это — последняя строка, вот [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Значит переход на более низкий уровень кода находится на последней строке, это означает, что код обфусцирован [i]последовательно[/i], т.е. весь код (а не его отдельные части) был обфусцирован несколько раз. Это упрощает работу, значит нам тоже разбирать код можно последовательно, не пытаясь найти места, с которых начать. [size=5][b]Этап 2.[/b][/size] Есть такие задачки для маленьких детей, где нарисованы какие-то непрерывные линии, их начала и концы указаны и нужно найти какая линия к чему приведет, причем начал больше чем концов. Легче всего это решить пойдя по этим линиям с конца, вот и мы поступим так же. У нас есть функция, которая ведет к переходу на более низкий уровень кода — эта та самая последняя строчка [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Будем работать над ней. Смотрим на образование названия самой функции: [code]
$oWHh = "\160\162";
$zYdUyk = 'eg';
$XqVM = "\137\162";
$PU0b = "\145\160";
$I0Tf = "\154\141";
$qGX8ht = "\143\145";
$d1QZk = $oWHh . $zYdUyk . $XqVM . $PU0b . $I0Tf . $qGX8ht;[/code] Через секунд 10 раздумий в голову приходит, что 160, 162, 137 и т.д. — это ASCII коды и о них нам рассказывали где-то в школе. Ищем таблицу ASCII кодов, открываем, ищем число 160. Находим, это символ [b][size=4]á[/size][/b]. В PHP нет стандартных функций в названиях которых используются такие символы (а на данном уровне кода у скрипта тоже никаких своих функций нет, помните мы выше это выяснили). Значит 160 нам не подходит, но ведь в коде он используется. Вспоминаем синтаксис PHP, черт, ведь там код символа указывается в восьмеричной системе исчисления. Смотрим тогда колонку [i]Oct[/i] (Octal — восьмеричная система исчисления). Находим, это латинская буква [b]p[/b]. Подходит! Смотрим дальше. 162 — это буква [b]r[/b], получаем, что [code]$oWHh = "\160\162";
$zYdUyk = 'eg';[/code] это ни что иное, как [b]preg[/b], т.е. это библиотека для работы с регулярными выражениями в PHP. Смотрим дальше, когда мы получаем[b] preg_r [/b]становится понятно, что вся функция имеет название [b]preg_replace[/b]. Промежуточный результат: [code]preg_replace($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Ну, совсем просто узнаем, что [font=courier new,courier,monospace]$phl6yJ[/font] это [code]/.*/e[/code] . Промежуточный результат: [code]preg_replace('/.*/e', $r6Q7D($lGp2BqP), $PJf4o9);[/code] Смотрим, что такое [font=courier new,courier,monospace]$r6Q7D[/font]. В коде это [code]
$BiDR51n = "\142\141";
$IhcdiCL = 'se';
$Vq5GI = '64';
$ID4o = "\137\144";
$nBHq = 'ec';
$ekeM_1 = "\157\144";
$NViQXn = "\145";
$r6Q7D = $BiDR51n . $IhcdiCL . $Vq5GI . $ID4o . $nBHq . $ekeM_1 . $NViQXn;
[/code] Увидев [font=courier new,courier,monospace]..se64..ec...[/font] машинально вспоминаем [code]base64_decode[/code] Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), $PJf4o9);[/code] [font=courier new,courier,monospace]$lGp2BqP[/font] — это результат работы какой-то функции, которая обрабатывает результат другой функции, пропустим пока. Остается [font=courier new,courier,monospace]$PJf4o9[/font]. Находим [code]
$uRk52 = "";
$PJf4o9 = $uRk52;
[/code] в самом начале файла. Пустая строка. Отлично. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), '');[/code] Теперь будем разбираться с [font=courier new,courier,monospace]$lGp2BqP[/font]. Путем рассуждений которые мы делали выше узнаем, что [font=courier new,courier,monospace]$lGp2BqP [/font]— это [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split($TjMGm), str_split($VtLjYNP)));[/code] Подставляем переменные и получаем [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')));[/code] А [font=courier new,courier,monospace]$v3IWiBF[/font] — это та огромная строка, про которую мы говорили в самом начале. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode(strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')))), '');[/code] [code]'/.*/e'[/code] в регулярном выражении означает выполнение кода, указанного в строке. Значит нам нужно получить эту строку, это основной код скрипта. Выполняем [font=courier new,courier,monospace]base64_decode[/font] и получаем вот это. [b][size=5]Этап 3[/size][/b] Переходим на еще более низкий уровень кода, опять выполнив [font=courier new,courier,monospace]base64_decode[/font]. Результат. Вот мы и добрались до этой функции [font=courier new,courier,monospace]ololololololo1[/font]. Смотрим и видим это [code]\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28'[/code] Это пошли уже HEX коды символов, расшифровав получаем [code]
eval(gzinflate(base64_decode('/* зашифрованный код */')));
[/code] Переходим еще на уровень ниже... [b][size=5]Этап 4[/size][/b] Вот он код, ребята! После небольшой паузы я начал смеяться, нет, правда Мы получили такой же код, как и в файле [code]public_html/cache/sd2178.php[/code] , отличие только в том, что он выполняется, если у пользователя установлена cookie с названием [b]zx[/b]. Получается, мы просто потратили время впустую? Нет. Во-первых, знаете, это вообще клёвое (я вообще никогда не ставлю букву Ё при набирании текста на клавиатуре, это исторический момент) чувство когда делаешь что-то вроде взлома. Ведь в самом деле, мы только что взломали защиту, которую кто-то делал. Во-вторых, лично я получил прекрасный опыт работы с [b]таким[/b] кодом. Можно считать эта была тренировка на умение ориентироваться и разбираться в защищенном коде. В-третьих, я могу сказать владельцу сайта (как писал я уже выше — это [member='Fensmas']), что ничего супер-страшного в этом коде не нашлось (нет, вообще этот скрипт может многое, вплоть до удаления всех файлов сайта, но мы сделали все вовремя). А вообще у нас есть еще один файл — [font=courier new,courier,monospace]uploads/profile/photo-128.jpg[/font], но разбирать его нет смысла. Вспомним ошибку: [CODE]
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
[/code]
Если кратко — код в этом файле является идентичным коду, который мы только что разбирали.
[size=5][b]Итоги[/b][/size]
Каждый сайт подвержен взлому, различия в том, что кто-то менее, кто-то более, зависит это от версий установленных скриптов.
Я помню у нас тут были люди, которые не хотели обновляться "потому что нет ничего нового". Тем не менее обновляться надо всегда!
Так же нельзя не забывать про патчи безопасности, которые тоже необходимо устанавливать.
Учитывая то, что в общем-то код был один и тот же, можно предположить, что через один бэкдор были закачаны все остальные (а не было взлома еще и механизма кэширования IP.Board).
В любом случае, я считаю, что это время я потратил не зря, хотя бы потому что это было интересно.
Спасибо.
Respected: так же можете почитать эту статью:
[size=5][b]UPDATE 09.11.2012[/b][/size]
Способ взлома сайта найден.
Подробности опубликованы в теме.
-
_Dark_ got a reaction from Prowler in IP.Board 3.3.x, 3.2.x, and 3.1.x Critical Security Update (6 November 2012)Добавил обновление для IP.Board 3.2.
Обновил наши релизы IP.Board 3.2.3 и 3.3.4.
-
_Dark_ got a reaction from St1L75 in IP.Board 3.3.x, 3.2.x, and 3.1.x Critical Security Update (6 November 2012)Перечитайте первое сообщение, пункт Замечания.
-
_Dark_ got a reaction from Prowler in IP.Board 3.3.x, 3.2.x, and 3.1.x Critical Security Update (6 November 2012)Обновил первое сообщение.
Версию для 3.2.x выложу позже.
-
_Dark_ got a reaction from Prowler in IP.Board 3.3.x, 3.2.x, and 3.1.x Critical Security Update (6 November 2012)Я же предупредил.
-
_Dark_ got a reaction from Prowler in IP.Board 3.3.x, 3.2.x, and 3.1.x Critical Security Update (6 November 2012)Устанавливать нельзя, лицензия пропадет. Позже выложу версии с необходимыми изменениями, чтобы так как с предыдущим фиксом не получилось.
-
_Dark_ got a reaction from Prowler in IP.Board 3.3.x, 3.2.x, and 3.1.x Critical Security Update (6 November 2012)Все можно.
-
_Dark_ got a reaction from Lordbl4 in Как я взлом сайта расследовал.Если вы зашли сюда — будьте готовы к огромному количеству букв, различных терминов, непонятного кода и т.п.
Началось все с темы.
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
Как мы видим, ошибка незаурядная. Само наличие "ololololololo1" уже говорит о многом, а учитывая то, что все это происходит в файле av-128.jpg — вообще интересно. В общем то, только по вот этим признакам уже можно говорить о том, что сайт подвергся взлому. Первым делом были взяты эти два файла и пока отложены на просторы рабочего стола. Т.к. обсуждать все это на форуме было неудобно — списались с в ICQ. Для начала хотелось выяснить, кто это сделал. Файл uploads/profile/av-128.jpg является аватаркой пользователя с ID 128 (пока не будем говорить о том, как вообще в аватарке оказался PHP код), казалось бы нарушитель найден, но проблема в том, что владелец сайта чистил БД от старых записей и аккаунт пользователя удален. Ладно, к черту тогда личность взломщика, давайте разбираться, что произошло. Первое что приходит в голову — запросить у хостера список измененных .php файлов за последнюю неделю. Запрашиваем. Хостер предоставить их не может, но зато он нам любезно включает SSH доступ (это действительно хорошая черта тех.поддержки хостинга — они поняли в чем дело и без лишних разговоров предоставляют нам то, что в наш тарифный план не входит). Отлично, SSH у нас есть. При помощи простой команды find /public_html/ -type f -iname "*.php" -mtime -7[/code] (полный путь к директории вырезан за ненадобностью) получаем: [spoiler] [code]
public_html/cache/cache_clean.php
public_html/cache/globalCaches.php
public_html/cache/furlCache.php
public_html/cache/skin_cache/cacheid_1/skin_register.php
public_html/cache/skin_cache/cacheid_1/skin_profile.php
public_html/cache/skin_cache/cacheid_1/skin_online.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_support.php
public_html/cache/skin_cache/cacheid_1/skin_editors.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox.php
public_html/cache/skin_cache/cacheid_1/skin_stats.php
public_html/cache/skin_cache/cacheid_1/skin_upload.php
public_html/cache/skin_cache/cacheid_1/skin_emails.php
public_html/cache/skin_cache/cacheid_1/skin_promenu.php
public_html/cache/skin_cache/cacheid_1/skin_ipseo.php
public_html/cache/skin_cache/cacheid_1/skin_login.php
public_html/cache/skin_cache/cacheid_1/skin_mod.php
public_html/cache/skin_cache/cacheid_1/skin_search.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox_hooks.php
public_html/cache/skin_cache/cacheid_1/skin_boards.php
public_html/cache/skin_cache/cacheid_1/skin_gms.php
public_html/cache/skin_cache/cacheid_1/skin_messaging.php
public_html/cache/skin_cache/cacheid_1/skin_legends.php
public_html/cache/skin_cache/cacheid_1/skin_cp.php
public_html/cache/skin_cache/cacheid_1/skin_post.php
public_html/cache/skin_cache/cacheid_1/skin_mlist.php
public_html/cache/skin_cache/cacheid_1/skin_modcp.php
public_html/cache/skin_cache/cacheid_1/skin_global_other.php
public_html/cache/skin_cache/cacheid_1/skin_reports.php
public_html/cache/skin_cache/cacheid_1/skin_global.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_clients.php
public_html/cache/skin_cache/cacheid_1/skin_topic.php
public_html/cache/skin_cache/cacheid_1/skin_help.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_emails.php
public_html/cache/skin_cache/cacheid_1/skin_ucp.php
public_html/cache/skin_cache/cacheid_1/skin_global_comments.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_payments.php
public_html/cache/skin_cache/cacheid_1/skin_forum.php
public_html/cache/cache.php
public_html/cache/aq.php
public_html/cache/sd2178.php
public_html/hooks/ipSeoPingTopics_9be3a8f6d34784b16a253af2060440da.php
public_html/hooks/ipSeoAcronymsEditor_f29ecb558858bb04bf957fb505093329.php
public_html/hooks/ipSeoMeta_1dfa8b1e2915158bcd0bc2ca20a90f4f.php
public_html/hooks/dp3_fi_boardsClassActionOverloader_5fee7a7dd42c37cd850eba64e519789d.php
public_html/hooks/cstopspamreg_cea6e736e42ab14fa64581f28c8c08d1.php
public_html/hooks/passwordStrength_skin_7b219a756db0cc9bcbf78cb9b17ad92f.php
public_html/hooks/ipSeoGuestSkin_ceb6061092c92fc4b36e682aabaa5c96.php
public_html/hooks/globalProMenuRemovalTool_f73b5f48f7515d65c93216498d309aac.php
public_html/hooks/cstopspamreg_bstats_99fac0fad97daf26fb18c4e61a46ed90.php
public_html/hooks/topicosrecentes_ucp_8eced785d6487592b493fc683e778f68.php
public_html/hooks/dp3_fi_forumsClassActionOverloader_0317c8e4a356386124447e57d90a0188.php
public_html/hooks/globalProMenuJava_1e4b91655304505004f3429052bc0561.php
public_html/hooks/ipSeoAcronymsBbcodeParser_46716b0eace16d346a426516a5a550ca.php
[/code] [/spoiler] В глаза бросается [code]
public_html/cache/aq.php
public_html/cache/sd2178.php
(названия файлов изменены, т.к. пока незачем их публиковать всем).
[/code] (файл [font=courier new,courier,monospace]public_html/cache/cache.php[/font] я заметил только когда писал это, с ним тоже разберемся). Первый файл оказывается скриптом, значение которого я так и не понял. Второй файл имеет интересное содержание. После небольшой пробежки по Google оказываемся здесь. Все понятно, бэкдор из паблика. Удалять эти файлы как-то банально, сделаем по другому — заставим эти файлы работать на нас. Я не буду приводить код, скажу только, что IP-адрес, а так же информация о системе каждого, кто откроет эти файлы будут сохранены. С этим разобрались. Но очевидно, что "центр" взлома находится не здесь, а вон в тех аватарках с PHP кодом. Нам нужно определить, что этот код делает, чтобы установить, для чего был осуществлен взлом. Для начала берем первый файл — [b]av-128.php[/b]. Открываем его. Смотрим. Это кошмар. Во-первых, сразу видно, что код обфусцирован. Во-вторых, начисто нет форматирования кода. Начинаем с малого, приведем код к читаемому виду, в плане переносов строк. Для этого воспользуемся вот этим прекрасным сервисом, который отформатирует код за нас. Прогоняем код. Получаем результат, смотрим. Красота. Код стал более читабелен, мы можем сразу провести небольшой анализ. В коде нет зарезервированных слов PHP (if, function, for, while, и т.д.). Значит код в том виде, в котором он сейчас использует только стандартные функции PHP, не определяя свои. Из первого пункта получаем, что код обфусцирован несколько раз (почему? Потому что свои функции у скрипта все таки есть, помните ошибку, с которой все начиналось?). Скорее всего деобфусцировать код автоматически не выйдет. Поискав в Google сервисы для деобфускации становится понятно, что все что там есть — ерунда. Ну что ж, будем делать все самостоятельно. [size=5][b]Этап 1.[/b][/size] Бегло взглянув на код и обнаружив множество текстовых строк, а затем одну, которая все их объединяет [code]
$v3IWiBF = // и здесь все эти текстовые строки
[/code] приходим к выводу, что на данной стадии в коде минимум логики. Нужно найти переход с этого уровня кода на более низкий. Смотрим где же используется эта переменная [font=courier new,courier,monospace]$v3IWiBF[/font] с огромным текстом внутри. В коде таких упоминаний одно, это [code]
$lGp2BqP = $Mb8Ze($v3IWiBF, $hFl0_($Jj1U($TjMGm), $Jj1U($VtLjYNP)));
[/code] Ладно, смотрим где встречается собственно [font=courier new,courier,monospace]$lGp2BqP[/font], а это — последняя строка, вот [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Значит переход на более низкий уровень кода находится на последней строке, это означает, что код обфусцирован [i]последовательно[/i], т.е. весь код (а не его отдельные части) был обфусцирован несколько раз. Это упрощает работу, значит нам тоже разбирать код можно последовательно, не пытаясь найти места, с которых начать. [size=5][b]Этап 2.[/b][/size] Есть такие задачки для маленьких детей, где нарисованы какие-то непрерывные линии, их начала и концы указаны и нужно найти какая линия к чему приведет, причем начал больше чем концов. Легче всего это решить пойдя по этим линиям с конца, вот и мы поступим так же. У нас есть функция, которая ведет к переходу на более низкий уровень кода — эта та самая последняя строчка [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Будем работать над ней. Смотрим на образование названия самой функции: [code]
$oWHh = "\160\162";
$zYdUyk = 'eg';
$XqVM = "\137\162";
$PU0b = "\145\160";
$I0Tf = "\154\141";
$qGX8ht = "\143\145";
$d1QZk = $oWHh . $zYdUyk . $XqVM . $PU0b . $I0Tf . $qGX8ht;[/code] Через секунд 10 раздумий в голову приходит, что 160, 162, 137 и т.д. — это ASCII коды и о них нам рассказывали где-то в школе. Ищем таблицу ASCII кодов, открываем, ищем число 160. Находим, это символ [b][size=4]á[/size][/b]. В PHP нет стандартных функций в названиях которых используются такие символы (а на данном уровне кода у скрипта тоже никаких своих функций нет, помните мы выше это выяснили). Значит 160 нам не подходит, но ведь в коде он используется. Вспоминаем синтаксис PHP, черт, ведь там код символа указывается в восьмеричной системе исчисления. Смотрим тогда колонку [i]Oct[/i] (Octal — восьмеричная система исчисления). Находим, это латинская буква [b]p[/b]. Подходит! Смотрим дальше. 162 — это буква [b]r[/b], получаем, что [code]$oWHh = "\160\162";
$zYdUyk = 'eg';[/code] это ни что иное, как [b]preg[/b], т.е. это библиотека для работы с регулярными выражениями в PHP. Смотрим дальше, когда мы получаем[b] preg_r [/b]становится понятно, что вся функция имеет название [b]preg_replace[/b]. Промежуточный результат: [code]preg_replace($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Ну, совсем просто узнаем, что [font=courier new,courier,monospace]$phl6yJ[/font] это [code]/.*/e[/code] . Промежуточный результат: [code]preg_replace('/.*/e', $r6Q7D($lGp2BqP), $PJf4o9);[/code] Смотрим, что такое [font=courier new,courier,monospace]$r6Q7D[/font]. В коде это [code]
$BiDR51n = "\142\141";
$IhcdiCL = 'se';
$Vq5GI = '64';
$ID4o = "\137\144";
$nBHq = 'ec';
$ekeM_1 = "\157\144";
$NViQXn = "\145";
$r6Q7D = $BiDR51n . $IhcdiCL . $Vq5GI . $ID4o . $nBHq . $ekeM_1 . $NViQXn;
[/code] Увидев [font=courier new,courier,monospace]..se64..ec...[/font] машинально вспоминаем [code]base64_decode[/code] Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), $PJf4o9);[/code] [font=courier new,courier,monospace]$lGp2BqP[/font] — это результат работы какой-то функции, которая обрабатывает результат другой функции, пропустим пока. Остается [font=courier new,courier,monospace]$PJf4o9[/font]. Находим [code]
$uRk52 = "";
$PJf4o9 = $uRk52;
[/code] в самом начале файла. Пустая строка. Отлично. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), '');[/code] Теперь будем разбираться с [font=courier new,courier,monospace]$lGp2BqP[/font]. Путем рассуждений которые мы делали выше узнаем, что [font=courier new,courier,monospace]$lGp2BqP [/font]— это [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split($TjMGm), str_split($VtLjYNP)));[/code] Подставляем переменные и получаем [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')));[/code] А [font=courier new,courier,monospace]$v3IWiBF[/font] — это та огромная строка, про которую мы говорили в самом начале. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode(strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')))), '');[/code] [code]'/.*/e'[/code] в регулярном выражении означает выполнение кода, указанного в строке. Значит нам нужно получить эту строку, это основной код скрипта. Выполняем [font=courier new,courier,monospace]base64_decode[/font] и получаем вот это. [b][size=5]Этап 3[/size][/b] Переходим на еще более низкий уровень кода, опять выполнив [font=courier new,courier,monospace]base64_decode[/font]. Результат. Вот мы и добрались до этой функции [font=courier new,courier,monospace]ololololololo1[/font]. Смотрим и видим это [code]\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28'[/code] Это пошли уже HEX коды символов, расшифровав получаем [code]
eval(gzinflate(base64_decode('/* зашифрованный код */')));
[/code] Переходим еще на уровень ниже... [b][size=5]Этап 4[/size][/b] Вот он код, ребята! После небольшой паузы я начал смеяться, нет, правда Мы получили такой же код, как и в файле [code]public_html/cache/sd2178.php[/code] , отличие только в том, что он выполняется, если у пользователя установлена cookie с названием [b]zx[/b]. Получается, мы просто потратили время впустую? Нет. Во-первых, знаете, это вообще клёвое (я вообще никогда не ставлю букву Ё при набирании текста на клавиатуре, это исторический момент) чувство когда делаешь что-то вроде взлома. Ведь в самом деле, мы только что взломали защиту, которую кто-то делал. Во-вторых, лично я получил прекрасный опыт работы с [b]таким[/b] кодом. Можно считать эта была тренировка на умение ориентироваться и разбираться в защищенном коде. В-третьих, я могу сказать владельцу сайта (как писал я уже выше — это [member='Fensmas']), что ничего супер-страшного в этом коде не нашлось (нет, вообще этот скрипт может многое, вплоть до удаления всех файлов сайта, но мы сделали все вовремя). А вообще у нас есть еще один файл — [font=courier new,courier,monospace]uploads/profile/photo-128.jpg[/font], но разбирать его нет смысла. Вспомним ошибку: [CODE]
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
[/code]
Если кратко — код в этом файле является идентичным коду, который мы только что разбирали.
[size=5][b]Итоги[/b][/size]
Каждый сайт подвержен взлому, различия в том, что кто-то менее, кто-то более, зависит это от версий установленных скриптов.
Я помню у нас тут были люди, которые не хотели обновляться "потому что нет ничего нового". Тем не менее обновляться надо всегда!
Так же нельзя не забывать про патчи безопасности, которые тоже необходимо устанавливать.
Учитывая то, что в общем-то код был один и тот же, можно предположить, что через один бэкдор были закачаны все остальные (а не было взлома еще и механизма кэширования IP.Board).
В любом случае, я считаю, что это время я потратил не зря, хотя бы потому что это было интересно.
Спасибо.
Respected: так же можете почитать эту статью:
[size=5][b]UPDATE 09.11.2012[/b][/size]
Способ взлома сайта найден.
Подробности опубликованы в теме.
-
_Dark_ got a reaction from Wulf in Как я взлом сайта расследовал.Если вы зашли сюда — будьте готовы к огромному количеству букв, различных терминов, непонятного кода и т.п.
Началось все с темы.
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
Как мы видим, ошибка незаурядная. Само наличие "ololololololo1" уже говорит о многом, а учитывая то, что все это происходит в файле av-128.jpg — вообще интересно. В общем то, только по вот этим признакам уже можно говорить о том, что сайт подвергся взлому. Первым делом были взяты эти два файла и пока отложены на просторы рабочего стола. Т.к. обсуждать все это на форуме было неудобно — списались с в ICQ. Для начала хотелось выяснить, кто это сделал. Файл uploads/profile/av-128.jpg является аватаркой пользователя с ID 128 (пока не будем говорить о том, как вообще в аватарке оказался PHP код), казалось бы нарушитель найден, но проблема в том, что владелец сайта чистил БД от старых записей и аккаунт пользователя удален. Ладно, к черту тогда личность взломщика, давайте разбираться, что произошло. Первое что приходит в голову — запросить у хостера список измененных .php файлов за последнюю неделю. Запрашиваем. Хостер предоставить их не может, но зато он нам любезно включает SSH доступ (это действительно хорошая черта тех.поддержки хостинга — они поняли в чем дело и без лишних разговоров предоставляют нам то, что в наш тарифный план не входит). Отлично, SSH у нас есть. При помощи простой команды find /public_html/ -type f -iname "*.php" -mtime -7[/code] (полный путь к директории вырезан за ненадобностью) получаем: [spoiler] [code]
public_html/cache/cache_clean.php
public_html/cache/globalCaches.php
public_html/cache/furlCache.php
public_html/cache/skin_cache/cacheid_1/skin_register.php
public_html/cache/skin_cache/cacheid_1/skin_profile.php
public_html/cache/skin_cache/cacheid_1/skin_online.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_support.php
public_html/cache/skin_cache/cacheid_1/skin_editors.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox.php
public_html/cache/skin_cache/cacheid_1/skin_stats.php
public_html/cache/skin_cache/cacheid_1/skin_upload.php
public_html/cache/skin_cache/cacheid_1/skin_emails.php
public_html/cache/skin_cache/cacheid_1/skin_promenu.php
public_html/cache/skin_cache/cacheid_1/skin_ipseo.php
public_html/cache/skin_cache/cacheid_1/skin_login.php
public_html/cache/skin_cache/cacheid_1/skin_mod.php
public_html/cache/skin_cache/cacheid_1/skin_search.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox_hooks.php
public_html/cache/skin_cache/cacheid_1/skin_boards.php
public_html/cache/skin_cache/cacheid_1/skin_gms.php
public_html/cache/skin_cache/cacheid_1/skin_messaging.php
public_html/cache/skin_cache/cacheid_1/skin_legends.php
public_html/cache/skin_cache/cacheid_1/skin_cp.php
public_html/cache/skin_cache/cacheid_1/skin_post.php
public_html/cache/skin_cache/cacheid_1/skin_mlist.php
public_html/cache/skin_cache/cacheid_1/skin_modcp.php
public_html/cache/skin_cache/cacheid_1/skin_global_other.php
public_html/cache/skin_cache/cacheid_1/skin_reports.php
public_html/cache/skin_cache/cacheid_1/skin_global.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_clients.php
public_html/cache/skin_cache/cacheid_1/skin_topic.php
public_html/cache/skin_cache/cacheid_1/skin_help.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_emails.php
public_html/cache/skin_cache/cacheid_1/skin_ucp.php
public_html/cache/skin_cache/cacheid_1/skin_global_comments.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_payments.php
public_html/cache/skin_cache/cacheid_1/skin_forum.php
public_html/cache/cache.php
public_html/cache/aq.php
public_html/cache/sd2178.php
public_html/hooks/ipSeoPingTopics_9be3a8f6d34784b16a253af2060440da.php
public_html/hooks/ipSeoAcronymsEditor_f29ecb558858bb04bf957fb505093329.php
public_html/hooks/ipSeoMeta_1dfa8b1e2915158bcd0bc2ca20a90f4f.php
public_html/hooks/dp3_fi_boardsClassActionOverloader_5fee7a7dd42c37cd850eba64e519789d.php
public_html/hooks/cstopspamreg_cea6e736e42ab14fa64581f28c8c08d1.php
public_html/hooks/passwordStrength_skin_7b219a756db0cc9bcbf78cb9b17ad92f.php
public_html/hooks/ipSeoGuestSkin_ceb6061092c92fc4b36e682aabaa5c96.php
public_html/hooks/globalProMenuRemovalTool_f73b5f48f7515d65c93216498d309aac.php
public_html/hooks/cstopspamreg_bstats_99fac0fad97daf26fb18c4e61a46ed90.php
public_html/hooks/topicosrecentes_ucp_8eced785d6487592b493fc683e778f68.php
public_html/hooks/dp3_fi_forumsClassActionOverloader_0317c8e4a356386124447e57d90a0188.php
public_html/hooks/globalProMenuJava_1e4b91655304505004f3429052bc0561.php
public_html/hooks/ipSeoAcronymsBbcodeParser_46716b0eace16d346a426516a5a550ca.php
[/code] [/spoiler] В глаза бросается [code]
public_html/cache/aq.php
public_html/cache/sd2178.php
(названия файлов изменены, т.к. пока незачем их публиковать всем).
[/code] (файл [font=courier new,courier,monospace]public_html/cache/cache.php[/font] я заметил только когда писал это, с ним тоже разберемся). Первый файл оказывается скриптом, значение которого я так и не понял. Второй файл имеет интересное содержание. После небольшой пробежки по Google оказываемся здесь. Все понятно, бэкдор из паблика. Удалять эти файлы как-то банально, сделаем по другому — заставим эти файлы работать на нас. Я не буду приводить код, скажу только, что IP-адрес, а так же информация о системе каждого, кто откроет эти файлы будут сохранены. С этим разобрались. Но очевидно, что "центр" взлома находится не здесь, а вон в тех аватарках с PHP кодом. Нам нужно определить, что этот код делает, чтобы установить, для чего был осуществлен взлом. Для начала берем первый файл — [b]av-128.php[/b]. Открываем его. Смотрим. Это кошмар. Во-первых, сразу видно, что код обфусцирован. Во-вторых, начисто нет форматирования кода. Начинаем с малого, приведем код к читаемому виду, в плане переносов строк. Для этого воспользуемся вот этим прекрасным сервисом, который отформатирует код за нас. Прогоняем код. Получаем результат, смотрим. Красота. Код стал более читабелен, мы можем сразу провести небольшой анализ. В коде нет зарезервированных слов PHP (if, function, for, while, и т.д.). Значит код в том виде, в котором он сейчас использует только стандартные функции PHP, не определяя свои. Из первого пункта получаем, что код обфусцирован несколько раз (почему? Потому что свои функции у скрипта все таки есть, помните ошибку, с которой все начиналось?). Скорее всего деобфусцировать код автоматически не выйдет. Поискав в Google сервисы для деобфускации становится понятно, что все что там есть — ерунда. Ну что ж, будем делать все самостоятельно. [size=5][b]Этап 1.[/b][/size] Бегло взглянув на код и обнаружив множество текстовых строк, а затем одну, которая все их объединяет [code]
$v3IWiBF = // и здесь все эти текстовые строки
[/code] приходим к выводу, что на данной стадии в коде минимум логики. Нужно найти переход с этого уровня кода на более низкий. Смотрим где же используется эта переменная [font=courier new,courier,monospace]$v3IWiBF[/font] с огромным текстом внутри. В коде таких упоминаний одно, это [code]
$lGp2BqP = $Mb8Ze($v3IWiBF, $hFl0_($Jj1U($TjMGm), $Jj1U($VtLjYNP)));
[/code] Ладно, смотрим где встречается собственно [font=courier new,courier,monospace]$lGp2BqP[/font], а это — последняя строка, вот [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Значит переход на более низкий уровень кода находится на последней строке, это означает, что код обфусцирован [i]последовательно[/i], т.е. весь код (а не его отдельные части) был обфусцирован несколько раз. Это упрощает работу, значит нам тоже разбирать код можно последовательно, не пытаясь найти места, с которых начать. [size=5][b]Этап 2.[/b][/size] Есть такие задачки для маленьких детей, где нарисованы какие-то непрерывные линии, их начала и концы указаны и нужно найти какая линия к чему приведет, причем начал больше чем концов. Легче всего это решить пойдя по этим линиям с конца, вот и мы поступим так же. У нас есть функция, которая ведет к переходу на более низкий уровень кода — эта та самая последняя строчка [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Будем работать над ней. Смотрим на образование названия самой функции: [code]
$oWHh = "\160\162";
$zYdUyk = 'eg';
$XqVM = "\137\162";
$PU0b = "\145\160";
$I0Tf = "\154\141";
$qGX8ht = "\143\145";
$d1QZk = $oWHh . $zYdUyk . $XqVM . $PU0b . $I0Tf . $qGX8ht;[/code] Через секунд 10 раздумий в голову приходит, что 160, 162, 137 и т.д. — это ASCII коды и о них нам рассказывали где-то в школе. Ищем таблицу ASCII кодов, открываем, ищем число 160. Находим, это символ [b][size=4]á[/size][/b]. В PHP нет стандартных функций в названиях которых используются такие символы (а на данном уровне кода у скрипта тоже никаких своих функций нет, помните мы выше это выяснили). Значит 160 нам не подходит, но ведь в коде он используется. Вспоминаем синтаксис PHP, черт, ведь там код символа указывается в восьмеричной системе исчисления. Смотрим тогда колонку [i]Oct[/i] (Octal — восьмеричная система исчисления). Находим, это латинская буква [b]p[/b]. Подходит! Смотрим дальше. 162 — это буква [b]r[/b], получаем, что [code]$oWHh = "\160\162";
$zYdUyk = 'eg';[/code] это ни что иное, как [b]preg[/b], т.е. это библиотека для работы с регулярными выражениями в PHP. Смотрим дальше, когда мы получаем[b] preg_r [/b]становится понятно, что вся функция имеет название [b]preg_replace[/b]. Промежуточный результат: [code]preg_replace($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Ну, совсем просто узнаем, что [font=courier new,courier,monospace]$phl6yJ[/font] это [code]/.*/e[/code] . Промежуточный результат: [code]preg_replace('/.*/e', $r6Q7D($lGp2BqP), $PJf4o9);[/code] Смотрим, что такое [font=courier new,courier,monospace]$r6Q7D[/font]. В коде это [code]
$BiDR51n = "\142\141";
$IhcdiCL = 'se';
$Vq5GI = '64';
$ID4o = "\137\144";
$nBHq = 'ec';
$ekeM_1 = "\157\144";
$NViQXn = "\145";
$r6Q7D = $BiDR51n . $IhcdiCL . $Vq5GI . $ID4o . $nBHq . $ekeM_1 . $NViQXn;
[/code] Увидев [font=courier new,courier,monospace]..se64..ec...[/font] машинально вспоминаем [code]base64_decode[/code] Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), $PJf4o9);[/code] [font=courier new,courier,monospace]$lGp2BqP[/font] — это результат работы какой-то функции, которая обрабатывает результат другой функции, пропустим пока. Остается [font=courier new,courier,monospace]$PJf4o9[/font]. Находим [code]
$uRk52 = "";
$PJf4o9 = $uRk52;
[/code] в самом начале файла. Пустая строка. Отлично. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), '');[/code] Теперь будем разбираться с [font=courier new,courier,monospace]$lGp2BqP[/font]. Путем рассуждений которые мы делали выше узнаем, что [font=courier new,courier,monospace]$lGp2BqP [/font]— это [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split($TjMGm), str_split($VtLjYNP)));[/code] Подставляем переменные и получаем [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')));[/code] А [font=courier new,courier,monospace]$v3IWiBF[/font] — это та огромная строка, про которую мы говорили в самом начале. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode(strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')))), '');[/code] [code]'/.*/e'[/code] в регулярном выражении означает выполнение кода, указанного в строке. Значит нам нужно получить эту строку, это основной код скрипта. Выполняем [font=courier new,courier,monospace]base64_decode[/font] и получаем вот это. [b][size=5]Этап 3[/size][/b] Переходим на еще более низкий уровень кода, опять выполнив [font=courier new,courier,monospace]base64_decode[/font]. Результат. Вот мы и добрались до этой функции [font=courier new,courier,monospace]ololololololo1[/font]. Смотрим и видим это [code]\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28'[/code] Это пошли уже HEX коды символов, расшифровав получаем [code]
eval(gzinflate(base64_decode('/* зашифрованный код */')));
[/code] Переходим еще на уровень ниже... [b][size=5]Этап 4[/size][/b] Вот он код, ребята! После небольшой паузы я начал смеяться, нет, правда Мы получили такой же код, как и в файле [code]public_html/cache/sd2178.php[/code] , отличие только в том, что он выполняется, если у пользователя установлена cookie с названием [b]zx[/b]. Получается, мы просто потратили время впустую? Нет. Во-первых, знаете, это вообще клёвое (я вообще никогда не ставлю букву Ё при набирании текста на клавиатуре, это исторический момент) чувство когда делаешь что-то вроде взлома. Ведь в самом деле, мы только что взломали защиту, которую кто-то делал. Во-вторых, лично я получил прекрасный опыт работы с [b]таким[/b] кодом. Можно считать эта была тренировка на умение ориентироваться и разбираться в защищенном коде. В-третьих, я могу сказать владельцу сайта (как писал я уже выше — это [member='Fensmas']), что ничего супер-страшного в этом коде не нашлось (нет, вообще этот скрипт может многое, вплоть до удаления всех файлов сайта, но мы сделали все вовремя). А вообще у нас есть еще один файл — [font=courier new,courier,monospace]uploads/profile/photo-128.jpg[/font], но разбирать его нет смысла. Вспомним ошибку: [CODE]
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
[/code]
Если кратко — код в этом файле является идентичным коду, который мы только что разбирали.
[size=5][b]Итоги[/b][/size]
Каждый сайт подвержен взлому, различия в том, что кто-то менее, кто-то более, зависит это от версий установленных скриптов.
Я помню у нас тут были люди, которые не хотели обновляться "потому что нет ничего нового". Тем не менее обновляться надо всегда!
Так же нельзя не забывать про патчи безопасности, которые тоже необходимо устанавливать.
Учитывая то, что в общем-то код был один и тот же, можно предположить, что через один бэкдор были закачаны все остальные (а не было взлома еще и механизма кэширования IP.Board).
В любом случае, я считаю, что это время я потратил не зря, хотя бы потому что это было интересно.
Спасибо.
Respected: так же можете почитать эту статью:
[size=5][b]UPDATE 09.11.2012[/b][/size]
Способ взлома сайта найден.
Подробности опубликованы в теме.
-
_Dark_ got a reaction from ZloyMonah in Как я взлом сайта расследовал.Если вы зашли сюда — будьте готовы к огромному количеству букв, различных терминов, непонятного кода и т.п.
Началось все с темы.
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
Как мы видим, ошибка незаурядная. Само наличие "ololololololo1" уже говорит о многом, а учитывая то, что все это происходит в файле av-128.jpg — вообще интересно. В общем то, только по вот этим признакам уже можно говорить о том, что сайт подвергся взлому. Первым делом были взяты эти два файла и пока отложены на просторы рабочего стола. Т.к. обсуждать все это на форуме было неудобно — списались с в ICQ. Для начала хотелось выяснить, кто это сделал. Файл uploads/profile/av-128.jpg является аватаркой пользователя с ID 128 (пока не будем говорить о том, как вообще в аватарке оказался PHP код), казалось бы нарушитель найден, но проблема в том, что владелец сайта чистил БД от старых записей и аккаунт пользователя удален. Ладно, к черту тогда личность взломщика, давайте разбираться, что произошло. Первое что приходит в голову — запросить у хостера список измененных .php файлов за последнюю неделю. Запрашиваем. Хостер предоставить их не может, но зато он нам любезно включает SSH доступ (это действительно хорошая черта тех.поддержки хостинга — они поняли в чем дело и без лишних разговоров предоставляют нам то, что в наш тарифный план не входит). Отлично, SSH у нас есть. При помощи простой команды find /public_html/ -type f -iname "*.php" -mtime -7[/code] (полный путь к директории вырезан за ненадобностью) получаем: [spoiler] [code]
public_html/cache/cache_clean.php
public_html/cache/globalCaches.php
public_html/cache/furlCache.php
public_html/cache/skin_cache/cacheid_1/skin_register.php
public_html/cache/skin_cache/cacheid_1/skin_profile.php
public_html/cache/skin_cache/cacheid_1/skin_online.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_support.php
public_html/cache/skin_cache/cacheid_1/skin_editors.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox.php
public_html/cache/skin_cache/cacheid_1/skin_stats.php
public_html/cache/skin_cache/cacheid_1/skin_upload.php
public_html/cache/skin_cache/cacheid_1/skin_emails.php
public_html/cache/skin_cache/cacheid_1/skin_promenu.php
public_html/cache/skin_cache/cacheid_1/skin_ipseo.php
public_html/cache/skin_cache/cacheid_1/skin_login.php
public_html/cache/skin_cache/cacheid_1/skin_mod.php
public_html/cache/skin_cache/cacheid_1/skin_search.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox_hooks.php
public_html/cache/skin_cache/cacheid_1/skin_boards.php
public_html/cache/skin_cache/cacheid_1/skin_gms.php
public_html/cache/skin_cache/cacheid_1/skin_messaging.php
public_html/cache/skin_cache/cacheid_1/skin_legends.php
public_html/cache/skin_cache/cacheid_1/skin_cp.php
public_html/cache/skin_cache/cacheid_1/skin_post.php
public_html/cache/skin_cache/cacheid_1/skin_mlist.php
public_html/cache/skin_cache/cacheid_1/skin_modcp.php
public_html/cache/skin_cache/cacheid_1/skin_global_other.php
public_html/cache/skin_cache/cacheid_1/skin_reports.php
public_html/cache/skin_cache/cacheid_1/skin_global.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_clients.php
public_html/cache/skin_cache/cacheid_1/skin_topic.php
public_html/cache/skin_cache/cacheid_1/skin_help.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_emails.php
public_html/cache/skin_cache/cacheid_1/skin_ucp.php
public_html/cache/skin_cache/cacheid_1/skin_global_comments.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_payments.php
public_html/cache/skin_cache/cacheid_1/skin_forum.php
public_html/cache/cache.php
public_html/cache/aq.php
public_html/cache/sd2178.php
public_html/hooks/ipSeoPingTopics_9be3a8f6d34784b16a253af2060440da.php
public_html/hooks/ipSeoAcronymsEditor_f29ecb558858bb04bf957fb505093329.php
public_html/hooks/ipSeoMeta_1dfa8b1e2915158bcd0bc2ca20a90f4f.php
public_html/hooks/dp3_fi_boardsClassActionOverloader_5fee7a7dd42c37cd850eba64e519789d.php
public_html/hooks/cstopspamreg_cea6e736e42ab14fa64581f28c8c08d1.php
public_html/hooks/passwordStrength_skin_7b219a756db0cc9bcbf78cb9b17ad92f.php
public_html/hooks/ipSeoGuestSkin_ceb6061092c92fc4b36e682aabaa5c96.php
public_html/hooks/globalProMenuRemovalTool_f73b5f48f7515d65c93216498d309aac.php
public_html/hooks/cstopspamreg_bstats_99fac0fad97daf26fb18c4e61a46ed90.php
public_html/hooks/topicosrecentes_ucp_8eced785d6487592b493fc683e778f68.php
public_html/hooks/dp3_fi_forumsClassActionOverloader_0317c8e4a356386124447e57d90a0188.php
public_html/hooks/globalProMenuJava_1e4b91655304505004f3429052bc0561.php
public_html/hooks/ipSeoAcronymsBbcodeParser_46716b0eace16d346a426516a5a550ca.php
[/code] [/spoiler] В глаза бросается [code]
public_html/cache/aq.php
public_html/cache/sd2178.php
(названия файлов изменены, т.к. пока незачем их публиковать всем).
[/code] (файл [font=courier new,courier,monospace]public_html/cache/cache.php[/font] я заметил только когда писал это, с ним тоже разберемся). Первый файл оказывается скриптом, значение которого я так и не понял. Второй файл имеет интересное содержание. После небольшой пробежки по Google оказываемся здесь. Все понятно, бэкдор из паблика. Удалять эти файлы как-то банально, сделаем по другому — заставим эти файлы работать на нас. Я не буду приводить код, скажу только, что IP-адрес, а так же информация о системе каждого, кто откроет эти файлы будут сохранены. С этим разобрались. Но очевидно, что "центр" взлома находится не здесь, а вон в тех аватарках с PHP кодом. Нам нужно определить, что этот код делает, чтобы установить, для чего был осуществлен взлом. Для начала берем первый файл — [b]av-128.php[/b]. Открываем его. Смотрим. Это кошмар. Во-первых, сразу видно, что код обфусцирован. Во-вторых, начисто нет форматирования кода. Начинаем с малого, приведем код к читаемому виду, в плане переносов строк. Для этого воспользуемся вот этим прекрасным сервисом, который отформатирует код за нас. Прогоняем код. Получаем результат, смотрим. Красота. Код стал более читабелен, мы можем сразу провести небольшой анализ. В коде нет зарезервированных слов PHP (if, function, for, while, и т.д.). Значит код в том виде, в котором он сейчас использует только стандартные функции PHP, не определяя свои. Из первого пункта получаем, что код обфусцирован несколько раз (почему? Потому что свои функции у скрипта все таки есть, помните ошибку, с которой все начиналось?). Скорее всего деобфусцировать код автоматически не выйдет. Поискав в Google сервисы для деобфускации становится понятно, что все что там есть — ерунда. Ну что ж, будем делать все самостоятельно. [size=5][b]Этап 1.[/b][/size] Бегло взглянув на код и обнаружив множество текстовых строк, а затем одну, которая все их объединяет [code]
$v3IWiBF = // и здесь все эти текстовые строки
[/code] приходим к выводу, что на данной стадии в коде минимум логики. Нужно найти переход с этого уровня кода на более низкий. Смотрим где же используется эта переменная [font=courier new,courier,monospace]$v3IWiBF[/font] с огромным текстом внутри. В коде таких упоминаний одно, это [code]
$lGp2BqP = $Mb8Ze($v3IWiBF, $hFl0_($Jj1U($TjMGm), $Jj1U($VtLjYNP)));
[/code] Ладно, смотрим где встречается собственно [font=courier new,courier,monospace]$lGp2BqP[/font], а это — последняя строка, вот [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Значит переход на более низкий уровень кода находится на последней строке, это означает, что код обфусцирован [i]последовательно[/i], т.е. весь код (а не его отдельные части) был обфусцирован несколько раз. Это упрощает работу, значит нам тоже разбирать код можно последовательно, не пытаясь найти места, с которых начать. [size=5][b]Этап 2.[/b][/size] Есть такие задачки для маленьких детей, где нарисованы какие-то непрерывные линии, их начала и концы указаны и нужно найти какая линия к чему приведет, причем начал больше чем концов. Легче всего это решить пойдя по этим линиям с конца, вот и мы поступим так же. У нас есть функция, которая ведет к переходу на более низкий уровень кода — эта та самая последняя строчка [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Будем работать над ней. Смотрим на образование названия самой функции: [code]
$oWHh = "\160\162";
$zYdUyk = 'eg';
$XqVM = "\137\162";
$PU0b = "\145\160";
$I0Tf = "\154\141";
$qGX8ht = "\143\145";
$d1QZk = $oWHh . $zYdUyk . $XqVM . $PU0b . $I0Tf . $qGX8ht;[/code] Через секунд 10 раздумий в голову приходит, что 160, 162, 137 и т.д. — это ASCII коды и о них нам рассказывали где-то в школе. Ищем таблицу ASCII кодов, открываем, ищем число 160. Находим, это символ [b][size=4]á[/size][/b]. В PHP нет стандартных функций в названиях которых используются такие символы (а на данном уровне кода у скрипта тоже никаких своих функций нет, помните мы выше это выяснили). Значит 160 нам не подходит, но ведь в коде он используется. Вспоминаем синтаксис PHP, черт, ведь там код символа указывается в восьмеричной системе исчисления. Смотрим тогда колонку [i]Oct[/i] (Octal — восьмеричная система исчисления). Находим, это латинская буква [b]p[/b]. Подходит! Смотрим дальше. 162 — это буква [b]r[/b], получаем, что [code]$oWHh = "\160\162";
$zYdUyk = 'eg';[/code] это ни что иное, как [b]preg[/b], т.е. это библиотека для работы с регулярными выражениями в PHP. Смотрим дальше, когда мы получаем[b] preg_r [/b]становится понятно, что вся функция имеет название [b]preg_replace[/b]. Промежуточный результат: [code]preg_replace($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Ну, совсем просто узнаем, что [font=courier new,courier,monospace]$phl6yJ[/font] это [code]/.*/e[/code] . Промежуточный результат: [code]preg_replace('/.*/e', $r6Q7D($lGp2BqP), $PJf4o9);[/code] Смотрим, что такое [font=courier new,courier,monospace]$r6Q7D[/font]. В коде это [code]
$BiDR51n = "\142\141";
$IhcdiCL = 'se';
$Vq5GI = '64';
$ID4o = "\137\144";
$nBHq = 'ec';
$ekeM_1 = "\157\144";
$NViQXn = "\145";
$r6Q7D = $BiDR51n . $IhcdiCL . $Vq5GI . $ID4o . $nBHq . $ekeM_1 . $NViQXn;
[/code] Увидев [font=courier new,courier,monospace]..se64..ec...[/font] машинально вспоминаем [code]base64_decode[/code] Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), $PJf4o9);[/code] [font=courier new,courier,monospace]$lGp2BqP[/font] — это результат работы какой-то функции, которая обрабатывает результат другой функции, пропустим пока. Остается [font=courier new,courier,monospace]$PJf4o9[/font]. Находим [code]
$uRk52 = "";
$PJf4o9 = $uRk52;
[/code] в самом начале файла. Пустая строка. Отлично. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), '');[/code] Теперь будем разбираться с [font=courier new,courier,monospace]$lGp2BqP[/font]. Путем рассуждений которые мы делали выше узнаем, что [font=courier new,courier,monospace]$lGp2BqP [/font]— это [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split($TjMGm), str_split($VtLjYNP)));[/code] Подставляем переменные и получаем [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')));[/code] А [font=courier new,courier,monospace]$v3IWiBF[/font] — это та огромная строка, про которую мы говорили в самом начале. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode(strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')))), '');[/code] [code]'/.*/e'[/code] в регулярном выражении означает выполнение кода, указанного в строке. Значит нам нужно получить эту строку, это основной код скрипта. Выполняем [font=courier new,courier,monospace]base64_decode[/font] и получаем вот это. [b][size=5]Этап 3[/size][/b] Переходим на еще более низкий уровень кода, опять выполнив [font=courier new,courier,monospace]base64_decode[/font]. Результат. Вот мы и добрались до этой функции [font=courier new,courier,monospace]ololololololo1[/font]. Смотрим и видим это [code]\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28'[/code] Это пошли уже HEX коды символов, расшифровав получаем [code]
eval(gzinflate(base64_decode('/* зашифрованный код */')));
[/code] Переходим еще на уровень ниже... [b][size=5]Этап 4[/size][/b] Вот он код, ребята! После небольшой паузы я начал смеяться, нет, правда Мы получили такой же код, как и в файле [code]public_html/cache/sd2178.php[/code] , отличие только в том, что он выполняется, если у пользователя установлена cookie с названием [b]zx[/b]. Получается, мы просто потратили время впустую? Нет. Во-первых, знаете, это вообще клёвое (я вообще никогда не ставлю букву Ё при набирании текста на клавиатуре, это исторический момент) чувство когда делаешь что-то вроде взлома. Ведь в самом деле, мы только что взломали защиту, которую кто-то делал. Во-вторых, лично я получил прекрасный опыт работы с [b]таким[/b] кодом. Можно считать эта была тренировка на умение ориентироваться и разбираться в защищенном коде. В-третьих, я могу сказать владельцу сайта (как писал я уже выше — это [member='Fensmas']), что ничего супер-страшного в этом коде не нашлось (нет, вообще этот скрипт может многое, вплоть до удаления всех файлов сайта, но мы сделали все вовремя). А вообще у нас есть еще один файл — [font=courier new,courier,monospace]uploads/profile/photo-128.jpg[/font], но разбирать его нет смысла. Вспомним ошибку: [CODE]
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
[/code]
Если кратко — код в этом файле является идентичным коду, который мы только что разбирали.
[size=5][b]Итоги[/b][/size]
Каждый сайт подвержен взлому, различия в том, что кто-то менее, кто-то более, зависит это от версий установленных скриптов.
Я помню у нас тут были люди, которые не хотели обновляться "потому что нет ничего нового". Тем не менее обновляться надо всегда!
Так же нельзя не забывать про патчи безопасности, которые тоже необходимо устанавливать.
Учитывая то, что в общем-то код был один и тот же, можно предположить, что через один бэкдор были закачаны все остальные (а не было взлома еще и механизма кэширования IP.Board).
В любом случае, я считаю, что это время я потратил не зря, хотя бы потому что это было интересно.
Спасибо.
Respected: так же можете почитать эту статью:
[size=5][b]UPDATE 09.11.2012[/b][/size]
Способ взлома сайта найден.
Подробности опубликованы в теме.
-
_Dark_ got a reaction from AUYKGN in Как я взлом сайта расследовал.Если вы зашли сюда — будьте готовы к огромному количеству букв, различных терминов, непонятного кода и т.п.
Началось все с темы.
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
Как мы видим, ошибка незаурядная. Само наличие "ololololololo1" уже говорит о многом, а учитывая то, что все это происходит в файле av-128.jpg — вообще интересно. В общем то, только по вот этим признакам уже можно говорить о том, что сайт подвергся взлому. Первым делом были взяты эти два файла и пока отложены на просторы рабочего стола. Т.к. обсуждать все это на форуме было неудобно — списались с в ICQ. Для начала хотелось выяснить, кто это сделал. Файл uploads/profile/av-128.jpg является аватаркой пользователя с ID 128 (пока не будем говорить о том, как вообще в аватарке оказался PHP код), казалось бы нарушитель найден, но проблема в том, что владелец сайта чистил БД от старых записей и аккаунт пользователя удален. Ладно, к черту тогда личность взломщика, давайте разбираться, что произошло. Первое что приходит в голову — запросить у хостера список измененных .php файлов за последнюю неделю. Запрашиваем. Хостер предоставить их не может, но зато он нам любезно включает SSH доступ (это действительно хорошая черта тех.поддержки хостинга — они поняли в чем дело и без лишних разговоров предоставляют нам то, что в наш тарифный план не входит). Отлично, SSH у нас есть. При помощи простой команды find /public_html/ -type f -iname "*.php" -mtime -7[/code] (полный путь к директории вырезан за ненадобностью) получаем: [spoiler] [code]
public_html/cache/cache_clean.php
public_html/cache/globalCaches.php
public_html/cache/furlCache.php
public_html/cache/skin_cache/cacheid_1/skin_register.php
public_html/cache/skin_cache/cacheid_1/skin_profile.php
public_html/cache/skin_cache/cacheid_1/skin_online.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_support.php
public_html/cache/skin_cache/cacheid_1/skin_editors.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox.php
public_html/cache/skin_cache/cacheid_1/skin_stats.php
public_html/cache/skin_cache/cacheid_1/skin_upload.php
public_html/cache/skin_cache/cacheid_1/skin_emails.php
public_html/cache/skin_cache/cacheid_1/skin_promenu.php
public_html/cache/skin_cache/cacheid_1/skin_ipseo.php
public_html/cache/skin_cache/cacheid_1/skin_login.php
public_html/cache/skin_cache/cacheid_1/skin_mod.php
public_html/cache/skin_cache/cacheid_1/skin_search.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox_hooks.php
public_html/cache/skin_cache/cacheid_1/skin_boards.php
public_html/cache/skin_cache/cacheid_1/skin_gms.php
public_html/cache/skin_cache/cacheid_1/skin_messaging.php
public_html/cache/skin_cache/cacheid_1/skin_legends.php
public_html/cache/skin_cache/cacheid_1/skin_cp.php
public_html/cache/skin_cache/cacheid_1/skin_post.php
public_html/cache/skin_cache/cacheid_1/skin_mlist.php
public_html/cache/skin_cache/cacheid_1/skin_modcp.php
public_html/cache/skin_cache/cacheid_1/skin_global_other.php
public_html/cache/skin_cache/cacheid_1/skin_reports.php
public_html/cache/skin_cache/cacheid_1/skin_global.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_clients.php
public_html/cache/skin_cache/cacheid_1/skin_topic.php
public_html/cache/skin_cache/cacheid_1/skin_help.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_emails.php
public_html/cache/skin_cache/cacheid_1/skin_ucp.php
public_html/cache/skin_cache/cacheid_1/skin_global_comments.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_payments.php
public_html/cache/skin_cache/cacheid_1/skin_forum.php
public_html/cache/cache.php
public_html/cache/aq.php
public_html/cache/sd2178.php
public_html/hooks/ipSeoPingTopics_9be3a8f6d34784b16a253af2060440da.php
public_html/hooks/ipSeoAcronymsEditor_f29ecb558858bb04bf957fb505093329.php
public_html/hooks/ipSeoMeta_1dfa8b1e2915158bcd0bc2ca20a90f4f.php
public_html/hooks/dp3_fi_boardsClassActionOverloader_5fee7a7dd42c37cd850eba64e519789d.php
public_html/hooks/cstopspamreg_cea6e736e42ab14fa64581f28c8c08d1.php
public_html/hooks/passwordStrength_skin_7b219a756db0cc9bcbf78cb9b17ad92f.php
public_html/hooks/ipSeoGuestSkin_ceb6061092c92fc4b36e682aabaa5c96.php
public_html/hooks/globalProMenuRemovalTool_f73b5f48f7515d65c93216498d309aac.php
public_html/hooks/cstopspamreg_bstats_99fac0fad97daf26fb18c4e61a46ed90.php
public_html/hooks/topicosrecentes_ucp_8eced785d6487592b493fc683e778f68.php
public_html/hooks/dp3_fi_forumsClassActionOverloader_0317c8e4a356386124447e57d90a0188.php
public_html/hooks/globalProMenuJava_1e4b91655304505004f3429052bc0561.php
public_html/hooks/ipSeoAcronymsBbcodeParser_46716b0eace16d346a426516a5a550ca.php
[/code] [/spoiler] В глаза бросается [code]
public_html/cache/aq.php
public_html/cache/sd2178.php
(названия файлов изменены, т.к. пока незачем их публиковать всем).
[/code] (файл [font=courier new,courier,monospace]public_html/cache/cache.php[/font] я заметил только когда писал это, с ним тоже разберемся). Первый файл оказывается скриптом, значение которого я так и не понял. Второй файл имеет интересное содержание. После небольшой пробежки по Google оказываемся здесь. Все понятно, бэкдор из паблика. Удалять эти файлы как-то банально, сделаем по другому — заставим эти файлы работать на нас. Я не буду приводить код, скажу только, что IP-адрес, а так же информация о системе каждого, кто откроет эти файлы будут сохранены. С этим разобрались. Но очевидно, что "центр" взлома находится не здесь, а вон в тех аватарках с PHP кодом. Нам нужно определить, что этот код делает, чтобы установить, для чего был осуществлен взлом. Для начала берем первый файл — [b]av-128.php[/b]. Открываем его. Смотрим. Это кошмар. Во-первых, сразу видно, что код обфусцирован. Во-вторых, начисто нет форматирования кода. Начинаем с малого, приведем код к читаемому виду, в плане переносов строк. Для этого воспользуемся вот этим прекрасным сервисом, который отформатирует код за нас. Прогоняем код. Получаем результат, смотрим. Красота. Код стал более читабелен, мы можем сразу провести небольшой анализ. В коде нет зарезервированных слов PHP (if, function, for, while, и т.д.). Значит код в том виде, в котором он сейчас использует только стандартные функции PHP, не определяя свои. Из первого пункта получаем, что код обфусцирован несколько раз (почему? Потому что свои функции у скрипта все таки есть, помните ошибку, с которой все начиналось?). Скорее всего деобфусцировать код автоматически не выйдет. Поискав в Google сервисы для деобфускации становится понятно, что все что там есть — ерунда. Ну что ж, будем делать все самостоятельно. [size=5][b]Этап 1.[/b][/size] Бегло взглянув на код и обнаружив множество текстовых строк, а затем одну, которая все их объединяет [code]
$v3IWiBF = // и здесь все эти текстовые строки
[/code] приходим к выводу, что на данной стадии в коде минимум логики. Нужно найти переход с этого уровня кода на более низкий. Смотрим где же используется эта переменная [font=courier new,courier,monospace]$v3IWiBF[/font] с огромным текстом внутри. В коде таких упоминаний одно, это [code]
$lGp2BqP = $Mb8Ze($v3IWiBF, $hFl0_($Jj1U($TjMGm), $Jj1U($VtLjYNP)));
[/code] Ладно, смотрим где встречается собственно [font=courier new,courier,monospace]$lGp2BqP[/font], а это — последняя строка, вот [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Значит переход на более низкий уровень кода находится на последней строке, это означает, что код обфусцирован [i]последовательно[/i], т.е. весь код (а не его отдельные части) был обфусцирован несколько раз. Это упрощает работу, значит нам тоже разбирать код можно последовательно, не пытаясь найти места, с которых начать. [size=5][b]Этап 2.[/b][/size] Есть такие задачки для маленьких детей, где нарисованы какие-то непрерывные линии, их начала и концы указаны и нужно найти какая линия к чему приведет, причем начал больше чем концов. Легче всего это решить пойдя по этим линиям с конца, вот и мы поступим так же. У нас есть функция, которая ведет к переходу на более низкий уровень кода — эта та самая последняя строчка [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Будем работать над ней. Смотрим на образование названия самой функции: [code]
$oWHh = "\160\162";
$zYdUyk = 'eg';
$XqVM = "\137\162";
$PU0b = "\145\160";
$I0Tf = "\154\141";
$qGX8ht = "\143\145";
$d1QZk = $oWHh . $zYdUyk . $XqVM . $PU0b . $I0Tf . $qGX8ht;[/code] Через секунд 10 раздумий в голову приходит, что 160, 162, 137 и т.д. — это ASCII коды и о них нам рассказывали где-то в школе. Ищем таблицу ASCII кодов, открываем, ищем число 160. Находим, это символ [b][size=4]á[/size][/b]. В PHP нет стандартных функций в названиях которых используются такие символы (а на данном уровне кода у скрипта тоже никаких своих функций нет, помните мы выше это выяснили). Значит 160 нам не подходит, но ведь в коде он используется. Вспоминаем синтаксис PHP, черт, ведь там код символа указывается в восьмеричной системе исчисления. Смотрим тогда колонку [i]Oct[/i] (Octal — восьмеричная система исчисления). Находим, это латинская буква [b]p[/b]. Подходит! Смотрим дальше. 162 — это буква [b]r[/b], получаем, что [code]$oWHh = "\160\162";
$zYdUyk = 'eg';[/code] это ни что иное, как [b]preg[/b], т.е. это библиотека для работы с регулярными выражениями в PHP. Смотрим дальше, когда мы получаем[b] preg_r [/b]становится понятно, что вся функция имеет название [b]preg_replace[/b]. Промежуточный результат: [code]preg_replace($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Ну, совсем просто узнаем, что [font=courier new,courier,monospace]$phl6yJ[/font] это [code]/.*/e[/code] . Промежуточный результат: [code]preg_replace('/.*/e', $r6Q7D($lGp2BqP), $PJf4o9);[/code] Смотрим, что такое [font=courier new,courier,monospace]$r6Q7D[/font]. В коде это [code]
$BiDR51n = "\142\141";
$IhcdiCL = 'se';
$Vq5GI = '64';
$ID4o = "\137\144";
$nBHq = 'ec';
$ekeM_1 = "\157\144";
$NViQXn = "\145";
$r6Q7D = $BiDR51n . $IhcdiCL . $Vq5GI . $ID4o . $nBHq . $ekeM_1 . $NViQXn;
[/code] Увидев [font=courier new,courier,monospace]..se64..ec...[/font] машинально вспоминаем [code]base64_decode[/code] Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), $PJf4o9);[/code] [font=courier new,courier,monospace]$lGp2BqP[/font] — это результат работы какой-то функции, которая обрабатывает результат другой функции, пропустим пока. Остается [font=courier new,courier,monospace]$PJf4o9[/font]. Находим [code]
$uRk52 = "";
$PJf4o9 = $uRk52;
[/code] в самом начале файла. Пустая строка. Отлично. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), '');[/code] Теперь будем разбираться с [font=courier new,courier,monospace]$lGp2BqP[/font]. Путем рассуждений которые мы делали выше узнаем, что [font=courier new,courier,monospace]$lGp2BqP [/font]— это [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split($TjMGm), str_split($VtLjYNP)));[/code] Подставляем переменные и получаем [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')));[/code] А [font=courier new,courier,monospace]$v3IWiBF[/font] — это та огромная строка, про которую мы говорили в самом начале. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode(strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')))), '');[/code] [code]'/.*/e'[/code] в регулярном выражении означает выполнение кода, указанного в строке. Значит нам нужно получить эту строку, это основной код скрипта. Выполняем [font=courier new,courier,monospace]base64_decode[/font] и получаем вот это. [b][size=5]Этап 3[/size][/b] Переходим на еще более низкий уровень кода, опять выполнив [font=courier new,courier,monospace]base64_decode[/font]. Результат. Вот мы и добрались до этой функции [font=courier new,courier,monospace]ololololololo1[/font]. Смотрим и видим это [code]\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28'[/code] Это пошли уже HEX коды символов, расшифровав получаем [code]
eval(gzinflate(base64_decode('/* зашифрованный код */')));
[/code] Переходим еще на уровень ниже... [b][size=5]Этап 4[/size][/b] Вот он код, ребята! После небольшой паузы я начал смеяться, нет, правда Мы получили такой же код, как и в файле [code]public_html/cache/sd2178.php[/code] , отличие только в том, что он выполняется, если у пользователя установлена cookie с названием [b]zx[/b]. Получается, мы просто потратили время впустую? Нет. Во-первых, знаете, это вообще клёвое (я вообще никогда не ставлю букву Ё при набирании текста на клавиатуре, это исторический момент) чувство когда делаешь что-то вроде взлома. Ведь в самом деле, мы только что взломали защиту, которую кто-то делал. Во-вторых, лично я получил прекрасный опыт работы с [b]таким[/b] кодом. Можно считать эта была тренировка на умение ориентироваться и разбираться в защищенном коде. В-третьих, я могу сказать владельцу сайта (как писал я уже выше — это [member='Fensmas']), что ничего супер-страшного в этом коде не нашлось (нет, вообще этот скрипт может многое, вплоть до удаления всех файлов сайта, но мы сделали все вовремя). А вообще у нас есть еще один файл — [font=courier new,courier,monospace]uploads/profile/photo-128.jpg[/font], но разбирать его нет смысла. Вспомним ошибку: [CODE]
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
[/code]
Если кратко — код в этом файле является идентичным коду, который мы только что разбирали.
[size=5][b]Итоги[/b][/size]
Каждый сайт подвержен взлому, различия в том, что кто-то менее, кто-то более, зависит это от версий установленных скриптов.
Я помню у нас тут были люди, которые не хотели обновляться "потому что нет ничего нового". Тем не менее обновляться надо всегда!
Так же нельзя не забывать про патчи безопасности, которые тоже необходимо устанавливать.
Учитывая то, что в общем-то код был один и тот же, можно предположить, что через один бэкдор были закачаны все остальные (а не было взлома еще и механизма кэширования IP.Board).
В любом случае, я считаю, что это время я потратил не зря, хотя бы потому что это было интересно.
Спасибо.
Respected: так же можете почитать эту статью:
[size=5][b]UPDATE 09.11.2012[/b][/size]
Способ взлома сайта найден.
Подробности опубликованы в теме.
-
_Dark_ got a reaction from ♥ Соня in Как я взлом сайта расследовал.Если вы зашли сюда — будьте готовы к огромному количеству букв, различных терминов, непонятного кода и т.п.
Началось все с темы.
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
Как мы видим, ошибка незаурядная. Само наличие "ololololololo1" уже говорит о многом, а учитывая то, что все это происходит в файле av-128.jpg — вообще интересно. В общем то, только по вот этим признакам уже можно говорить о том, что сайт подвергся взлому. Первым делом были взяты эти два файла и пока отложены на просторы рабочего стола. Т.к. обсуждать все это на форуме было неудобно — списались с в ICQ. Для начала хотелось выяснить, кто это сделал. Файл uploads/profile/av-128.jpg является аватаркой пользователя с ID 128 (пока не будем говорить о том, как вообще в аватарке оказался PHP код), казалось бы нарушитель найден, но проблема в том, что владелец сайта чистил БД от старых записей и аккаунт пользователя удален. Ладно, к черту тогда личность взломщика, давайте разбираться, что произошло. Первое что приходит в голову — запросить у хостера список измененных .php файлов за последнюю неделю. Запрашиваем. Хостер предоставить их не может, но зато он нам любезно включает SSH доступ (это действительно хорошая черта тех.поддержки хостинга — они поняли в чем дело и без лишних разговоров предоставляют нам то, что в наш тарифный план не входит). Отлично, SSH у нас есть. При помощи простой команды find /public_html/ -type f -iname "*.php" -mtime -7[/code] (полный путь к директории вырезан за ненадобностью) получаем: [spoiler] [code]
public_html/cache/cache_clean.php
public_html/cache/globalCaches.php
public_html/cache/furlCache.php
public_html/cache/skin_cache/cacheid_1/skin_register.php
public_html/cache/skin_cache/cacheid_1/skin_profile.php
public_html/cache/skin_cache/cacheid_1/skin_online.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_support.php
public_html/cache/skin_cache/cacheid_1/skin_editors.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox.php
public_html/cache/skin_cache/cacheid_1/skin_stats.php
public_html/cache/skin_cache/cacheid_1/skin_upload.php
public_html/cache/skin_cache/cacheid_1/skin_emails.php
public_html/cache/skin_cache/cacheid_1/skin_promenu.php
public_html/cache/skin_cache/cacheid_1/skin_ipseo.php
public_html/cache/skin_cache/cacheid_1/skin_login.php
public_html/cache/skin_cache/cacheid_1/skin_mod.php
public_html/cache/skin_cache/cacheid_1/skin_search.php
public_html/cache/skin_cache/cacheid_1/skin_shoutbox_hooks.php
public_html/cache/skin_cache/cacheid_1/skin_boards.php
public_html/cache/skin_cache/cacheid_1/skin_gms.php
public_html/cache/skin_cache/cacheid_1/skin_messaging.php
public_html/cache/skin_cache/cacheid_1/skin_legends.php
public_html/cache/skin_cache/cacheid_1/skin_cp.php
public_html/cache/skin_cache/cacheid_1/skin_post.php
public_html/cache/skin_cache/cacheid_1/skin_mlist.php
public_html/cache/skin_cache/cacheid_1/skin_modcp.php
public_html/cache/skin_cache/cacheid_1/skin_global_other.php
public_html/cache/skin_cache/cacheid_1/skin_reports.php
public_html/cache/skin_cache/cacheid_1/skin_global.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_clients.php
public_html/cache/skin_cache/cacheid_1/skin_topic.php
public_html/cache/skin_cache/cacheid_1/skin_help.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_emails.php
public_html/cache/skin_cache/cacheid_1/skin_ucp.php
public_html/cache/skin_cache/cacheid_1/skin_global_comments.php
public_html/cache/skin_cache/cacheid_1/skin_nexus_payments.php
public_html/cache/skin_cache/cacheid_1/skin_forum.php
public_html/cache/cache.php
public_html/cache/aq.php
public_html/cache/sd2178.php
public_html/hooks/ipSeoPingTopics_9be3a8f6d34784b16a253af2060440da.php
public_html/hooks/ipSeoAcronymsEditor_f29ecb558858bb04bf957fb505093329.php
public_html/hooks/ipSeoMeta_1dfa8b1e2915158bcd0bc2ca20a90f4f.php
public_html/hooks/dp3_fi_boardsClassActionOverloader_5fee7a7dd42c37cd850eba64e519789d.php
public_html/hooks/cstopspamreg_cea6e736e42ab14fa64581f28c8c08d1.php
public_html/hooks/passwordStrength_skin_7b219a756db0cc9bcbf78cb9b17ad92f.php
public_html/hooks/ipSeoGuestSkin_ceb6061092c92fc4b36e682aabaa5c96.php
public_html/hooks/globalProMenuRemovalTool_f73b5f48f7515d65c93216498d309aac.php
public_html/hooks/cstopspamreg_bstats_99fac0fad97daf26fb18c4e61a46ed90.php
public_html/hooks/topicosrecentes_ucp_8eced785d6487592b493fc683e778f68.php
public_html/hooks/dp3_fi_forumsClassActionOverloader_0317c8e4a356386124447e57d90a0188.php
public_html/hooks/globalProMenuJava_1e4b91655304505004f3429052bc0561.php
public_html/hooks/ipSeoAcronymsBbcodeParser_46716b0eace16d346a426516a5a550ca.php
[/code] [/spoiler] В глаза бросается [code]
public_html/cache/aq.php
public_html/cache/sd2178.php
(названия файлов изменены, т.к. пока незачем их публиковать всем).
[/code] (файл [font=courier new,courier,monospace]public_html/cache/cache.php[/font] я заметил только когда писал это, с ним тоже разберемся). Первый файл оказывается скриптом, значение которого я так и не понял. Второй файл имеет интересное содержание. После небольшой пробежки по Google оказываемся здесь. Все понятно, бэкдор из паблика. Удалять эти файлы как-то банально, сделаем по другому — заставим эти файлы работать на нас. Я не буду приводить код, скажу только, что IP-адрес, а так же информация о системе каждого, кто откроет эти файлы будут сохранены. С этим разобрались. Но очевидно, что "центр" взлома находится не здесь, а вон в тех аватарках с PHP кодом. Нам нужно определить, что этот код делает, чтобы установить, для чего был осуществлен взлом. Для начала берем первый файл — [b]av-128.php[/b]. Открываем его. Смотрим. Это кошмар. Во-первых, сразу видно, что код обфусцирован. Во-вторых, начисто нет форматирования кода. Начинаем с малого, приведем код к читаемому виду, в плане переносов строк. Для этого воспользуемся вот этим прекрасным сервисом, который отформатирует код за нас. Прогоняем код. Получаем результат, смотрим. Красота. Код стал более читабелен, мы можем сразу провести небольшой анализ. В коде нет зарезервированных слов PHP (if, function, for, while, и т.д.). Значит код в том виде, в котором он сейчас использует только стандартные функции PHP, не определяя свои. Из первого пункта получаем, что код обфусцирован несколько раз (почему? Потому что свои функции у скрипта все таки есть, помните ошибку, с которой все начиналось?). Скорее всего деобфусцировать код автоматически не выйдет. Поискав в Google сервисы для деобфускации становится понятно, что все что там есть — ерунда. Ну что ж, будем делать все самостоятельно. [size=5][b]Этап 1.[/b][/size] Бегло взглянув на код и обнаружив множество текстовых строк, а затем одну, которая все их объединяет [code]
$v3IWiBF = // и здесь все эти текстовые строки
[/code] приходим к выводу, что на данной стадии в коде минимум логики. Нужно найти переход с этого уровня кода на более низкий. Смотрим где же используется эта переменная [font=courier new,courier,monospace]$v3IWiBF[/font] с огромным текстом внутри. В коде таких упоминаний одно, это [code]
$lGp2BqP = $Mb8Ze($v3IWiBF, $hFl0_($Jj1U($TjMGm), $Jj1U($VtLjYNP)));
[/code] Ладно, смотрим где встречается собственно [font=courier new,courier,monospace]$lGp2BqP[/font], а это — последняя строка, вот [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Значит переход на более низкий уровень кода находится на последней строке, это означает, что код обфусцирован [i]последовательно[/i], т.е. весь код (а не его отдельные части) был обфусцирован несколько раз. Это упрощает работу, значит нам тоже разбирать код можно последовательно, не пытаясь найти места, с которых начать. [size=5][b]Этап 2.[/b][/size] Есть такие задачки для маленьких детей, где нарисованы какие-то непрерывные линии, их начала и концы указаны и нужно найти какая линия к чему приведет, причем начал больше чем концов. Легче всего это решить пойдя по этим линиям с конца, вот и мы поступим так же. У нас есть функция, которая ведет к переходу на более низкий уровень кода — эта та самая последняя строчка [code]$d1QZk($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Будем работать над ней. Смотрим на образование названия самой функции: [code]
$oWHh = "\160\162";
$zYdUyk = 'eg';
$XqVM = "\137\162";
$PU0b = "\145\160";
$I0Tf = "\154\141";
$qGX8ht = "\143\145";
$d1QZk = $oWHh . $zYdUyk . $XqVM . $PU0b . $I0Tf . $qGX8ht;[/code] Через секунд 10 раздумий в голову приходит, что 160, 162, 137 и т.д. — это ASCII коды и о них нам рассказывали где-то в школе. Ищем таблицу ASCII кодов, открываем, ищем число 160. Находим, это символ [b][size=4]á[/size][/b]. В PHP нет стандартных функций в названиях которых используются такие символы (а на данном уровне кода у скрипта тоже никаких своих функций нет, помните мы выше это выяснили). Значит 160 нам не подходит, но ведь в коде он используется. Вспоминаем синтаксис PHP, черт, ведь там код символа указывается в восьмеричной системе исчисления. Смотрим тогда колонку [i]Oct[/i] (Octal — восьмеричная система исчисления). Находим, это латинская буква [b]p[/b]. Подходит! Смотрим дальше. 162 — это буква [b]r[/b], получаем, что [code]$oWHh = "\160\162";
$zYdUyk = 'eg';[/code] это ни что иное, как [b]preg[/b], т.е. это библиотека для работы с регулярными выражениями в PHP. Смотрим дальше, когда мы получаем[b] preg_r [/b]становится понятно, что вся функция имеет название [b]preg_replace[/b]. Промежуточный результат: [code]preg_replace($phl6yJ, $r6Q7D($lGp2BqP), $PJf4o9);[/code] Ну, совсем просто узнаем, что [font=courier new,courier,monospace]$phl6yJ[/font] это [code]/.*/e[/code] . Промежуточный результат: [code]preg_replace('/.*/e', $r6Q7D($lGp2BqP), $PJf4o9);[/code] Смотрим, что такое [font=courier new,courier,monospace]$r6Q7D[/font]. В коде это [code]
$BiDR51n = "\142\141";
$IhcdiCL = 'se';
$Vq5GI = '64';
$ID4o = "\137\144";
$nBHq = 'ec';
$ekeM_1 = "\157\144";
$NViQXn = "\145";
$r6Q7D = $BiDR51n . $IhcdiCL . $Vq5GI . $ID4o . $nBHq . $ekeM_1 . $NViQXn;
[/code] Увидев [font=courier new,courier,monospace]..se64..ec...[/font] машинально вспоминаем [code]base64_decode[/code] Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), $PJf4o9);[/code] [font=courier new,courier,monospace]$lGp2BqP[/font] — это результат работы какой-то функции, которая обрабатывает результат другой функции, пропустим пока. Остается [font=courier new,courier,monospace]$PJf4o9[/font]. Находим [code]
$uRk52 = "";
$PJf4o9 = $uRk52;
[/code] в самом начале файла. Пустая строка. Отлично. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode($lGp2BqP), '');[/code] Теперь будем разбираться с [font=courier new,courier,monospace]$lGp2BqP[/font]. Путем рассуждений которые мы делали выше узнаем, что [font=courier new,courier,monospace]$lGp2BqP [/font]— это [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split($TjMGm), str_split($VtLjYNP)));[/code] Подставляем переменные и получаем [code]$lGp2BqP = strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')));[/code] А [font=courier new,courier,monospace]$v3IWiBF[/font] — это та огромная строка, про которую мы говорили в самом начале. Промежуточный результат: [code]preg_replace('/.*/e', base64_decode(strtr($v3IWiBF, array_combine(str_split('0=7ApLG%5HY#VS-$u_xsE 9,ZtD!crgq2b^/:6o3v1(&ln~k)\'B*IdQ[f4a`W\\'), str_split('8yaoY9jrcKuARDHlPC3S65nBwemEiN=Q1Vhf2stLZqJGUdIWbpM0zx4XvTFkgO')))), '');[/code] [code]'/.*/e'[/code] в регулярном выражении означает выполнение кода, указанного в строке. Значит нам нужно получить эту строку, это основной код скрипта. Выполняем [font=courier new,courier,monospace]base64_decode[/font] и получаем вот это. [b][size=5]Этап 3[/size][/b] Переходим на еще более низкий уровень кода, опять выполнив [font=courier new,courier,monospace]base64_decode[/font]. Результат. Вот мы и добрались до этой функции [font=courier new,courier,monospace]ololololololo1[/font]. Смотрим и видим это [code]\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28'[/code] Это пошли уже HEX коды символов, расшифровав получаем [code]
eval(gzinflate(base64_decode('/* зашифрованный код */')));
[/code] Переходим еще на уровень ниже... [b][size=5]Этап 4[/size][/b] Вот он код, ребята! После небольшой паузы я начал смеяться, нет, правда Мы получили такой же код, как и в файле [code]public_html/cache/sd2178.php[/code] , отличие только в том, что он выполняется, если у пользователя установлена cookie с названием [b]zx[/b]. Получается, мы просто потратили время впустую? Нет. Во-первых, знаете, это вообще клёвое (я вообще никогда не ставлю букву Ё при набирании текста на клавиатуре, это исторический момент) чувство когда делаешь что-то вроде взлома. Ведь в самом деле, мы только что взломали защиту, которую кто-то делал. Во-вторых, лично я получил прекрасный опыт работы с [b]таким[/b] кодом. Можно считать эта была тренировка на умение ориентироваться и разбираться в защищенном коде. В-третьих, я могу сказать владельцу сайта (как писал я уже выше — это [member='Fensmas']), что ничего супер-страшного в этом коде не нашлось (нет, вообще этот скрипт может многое, вплоть до удаления всех файлов сайта, но мы сделали все вовремя). А вообще у нас есть еще один файл — [font=courier new,courier,monospace]uploads/profile/photo-128.jpg[/font], но разбирать его нет смысла. Вспомним ошибку: [CODE]
Fatal error: Cannot redeclare ololololololo1() (previously declared in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/av-128.jpg(33) : regexp code(1) : eval()'d code:2) in /home/o/ХХХ/pro-ucheba.com/public_html/uploads/profile/photo-128.jpg(33) : regexp code(1) : eval()'d code on line 3
[/code]
Если кратко — код в этом файле является идентичным коду, который мы только что разбирали.
[size=5][b]Итоги[/b][/size]
Каждый сайт подвержен взлому, различия в том, что кто-то менее, кто-то более, зависит это от версий установленных скриптов.
Я помню у нас тут были люди, которые не хотели обновляться "потому что нет ничего нового". Тем не менее обновляться надо всегда!
Так же нельзя не забывать про патчи безопасности, которые тоже необходимо устанавливать.
Учитывая то, что в общем-то код был один и тот же, можно предположить, что через один бэкдор были закачаны все остальные (а не было взлома еще и механизма кэширования IP.Board).
В любом случае, я считаю, что это время я потратил не зря, хотя бы потому что это было интересно.
Спасибо.
Respected: так же можете почитать эту статью:
[size=5][b]UPDATE 09.11.2012[/b][/size]
Способ взлома сайта найден.
Подробности опубликованы в теме.
-
_Dark_ got a reaction from alcone in IP.Board 3.3.x, 3.2.x, and 3.1.x Critical Security Update (6 November 2012)Добавил обновление для IP.Board 3.2.
Обновил наши релизы IP.Board 3.2.3 и 3.3.4.
-
_Dark_ got a reaction from CNoise in Ошибка Fatal error: Cannot redeclareУ вас какая версия форума?
Здесь речь идет о возможной уязвимости IP.Board, нельзя это здесь публично обсуждать.
Отправьте мне ваш номерок ICQ.
-
_Dark_ got a reaction from Quicksdk in Ошибка Fatal error: Cannot redeclareЯ так и думал.
Это PHP, а не изображения.
Прекрасно открываются текстовым редактором.
Да, вас взломали.