Опять блог задели… Ваш на подходе!

4 комментария

взлом WordPress

Добрый день! Я надолго оставила блог в связи с очередной «большойкучейдел», аж на целый месяц. Были идеи по поводу одной немаленькой статьи, возможно даже небольшого цикла статей, но времени и сил никак не хватало. Так или иначе я поглядывала за тем, жив ли сайт, заходят ли на него, но… к сожалению, я больше ничего с ним не делала, в том числе и не обновляла. А новые версии WordPress все выходили и выходили, в которых закрывались обнаруживаемые уязвимости, чтобы взлом WordPress не был такой уж тривиальной задачей. Все это проходило мимо меня. В общем до середины февраля я просидела с WordPress 4.7.0, с чем меня дружно и поздравим . Если у Вас версия более ранняя, чем 4.7.2, то прочтите обязательно, это Вам непременно поможет!

Зайдя сегодня на главную страницу сайта, я увидела, что название последнего топика изменилось до неузнаваемости: «HaCkEd By GeNErAL». Содержимое статьи было изменено неизвестными людьми и выглядело так:

взлом блога wordpress

Прямоугольник с упоминанием Билайна на скриншоте — это все же реклама от Google, это не происки хакеров  .

Тааак, подумала я, все это напоминает историю почти годичной давности.  Как и тогда, меня вновь спасли бэкапы. Проверьте и Вы, делаются ли они у Вас! Затем были накатаны самые последние обновления WordPress (4.7.2) и плагинов. Как говорится, пока петух не клюнет…

Что же произошло, и почему кто-то вот так просто сумел заменить содержимое страницы поста на что-то свое и нафиХ никому не нужное? Все дело в уязвимости версий WordPress 4.7.0/4.7.1. Полное описание проблемы можно найти на этом сайте, я же попробую дать перевод того, что там написано, с «отсебятиной». Скорее всего именно эта уязвимость и была заюзана на блоге, тем более, что эксплоит, написанный на Python, есть в открытом доступе. Если Вы не обновили WordPress, то, к сожалению, Ваш блог в опасности… 

Во всем оказалось виновато одно нововведение, которое, начиная с версии ворпресса 4.7.0, включено в него по умолчанию — это REST API. Один из эндпоинтов этого API был предназначен для того, чтобы корректировать посты, но в код закралась бага, и это мог сделать кто угодно .

Проблема в двух вещах:

  1. REST API в вордпресс устроено так, что сначала формируется адрес страницы блога по регулярке, а уже потом на него навешиваются GET и POST параметры. Итого, ожидался адрес /wp-json/wp/v2/posts/1234, а получен /wp-json/wp/v2/posts/1234?id=12345helloworld. Хвостовик после после знака вопроса должен проверяться в коде.
  2. Так уж устроена система приведения типов в PHP, что она совсем не похожа на такую же в C#  . Динамическая типизация против статической, Fight!  Строка вида «123abc», переданная в параметре типа int, спокойно может быть приведена в числу 123. Шарповоду в первый раз может стать страшно после такого:
преобразование типов в PHP

То, что здесь перечислено, это реальность, в которой приходится существовать. Поэтому в коде все должно было проверяться. Вот к версии 4.7.2 проверки и подкрутили. Приводимый ниже код располагается по адресу wp-includes\rest-api\endpoints\class-wp-rest-posts-controller.php.

За обновление текста статей на блоге отвечают две функции в REST API вордпресса — это update_item_permissions_check и update_item. Первая проверяет наличие прав у автора на изменение содержимого поста, при помощи второй вносятся сами коррективы.

Вот как выглядела первая половина функции update_item_permissions_check в WordPress 4.7.0/4.7.1:

Как мы видим, никак не обрабатываемый параметр $request[‘id’] передается в функцию get_post(). На выходе у нас либо ошибка преобразования и возврат пустого поста, либо информация о посте. В последующей конструкции IF первым аргументом идет $post, возвращенный функцией get_post(). Если у нас вернулось что-то не то, то… этот IF игнорируется, где как раз и должна была идти проверка на наличие прав на обновление текста, и код выполняется далее! Остальные проверки — не помеха. После того, как мы благополучно слили проверку на права записи, нас ждет функция update_item, часть из которой приведена ниже.

Поведение строки $id = (int)$request[‘id’] объяснено выше, в проблеме №2. Если в $request есть число, то оно и будет результатом, т.е. «123abc» -> 123. Итого, нам надо всего лишь найти пост с ID 123 и записать туда ерунду из запроса.

В версии 4.7.2 постарались исправить эти ошибки. Теперь интересующая нас часть функции update_item_permissions_check выглядит так:

Первое, что бросается в глаза, это использование кастомной функции get_post() взамен встроенной. Вот ее код:

Суть простая — не смогли сделать приведение, или оно оказалось каким-то странным — выдаем ошибку, не нашли пост с полученным после приведения типов ID — выдаем ошибку. Таким образом, в дальнейшем коде функции update_item_permissions_check будет использоваться ID гарантированно найденной статьи на блоге, и уже для нее будут проверяться права на запись.

Функция update_item также претерпела изменения:

Тут все по сути тоже самое, что и в выше описанной функции проверки прав.

Мораль сей басни: если у Вас еще не обновлен Wordress до последней версии — GO обновляться!!! И не забудьте очистить кеш сайта после этого , если Вы его, конечно, используете.


4 комментария “Опять блог задели… Ваш на подходе!”

  1. Pogudo

    Прочитал этот пост, улыбнулся, думаю с моим проектом такого не будет) но всё же обновился. А потом взял и пролистал чутка страничку вниз и увидел hacked by slade :DDD

    Ответить
    • NoService
      NoService

      http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ag.gif
      Нельзя взломать лишь тот блог, который не существует в сети))

      Ответить
  2. Благодарю за подробное объяснение. По поводу всей этой заварухи скажу первое — золотое правило работает не трож — это касательно автоматических обновлений. Второе — админы делятся на тех кто еще не делает бэкапы и на тех кто Уже делает бекапы 😉 Меньше вам дефейсов ✌

    Ответить
    • NoService
      NoService

      Спасибо 🙂
      Я все вручную обновляю, т.к. мала минимум прав на изменение файлов. Это и подвело 🙂 И пусть блог обойдут все невзгоды http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ay.gif

      Ответить

Оставьте комментарий

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url=""> <img src="" alt="" class="" width="" height="">

http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ab.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ac.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ag.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ah.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ai.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ak.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/am.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/an.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ao.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/aq.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ar.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/at.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/av.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/aw.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/ay.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/az.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/bb.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/bc.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/bd.gif 
http://noservice.ru/wp-content/plugins/wp-monalisa/icons/be.gif 
больше...