Добрый день.
Я проверяю безопасность веб-приложений.
Проще говоря, тесты на проникновение для веб-сайтов.
Иногда в моей практике встречаются интересные и познавательные случаи, которые хотелось бы описать в виде подобных статей, но редко (для меня это первый случай) случаются ситуации, когда клиент разрешает публикацию такого материала с подробным описанием.
обо всех возникших проблемах и предпринятых действиях.
Естественно, здесь вы не найдете каких-то конкретных имен, названия компании-заказчика и т. д. Наверное, мне никто и никогда не позволит упомянуть такие данные.
Надеюсь, что вам, дорогие читатели, эта статья будет интересна и полезна.
Предисловие
Исходная ситуация была следующая.Жила и развивалась одна браузерная игра с относительно высоким присутствием в сети.
Проект монетизировался за счет покупки игроками виртуальных предметов за реальные деньги.
В один прекрасный день среди игроков появился хакер, который, обнаружив несколько уязвимостей в игровом движке, начал различными способами нарушать игровой баланс.
Он увеличил количество денег как для себя, так и для других игроков, улучшил игровой процесс для всех и создал редкие игровые предметы.
Естественно, платежи от пользователей практически сразу исчезли.
Зачем платить за что-то, если это раздают бесплатно? Разработчики пытались с этим бороться, даже наняли человека, который за 200 долларов взялся устранить «все уязвимости» в коде, но результата не было.
Их терпение окончательно лопнуло, когда злоумышленник слил дамп базы данных + все исходные коды игры и выложил их на один публичный форум, с предложением использовать игру где угодно совершенно свободно.
И если раньше, в процессе борьбы с хакером, игра хоть как-то развивалась, то сейчас сделать это было просто невозможно — любые улучшения или новые модули могли тут же утечь в сеть.
Первичное обследование
Игра создана на базе VPS под управлением Debian и администрируется хостером.От последнего, помимо самого сервера, также были предусмотрены панель управления и PhpMyAdmin. Конфигурация внутреннего ПО очень способствовала взлому.
Настройка PHP позволяла как открывать, так и включать внешние файлы (allow_url_fopen/include), хотя ни то, ни другое для работы игры не требовалось.
Безопасный режим (safe_mode) отключен, а параметр open_basedir не установлен.
Такие функции, как system(), exec() и другие, обеспечивающие выполнение системных команд, не были отключены с помощью Disable_functions. Вывод ошибок был включен, но о их протоколировании речи не шло.
Что касается веб-сервера (Apache), то он контролировал несколько поддоменов, связанных с игрой - форум, тестовый сайт и т.д. Веб-сервер работал с PHP в режиме FastCGI, но главный козырь в плане безопасности - запуск скриптов с права их владельцев - сводилось на нет простым фактором - владельцем контента всех поддоменов был один и тот же пользователь.
В этот момент стало ясно, что уязвимости не обязательно должны быть в самом игровом движке; они также могут располагаться в периферических доменах.
В MySQL ситуация была аналогичная.
Каждый из поддоменов имел свою базу данных, и скрипты работали с ними через одного пользователя.
Доступ к серверу осуществлялся извне с использованием SSH и FTP. И если о первом я не могу сказать ничего плохого, то с FTP ситуация была совсем иная.
Попав на FTP, пользователь сразу получил доступ к содержимому всех поддоменов.
Кроме того, здесь, в корне FTP, была папка с резервными копиями баз данных.
В них содержалось все, вплоть до паролей пользователей.
Также были архивы с логами FTP. Апогеем всего этого, как многие, наверное, уже догадались, стало то, что логин и пароль были одинаковыми на SSH, FTP и MySQL. После более близкого знакомства всплыл еще один неприятный момент. Движок игры был разработан без использования системы контроля версий.
Все исправлялось «на лету», и если нужно было создать резервную копию файла, он назывался что-то вроде имя_скрипта111111111.php прямо на FTP, после чего скачивался свежий имя_скрипта.
php. Работа над движком шла довольно долго, и таких файлов «отката» были десятки.
Их наличие значительно усложняло поиск веб-шеллов и других бэкдоров, которые мог скачать злоумышленник.
И анализировать исходный код на наличие уязвимостей стало просто невозможно.
В общем, нужно было срочно исправлять ситуацию.
Попытка номер один
Необходимо упомянуть об одном, так сказать, недостатке, который у нас сработал.К тому моменту, когда разработчики обратились ко мне, разработка игры практически остановилась, количество игроков упало, а самому хакеру было скучно в нее играть.
Он приходил раз в день, около часа занимался всякой перепиской и уходил.
Активно вести себя он начал только тогда, когда разработчики начали действовать - внесли какие-то дополнения, заблокировали его аккаунт и т. д. То есть можно с уверенностью сказать, что пока мы не начнем вносить для него заметные изменения в серверное ПО и игры, взломщик сам не начнет двигаться.
Исходя из этого, необходимо было действовать таким образом, чтобы злоумышленник, осознав изменения, касающиеся защиты, уже не мог каким-либо образом на них влиять.
Поэтому, в первую очередь, мы задались целью минимизировать зону его влияния.
Сначала было решено ограничить внешний доступ ко всем жизненно важным сервисам (панель управления VPS, PMA, SSH, FTP, MySQL) по IP-адресам.
Далее в системе для каждого поддомена были созданы пользователи и весь их контент был перенесен в соответствующие домашние каталоги.
То же самое мы сделали с базой данных.
Теперь злоумышленник не мог, имея контроль над одним сайтом, как-то влиять на другие.
Я почти забыл.
Мы удалили разрешения 777 из всех каталогов, в которых они были.
Площадки стали полностью отделены друг от друга.
Затем мы исправили конфигурацию PHP. Запрещены функции запуска команд ОС, а также возможность подключения и чтения файлов по URL. Вывод ошибок был отключен, при этом была включена запись их в файл (error_log).
К сожалению, по причинам, связанным с особенностями движка, не удалось сразу включить безопасный режим (safe_mode) или хотя бы установить open_basedir. Поэтому нам пришлось продолжать работу без их помощи.
Как ни странно, все наши действия никоим образом не привлекли внимание злоумышленника.
Видимо ему окончательно надоело лазить по серверу и он кроме самой игры никуда не заходил.
Это дало еще немного времени.
Как раз в этот момент разработчики удалили все скрипты резервного копирования и можно было приступить к анализу используемых веб-приложений.
Сразу обнаружилась одна очень популярная проблема — содержимое каталогов с библиотеками, конфигурационными файлами и т.п.
было открыто для постороннего доступа.
Конечно, это не критичный недостаток (те же конфигурационные файлы были PHP-скриптами и прямой доступ к ним ничего не дал), но если их содержимое доступно извне, они являются хорошим местом для хранения вредоносного кода.
Когда доступ к таким папкам закрывается, количество мест для поиска «подарков» от злоумышленника резко сокращается.
В случае с игровым движком мы оставили возможность доступа извне в одну директорию со скриптами и в несколько с JS-файлами, стилями и изображениями.
Последний просто запретил выполнение скриптов.
Таким образом, осталась только одна папка, где выполнение PHP-кода могло быть вызвано внешним пользователем.
В принципе, злоумышленник может внести опасные изменения в какой-нибудь внутренний скрипт и попытаться получить доступ к своему коду из публичных скриптов.
Но и эту проблему мы решили, хотя и не сразу (об этом ниже).
Сам исходный код игры был просто пронизан слепыми SQL-инъекциями.
За весь период нашего сотрудничества их было обнаружено несколько десятков.
Нанятый для их устранения человек, о котором я уже упоминал в начале статьи, тривиально назначил использование функции mysql_real_escape_string() каждой включенной в запрос переменной.
Но почему-то он не учел того, что разработчики ожидали наличия в этих переменных числовых значений, поэтому в SQL-запросах места их включения не заключались в кавычки.
Поэтому, несмотря на экранирование с помощью mysql_real_escape_string(), инъекции можно использовать, главное не включать в опасные запросы специальные.
символы.
Интересно, что ни на одном домене на тот момент не было обнаружено различных вредоносных скриптов, хотя мы ожидали наличие хотя бы одного.
Позже нам удалось выяснить, что все свои действия хакер совершал через PMA. В качестве последнего штриха мы решили подключить к PHP логгер информации обо всех входящих запросах (запись сериализованных массивов GET/POST/SERVER/COOKIE/SESSION) с помощью опции auto_prepend_file и спровоцировать злоумышленника очередным баном.
Сразу возникли проблемы с логгером.
Хотя средний уровень присутствия в сети к тому времени был невелик, игроки делали столько запросов, что логгер съедал место на жестком диске как на дрожжах.
В качестве решения мы попытались использовать сжатие записываемых данных gzip. Это помогло.
С учетом свободного места на жестком диске + 1Гб в резерве логгер смог проработать примерно 17 часов.
В связи с этим было принято решение писать лог по каждому часу отдельно, а в середине дня слить все доступные лог-файлы на локальный компьютер, попутно перезаписав их оригиналы.
Поскольку злоумышленник после бана начал бы действовать максимум через 24 часа (он появлялся в игре каждый день), то скачивать логи придется всего 2-3 раза.
Так и произошло.
Попытка номер два
В назначенное время мы включили логгер, проверили, нормально ли идет запись данных, поменяли все старые пароли и забанили злоумышленника.Пришло время ждать.
Примерно через 12 часов он дал о себе знать.
К нашему удивлению, хакер снова снял бан и продолжил игру.
Сразу после этого мы начали обсуждать все принятые меры, чтобы понять, что мы упустили.
И они быстро обнаружили одну ошибку.
Все было просто и банально — пароли на всех службах управления поменяли, а про админку забыли.
Старые пароли все еще там.
Тогда я решил еще раз посмотреть исходный код самой игры.
Мало ли, что мог туда загрузить злоумышленник после недавней провокации.
У меня только что была последняя рабочая версия на жестком диске.
Я начал скачивать движок с FTP и сравнивать копии локально.
Ни один файл не был изменен, но появился один новый скрипт (анализ записей логгера, проведенный позже, показал обращения к нему).
Это была веб-оболочка.
Судя по дате его создания, я сразу понял, о чем идет речь.
Проверяя исходные коды, я перебирал папку за папкой, передавая найденные уязвимости разработчикам и ища подозрительные скрипты.
Когда около половины всего тома было изучено, злоумышленник загрузил веб-шелл в каталог, содержимое которого я проверял в самом начале.
Соответственно, сразу этого никто и не обнаружил.
И злоумышленник смог использовать это, чтобы снять бан.
В этот момент стало понятно, что нужно как-то решить вопрос с контролем целостности файловой структуры движка.
Поскольку система контроля версий еще не использовалась (она была реализована позже), нам пришлось использовать bash-скрипт, который запускался Cron раз в 10 минут и проверял наличие новых/удалённых файлов, а также проверял наличие контрольные суммы скриптов с исходными суммами.
Его прототип я описал в одной из своих статей - anton-kuzmin.blogspot.com/2011/01/blog-post.html .
Теперь, когда шелл удален, пароли снова изменены (на этот раз все) и запущен bash-скрипт, пришло время очередного бана.
Заключение
Принятые меры дали эффект. Злоумышленник зарегистрировал в игре нового персонажа, но даже через сутки (и до настоящего времени) его аккаунт остался таким же простым, как и у других игроков.Больше изменений в файловой структуре сервера не произошло, игровой баланс начал медленно восстанавливаться, а разработчики начали массово применять обновления, которые они заранее подготовили, но не хотели загружать на сервер до тех пор, пока не возникла проблема с хакером.
было решено.
Кстати, грабитель успокоился не сразу.
В тот же день на форуме, где он обычно выкладывал внутренности игры, он выложил еще один дамп, довольно старый, под видом самого свежего.
После этого он почему-то связался с одним из разработчиков и начал убеждать его, что доступ к серверу еще не потерян.
Но на просьбу подтвердить это (например, дать пароль одного из администраторов) он либо вообще не ответил, либо дал какие-то неактуальные данные.
P.S.
В конце этой статьи хотелось бы выделить несколько важных правил для разработчиков и администраторов веб-приложений.Кому-то они покажутся банальными, но я уверен, что кому-то они могут оказаться полезными.
1) Ограничьте PHP насколько это возможно.
Запретите функции выполнения команд ОС, включите безопасный режим, отключите модули, которые вы не используете.
Зарегистрируйте ошибки интерпретатора и отключите их вывод на производственных серверах.
2) При создании резервных копий удалите из них всю конфиденциальную информацию, такую как пароли пользователей, ответы на контрольные вопросы и данные подключения к базе данных.
3) При хешировании данных не используйте простые схемы, такие как один вызов md5() или sha1().
Не следует использовать решения, взятые из популярных веб-движков.
Большинство программ, работающих с хешами, уже умеют организовывать их расшифровку.
Если вы используете свою уникальную схему, даже если это 7 вызовов md5() подряд, то злоумышленник, скорее всего, ничего не сможет расшифровать.
Ведь если используемой вами схемы нет ни в одной известной программе, то ему придется либо писать отдельный модуль специально для вашего случая, либо заказывать его за деньги.
Подумайте, какой процент от общего числа злоумышленников это сделает? Не забывайте о сложных паролях.
4) В приложениях используйте строгое разделение на административные и простые учетные записи.
То есть, чтобы администратор не мог зайти в ту же игру, используя данные админки, и наоборот. 5) Если вы решили хранить какие-либо пароли непосредственно в коде приложения, храните не их сами, а их хэши.
6) Пароли привилегированных пользователей должны быть уникальными для вашего приложения.
Ситуация, когда, например, у модератора один и тот же пароль для входа в основное приложение и для доступа на форум, может иметь очень плохие последствия.
7) Для работы с базой данных используйте готовые библиотеки типа PEAR::MDB2. В них функция экранирования данных, входящих в запрос, вызывается автоматически, что предотвращает многие проблемы.
Аналогичная ситуация и с фреймворками.
Если вам приходится помещать данные в SQL-запрос прямо в коде (например, с помощью mysql_query()), то заключайте каждое значение, помещенное в запрос, в кавычки и не забывайте про mysql_real_escape_string().
8) Не устанавливайте разрешения 777 для каталогов веб-приложений.
Хотя все зависит от ситуации.
Иногда без этого не обойтись.
9) Запретить выполнение скриптов в каталогах, доступных извне и не содержащих внутри себя никаких скриптов.
Это могут быть папки с JS-файлами, стилями CSS, шрифтами, изображениями и т. д. И заблокировать доступ к каталогам (и их содержимому), к которым пользователи вообще не должны иметь доступ.
Если есть возможность, лучше переместить их за пределы веб-каталога.
10) Настоятельно рекомендуется хранить все ограничения и настройки, связанные с веб-сервером, в общем файле конфигурации (httpd.conf), а локальные настройки отключать (с помощью .
htaccess).
Это обеспечит централизованное хранение конфигурации, а также не позволит лицу, имеющему доступ к сайту, что-либо изменить, касающееся его конкретных каталогов.
Если это невозможно, и вы, например, используете .
htaccess, то попробуйте выставить на нем права и владельца так, чтобы невозможно было вносить туда изменения от имени веб-сервера.
11) Ограничьте доступ к важным сервисам и панелям управления по IP-адресу.
12) Используйте систему контроля версий.
13) Размещайте домены и базы данных для расположенных на них приложений таким образом, чтобы они не влияли друг на друга.
Чтобы злоумышленник, взломав один сайт, не смог пройти через него на другой.
14) Не устанавливайте антихакерские скрипты или подобные модули без предварительного их тщательного тестирования.
Особенно тщательно их изучите, если собираетесь устанавливать 2-3 таких скрипта вместе.
Чаще всего это приводит к большим проблемам.
15) Если вдруг злоумышленник после отражения атаки свяжется с вами и начнет убеждать в бесполезности ваших действий, внимательно проверяйте все, что он вам говорит. Возможно, он просто блефует. 16) При возникновении каких-либо инцидентов, если невозможно обнаружить уязвимость по журналам веб-сервера, попробуйте записать все данные от всех пользователей.
Это можно сделать как с помощью самописных скриптов, так и отдельных модулей веб-сервера.
И два отдельных правила относительно контроля пользователей в онлайн-играх, к которым я пришел, работая над этим кейсом: 1) Автоматизируйте подсчет количества игровых денег (полученных, потраченных) и опыта, ведите их ежедневную статистику.
Раз в день собирайте эти данные и сравнивайте их с предыдущим днем.
Так за неделю вы определите средний процент их общего прироста за 24 часа при обычном ходе игры.
Как только появится нечестный игрок, который, например, сумел начислить себе огромное количество игровой валюты, вы сразу об этом узнаете.
2) Протоколируйте все операции с игровыми предметами.
Предмет был создан, когда монстра убили, предмет отдали, предмет продали — все запишите.
Аналогично предыдущему пункту вы можете через определенный интервал времени выбирать из базы вещи, которые не имели никакой истории до появления игрока.
То есть они появились практически из ниоткуда.
Кстати, этот же механизм поможет вернуть украденные вещи их владельцам и быстро поймать нечестных игроков.
Надеюсь, что в процессе чтения этой статьи вы узнали что-то новое и она была вам полезна.
Я буду рад ответить на любые ваши вопросы.
Теги: #защита веб-приложений #браузерные игры #веб-взлом #информационная безопасность
-
Как Записать Игры Без Мод-Чипа
19 Oct, 24 -
Электронная Коммерция И Онлайн-Бизнес
19 Oct, 24 -
Симметричное Свойство Отношения Коинтеграции
19 Oct, 24 -
Конференция Инвесттех 2017
19 Oct, 24 -
Апач Мавен 2
19 Oct, 24