Шаловливый vbulletin. Наблюдения за vBulletin или попытки кэширования динамического контента
Основные преимущества:
- Быстрая и эффективная основа на базе данных
- Интерфейс, состоящий из шаблонов
- Мощная поисковая система
- Многоязыковая поддержка
- Профили пользователей
- Мощная и удобная панель администратора
- Неограниченное количество разделов/тем/сообщений
- Уведомления по email
- Поддержка COPPA
Ввиду того что демки форума, которую можно инсталлировать, фирма-производитель не предоставляет, пришлось устанавливать левую версию, скачанную с какого-то варезника. Так что инструкция может не совсем соответствовать процессу установки лицензионного форума. После инсталляции, сайт был удалён, по назначению не использовался.
Для инсталляции vBulletin, переходим в панель управления хостингом (кнопка с шестерёнкой напротив заказа хостинга в биллинге), там в "Менеджер файлов", в нём переходим в директорию "www". Нажимаем кнопку "Закачать файл в текущую директорию":
Указываем путь к файлу на своём компьютере:
Выделяем архив с vBulletin, распаковываем его:
Удаляем ненужные нам файлы и директории, в том числе директорию нашего www домена - при условии что там у вас ничего нужного нет. Если вы ставите не в корень сайта, или в директории сайта есть что-то нужное - удалять директорию www домена не надо:
Выделяем директорию с инсталлятором vBulletin, переименовываем её:
Вводим имя нашего сайта, в качестве имени директории:
Переходим в раздел "Базы данных", панели управления хостингом:
Создаём новую базу данных MySQL, и пользователя, с полными правами доступа к ней:
Обратите внимание, что и пользователь и база автоматически получили преффикс, по имени вашего аккаунта на хостинг-сервере:
Заходим на главную страницу нашего сайта, получаем такую ошибку vBulletin:
Вбиваем путь к инсталлятору в адресной строке, надо дописать "install/install.php", после чего запускется программа установки форума vBulletin:
Установщик vBulletin проверяет наличие файлов:
На следующем шаге присходит проверка соединения с базой данных, она не проходит - т.к. в файле конфигурации форума вбиты неверные данные:
Возвращаемся в панель управления хостингом, файловый менеджер, заходим в директорию с форумом, дальше субдиректория "includes". Открываем файл "config.php":
Вносим верные данные от БД в конфигурационный файл, после чего его закрываем:
Возвращаемся на сайт, к инсталлятору. нажимаем "F5", на этот раз всё хорошо, соединение с базой срослось:
Программа установки vBulletin создаёт таблицы в базе данных:
Инсталлятор vBulletin меняет типы некоторых таблиц:
Вносятся данные в базу данных:
Имортируются языки:
Импортируются стили:
Импортируется справка:
Настройки по умолчанию не трогаем, программа установки vBulletin всё верно определила:
Импортируются настройки по умолчанию:
Вводим данные администратора vBulletin:
Администратор vBulletin успешно добавлен:
Установка vBulletin на хостинг успешно завершена:
Следуя последнему совету инсталлятора, удаляем ненужные файлы:
Можно зайти на форум vBulletin, убедиться что всё работает корректно:
Ты наверняка неоднократно видел форумы на движке vBulletin. Форумы как таковые уже не на пике моды, но vBulletin по-прежнему один из самых популярных движков. В его последней (пятой) версии нашли несколько уязвимостей, которые способны сильно испортить жизнь админу. В этой статье я расскажу, как они эксплуатируются.
Первая проблема заключается в некорректной фильтрации пользовательских данных. О ней сообщил независимый исследователь безопасности, который пожелал остаться анонимным. Уязвимость, хоть и имеет некоторые ограничения, получила статус критической, потому что позволяет читать любые файлы и выполнять произвольный код на целевой системе.
Вторая уязвимость была найдена исследователями из компании TRUEL IT и получила идентификатор CVE-2017-17672. Она связана с особенностями десериализации данных в движке и может быть использована атакующим для удаления произвольных файлов в системе.
Полные отчеты с деталями обеих проблем были опубликованы в рамках программы Beyond Security от SecuriTeam. Там же есть PoC-эксплоиты для демонстрации уязвимостей. Давай по порядку пройдемся по всему этому.
Приготовления
В качестве сервера я использовал дистрибутив WAMP.
Читаем файлы, выполняем команды
Итак, причина первой уязвимости - некорректная логика при обработке параметра routestring, которая позволяет атакующему добавить через include любой файл на диске и выполнить PHP-код, который в нем находится.
Наш путь начинается с самого главного файла - index.php, где происходит базовая инициализация приложения.
/index.php
48: $app = vB5_Frontend_Application::init("config.php"); ... 60: $routing = $app->getRouter(); 61: $method = $routing->getAction(); 62: $template = $routing->getTemplate(); 63: $class = $routing->getControllerClass();Посмотрим на метод vB5_Frontend_Application::init .
/includes/vb5/frontend/application.php
13: class vB5_Frontend_Application extends vB5_ApplicationAbstract 14: { 15: public static function init($configFile) 16: { 17: parent::init($configFile); 18: 19: self::$instance = new vB5_Frontend_Application(); 20: self::$instance->router = new vB5_Frontend_Routing(); 21: self::$instance->router->setRoutes();Здесь нас интересует метод setRoutes .
47: public function setRoutes() 48: { 49: $this->processQueryString(); ... 54: if (isset($_GET["routestring"])) 55: { 56: $path = $_GET["routestring"];В переменную $path попадает значение юзердаты из параметра routestring . В него можно передать путь до страницы форума, и она будет загружена.
Допустим, мы передали /test .
После назначения переменной следует кусок кода, который избавляется от слеша в начале строки, если он присутствует.
/includes/vb5/frontend/routing.php
75: if (strlen($path) AND $path{0} == "/") 76: { 77: $path = substr($path, 1); // $path = "test" 78: }includes\vb5\frontend\routing.php
83: if (strlen($path) > 2) 84: { 85: $ext = strtolower(substr($path, -4)) ; 86: if (($ext == ".gif") OR ($ext == ".png") OR ($ext == ".jpg") OR ($ext == ".css") 87: OR (strtolower(substr($path, -3)) == ".js")) 88: { 89: header("HTTP/1.0 404 Not Found"); 90: die(""); 91: } 92: }Как видишь, проверка довольно странная. Как минимум смущает наличие зашитого прямо в код списка запрещенных расширений. Да и вообще сам факт, что расширение получают, вырезая четыре символа с конца строки (строка 85), вызывает недоумение. В общем, если мы пытаемся получить файл с расширениями gif, png, jsp, css или js, то сервер вернет страницу 404 и выполнение скрипта прекратится. Когда все проверки пройдены, с помощью callApi вызывается метод getRoute из класса vB_Api_Route . Он ищет подходящие роуты, исходя из переданной пользователем информации.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «сайт», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score!
Давно хотел написать об этом, да все руки не доходили, а тут как раз выдалась минутка опубликовать небольшую заметку по теме. Так почему же не опубликовать список того, на что пользователь смотреть в первую очередь перед выбором хостинга. Особенно для нас, тех кто пользуется vbulletin. Назовем это все просто - рекомендации. Понятное дело, что профессионалам и так все понятно, тут как бы объяснять нечего. А вот новичкам стоит все таки растасовать. Так как вижу нездоровую тенденцию, админ Vbulletin 4, хочет чтобы его форум работал на шаред хостинге за 5$ и все летало. такого не когда не будет!
Все мы знаем основы, но когда я искал свой хост когда-то я тоже совершал некоторые ошибки, вот и разберем некоторые.
Является ли компания оверселлером?
Господа, я вас умоляю, не пользуйтесь хостингом который перепродают (оверселлер). Скорее всего вам выделят кусок большого «гумна» с которым вы намучаетесь на долго. Но как нам определить, что хостинг перепродается через 50 руки? Тут секретов нет, вам предложат 500 или 1500ГБ места (тут я утрирую конечно но ненамного) и пропускную способность 100 ТБ и всего то за 5 баксов. Не слишком ли хорошо? Но это все бред сивой кобылы, на самом деле вам не нужно больше 2-10 ГБ дискового пространства, уж поверьте. А пропускной способности 50- 200 гб вам за уши, тем более на первых парах.
Является ли компания реселлером?
Тут тоже надо быть очень внимательным. Большинство реселлеров являются фирмами однодневками. Они берут деньги, поработают немного и все, вы их больше не увидите. Все ваши файлы и наработки пропадут! Но нам же это не надо, не правда ли? И даже если вам понравились цена на хостинг данных фирм, обязательно проверьте, как долго та или иная компания в бизнесе.
Предельный размер базы данных!
Это очень важный пункт, если вы планируете перенести ваш работоспособный vbulletin. Я осмотрелся в предложениях различных хостеров большинство предлагают 100мб. На первое время этого конечно вам будет достаточно, но как только ваш форум будет расти, вам этого будет мало и вы вынуждены будете перейти на VPS или выделенный сервер.
Количество одновременных подключений к базе данных.
О, да это 100% важная вещь. Это очень важно, тем более если вы работаете с Vbulletin. Так как со временем одновременное подключение только растет. Большинство компаний шаред хостинга предлагает 10-250, все зависит от хостинга. Просто позвоните в тех поддержку и спросите у них об этом. Но, не все шаред хостинги имеют эту информацию, или поделятся с вами.
Отзывы! Хорошо это или плохо?
Тех поддержка.
На большинстве хостингах есть круглосуточная тех поддержка, которая работает 24/7, через электронную почту, тикеты, icq, skype или еще каким либо способом. Но как долго они будут вам помогать? Иногда это играет решающую роль.
Вызовите тех поддержку и посмотрите как долго вы будете ждать ответа, особенно ночью или в 5-6 утра. И проверьте несколько вариантов и телефон и тикеты. Задайте простые вопросы на которые вы и так знаете ответы, нам нужно вычислить время их ответа. Получили! Отлично, посмотрите сколько вы ждали ответа на легкий вопрос, и прикиньте сколько вам будут отвечать на сложную ситуацию.
Большая известная компания или новая неизвестная?
В принципе тут выбор стоит только перед вами, чем старше компания и солиднее, цены у не будут немного выше, чем у только что созданных. Лично я выбираю компанию которая себя уже как-то зарекомендовала. Хотите знать почему? Все просто, представьте только себе, что вы в одночасье можете потерять множество полезных файлов и базу данных. То же самое про политику конфиденциальности, не всегда можно быть уверенным, что она соблюдается. Ваши данные могут быть скопированы и созданны сайты клоны. Этот список можно продолжать и продолжать. Ну вы меня поняли 🙂
Есть в моем ведении несколько VPSов, на которых крутится… вообщем не моя зона ответственности, и потому крутится там то что крутится, в меру тормозит, в меру работает. И оказалось, что крутится на одном из них некий форум, и начал форум притормаживать. И захотелось разобраться…
Исхдные
- Форум под vBulletin 3.8.x
- Вынесен на поддомен forum.domain.com
- Nginx 1.1.13, php 5.3.x (fpm)
- Кроме форума на этом сервере ничего не крутится. (это важно ).
- Mysql на отдельном сервере, коммуникация через TCP/IP.
Предыстория
Жил себе форум, не тужил, показывал по xm top нагрузку в районе 30-40 процентов. А затем наступил час «Х» и нагрузка подскочила до ровной полки в 90 процентов с пиками выше, что, вообщем-то, не есть гуд. Подозрение на DDOS не подтвердилось. По логам наблюдалась обычная рабочая нагрузка. Ну а перед тем как тупо наращивать ресурсы возникла идея разобраться в происходящем и попытаться закэшировать все что можно.Расследование. Часть первая - чего хочет женщина посетитель
Так как с идеологией и особенностями данной софтины я знаком не был, то начал изучение проблемы с анализа логов и траффика между посетителями и сервером. Первым делом я с удивлением обнаружил, что аттачи к сообщениям в форуме отдаются исключительно скриптом attachment.php , при этом сами файлы могут храниться в базе, могут на локальном диске, но отдача - только через скрипт. И никак иначе. То есть получаем по 8-10 лишних дерганий php-интерпретатора на ветвь сообщений с 8-10 фотографиями. И это для каждого посетителя. Так как на этом форуме для просмотра аттачей не требуется регистрация, то аттачи можно закэшировать, допустим, на пару дней. Примерно вот так:location = /attachment.php { expires max; limit_req zone=lim_req_1s_zone burst=5; fastcgi_pass forum__php_cluster; include /etc/nginx/fastcgi_params; include /etc/nginx/fastcgi_params_php-fpm; fastcgi_cache forum_att__cache; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; fastcgi_hide_header Set-Cookie; fastcgi_hide_header Pragma; fastcgi_cache_key "$request_method:$http_if_modified_since:$http_if_none_match:$host:$request_uri:"; fastcgi_cache_use_stale updating error timeout invalid_header http_500; fastcgi_cache_lock on; fastcgi_cache_lock_timeout 2m; fastcgi_cache_valid 2d; } и где-ньть в http-секци объявим forum_att__cache: fastcgi_cache_path /var/cache/nginx/att levels=1:2 keys_zone=forum_att__cache:4m max_size=2g inactive=2d;
Вторым «откровением» для меня было то, что на форуме есть архивы, и они не просто существуют, а практически половина запросов приходится именно на них. Внешний вид страниц также позволяет закэшировать их содержимое:
location /archive/ {
expires 10d;
limit_req zone=lim_req_1s_zone burst=2;
location ~ \.css$ {
expires max;
}
fastcgi_pass forum__php_cluster;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
include /etc/nginx/fastcgi_params_php-fpm;
fastcgi_param SCRIPT_FILENAME $document_root/archive/index.php;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_cache forum_arc__cache;
fastcgi_hide_header Set-Cookie;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_cache_key "$request_method:$http_if_modified_since:$http_if_none_match:$host:$request_uri:";
fastcgi_cache_use_stale updating error timeout invalid_header http_500;
fastcgi_cache_valid 2d;
}
и в http-секцию:
fastcgi_cache_path /var/cache/nginx/arc levels=1:2 keys_zone=forum_arc__cache:4m max_size=2g inactive=2d;
Заодно подстрахуемся от DDOS-атак:
limit_req_zone "$psUID" zone=lim_req_1s_zone:2m rate=1r/s;
О формировании ключа "$psUID" я поведаю далее.
Расследование. Часть вторая - авторизация в vBulletin
С точки зрения посетителя форума зашедший может быть либо зарегистрированным пользователем, либо гостем. Но совсем другая ситуация складывается, если мы пронаблюдаем ситуацию «пришел, походил, залогинился, походил, отлогинился, походил» с точки зрения появления и исчезновения кук в браузере. Итак, очищаем куки для домена и его поддоменов, открываем HTTPfox и наблюдаем что происходит:HTTP/1.1 200 OK Set-Cookie: PHPSESSID=cdme9rrptft67tbo97p4t1cua5; expires=Wed, 22-Feb-2012 15:04:12 GMT; path=/; domain=.domain.com Set-Cookie: bblastvisit=1329059052; expires=Mon, 11-Feb-2013 15:04:12 GMT; path=/; domain=.domain.com Set-Cookie: bblastactivity=0; expires=Mon, 11-Feb-2013 15:04:12 GMT; path=/; domain=.domain.com Set-Cookie: uid=XCuiGU831OyC8VLqAx/QAg==; expires=Thu, 31-Dec-37 23:55:55 GMT; domain=.domain.com; path=/
С uid и PHPSESSID все понятно - это происки nginx"a и php-интерпретатора с установленной опцией session.auto_start , а вот остальные - следилки за активностью на форуме. А вот главной сессионной куки vBulletin пока не наблюдается. Забегая вперед скажу, что vBulletin не использует стандартную php-вую сессию (точнее ПОЧТИ не использует), а ведет свою, идентификатор которой хранит в куке bbsessionhash . Итак, пользователь зашел, а сессии нет - то есть он аноним без сессии. При этом ссылки на форум далее могут иметь два вида (имеются ввиду все ссылки на странице, а не одна так, а другая эдак):
forum.domain.com/forumdisplay.php?s=12b66e447be52ebc84ab16d3f39626fb&f=69
forum.domain.com/forumdisplay.php?f=69
И если пройти по ссылке первого типа, то следующим ответом от форума придет кука сессии, а если по ссылке второго - нет. Если со вторым ответом кука от сессии не пришла то по форуму можно так и бродить безсессионным и неприкаянным пока не нарвешься на ссылку первого типа (закономерность их появления у меня выявить не получилось), или захочешь залогиниться. При успешном логине кука сессии придет по-любому. Если до логина гость был анонимом-с-сессией, то сессию ему заменят. Выглядит это так:
HTTP/1.1 200 OK Set-Cookie: bbsessionhash=85745bc6110db5221e159087bf037f24; path=/; domain=.domain.com; HttpOnly
После логина сессия «стабильна» и чехарды с ссылками не происходит. Процедура логаута оригинальностью не отличается - удаляются все существующие форумные куки (даже те, которые не были проставлены) и пишется кука новой («анонимной») сессии:
HTTP/1.1 200 OK Set-Cookie: bbsessionhash=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bblastvisit=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bblastactivity=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbthread_lastview=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbreferrerid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbuserid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbpassword=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbthreadedmode=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbstyleid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bblanguageid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbsessionhash=3d0bdc5dbe8dabae361deebe8f6048d2; path=/; domain=.domain.com; HttpOnly
То есть на выходе мы получаем анонима (гостя), но стопроцентно имеющего сессию.
В итоге с точки зрения форумного софта И HTTP-заголовков мы имеем три типа пользователей: гость без сессии , гость с сессией , залогиненный посетитель . Причем на уровне nginx"a отличать вторых от третьих крайне проблематично.
Теперь, поняв какие куки и как курсируют между посетителем и сервером, можно подойти к вопросу кэширования динамического контента. Как известно, функционал кэширования ответов fastcgi-бэкенда в nginx встроен в модуль ngx_http_fastcgi_module . Для этого надо прописать глобально в http-секции зону кэширования, а в нужном location"e - ключ. И если для условно-статического контента (изображения, архивы) ключем для кэширования мог считаться URI с незначительными дополнениями, то для кэширования динамики нужно учитывать еще и юзера. Казалось-бы правило типа
fastcgi_cache_key "$request_method:$http_if_modified_since:$http_if_none_match:$host:$request_uri:$cookie_bbsessionhash:";
могло бы удовлетворить и гостей и залогиненных пользователей, однако на практике посетители начали получать содержимое чужого кэша. Кэширование «истиной» динамики пришлось отключить. Надеюсь приговор не окончателен.
Однако данная информация не бесполезна. На ее основе мы можем генерить ключ для ограничения частоты запросов основываясь не только на IP адресе посетителя, но и на его статусе.
set $psUID "anon";
set $psUCL "anon";
if ($cookie_bbsessionhash) {
set $psUID "$cookie_bbsessionhash";
set $psUCL "user";
}
if ($psUCL = "anon") {
set $psUID "anon:$remote_addr";
}
Данный фрагмент конфига размещаем в секции server конфига nginx до описания всех location. В итоге мы получаем оригинальный ключ на пользователя имеющего сессию и ключ основанный на IP адресе для посетителей сессии не имеющих (например для поисковый краулеров).