Как взломать сервис, в котором используется десериализация данных
Привет! Я Артемий Богданов, эксперт по практической безопасности Start X. Сегодня я расскажу, как небезопасная десериализация может привести к взлому сервиса.
Сериализация и последующая десериализация бывают нужны, когда необходимо сохранить объект в строку, а затем в точности восстановить его одной командой, даже если это объект сложной структуры.
Выглядит полезно, но серьезно угрожает безопасности: хакеры могут внедрять вредоносный код, модифицировать данные, например, количество бонусов в интернет-магазине, украсть конфиденциальные сведения и много чего еще.
В этой статье мы рассмотрим уязвимый сервер глазами хакера, найдем слабые места и заполучим reverse-shell. На примере взлома сервиса доставки еды вы увидите, как отсутствие должной защиты может привести к серьезным последствиям — от утечки личных данных до полного захвата сервера.
Как происходит взлом
Чтобы продемонстрировать эту уязвимость, мы создали приложение-симулятор сервиса доставки еды.
Покажу, как действует хакер в процессе поиска уязвимости:
Злоумышленник вводит данные, которые просит приложение: адрес, имя, телефон.
Далее он делает заказ.
Получает сообщение, что заказ принят, и замечает, что сайт его каким-то образом запомнил. При повторном заказе уже не требуется вводить имя и адрес доставки, так как они уже заполнены и отображаются на странице.
Чтобы понять, каким образом приложение сохранило данные, хакер переходит в консоль разработчика на вкладку Application и в cookie видит записи:
Какие особенности мы видим? Здесь закодированы специальные символы, в частности, символы кириллического алфавита, а перенос строки отмечается спецсимволом.
Хакер обращает внимание на формат данных и видит, что они сериализованы в YAML. Если окажется, что на сервере используется небезопасная функция десериализации этих данных, это позволит злоумышленнику провести атаку на приложение.
Теперь можно поискать данные о бэкенде. Злоумышленник смотрит заголовки ответа сервера: видит, что используется Python 3.8.17. Это значит, что перед нами приложение на Python, которое принимает данные от пользователя, сериализует их и кладет в cookie.
Самая популярная библиотека, которая позволяет сериализовать и десериализовать данные в YAML в Python, — PyYAML. Если открыть документацию библиотеки PyYAML, то мы увидим, что при сериализации в YAML используются объекты классов.
Существуют YAML.tag, которые соответствуют типам в Python. В нашем случае хакера больше всего интересует apply module, который можно использовать при составлении эксплойта:
С его помощью можно создать эксплойт, который позволит выполнить произвольный код:
— эксплойт при десериализации выполнит команду операционной системы;
— команда вызовет bash;
— bash скажет эксплойту подключить еще один bash к удаленному серверу (к IP-серверу хакера).
Поэтому хакер на своем сервере открывает порт, чтобы принять соединение от уязвимого сервера:
Таким образом, при десериализации YAML-строки взломщик получит Back Connect Shell.
Хакер подменяет значение user data на эксплойт. Для этого он переходит в браузер на вкладку Application и меняет значение cookie на пейлоад, который заранее составил, и который позволит выполнить зловредный код. После этого злоумышленник перезагружает страницу.
При перезагрузке видим, что страничка «подвисла» — это возможный признак того, что эксплуатация прошла успешно.
Возвращаемся в терминал сервера атакующего. Злоумышленник видит, что к его серверу подключился атакуемый хост, а также пришло приглашение терминала для выполнения команд.
Сервер захвачен. Уязвимость привела к тому, что хакер может выполнить произвольную команду на сервере: заставить его майнить, получить все пользовательские данные и так далее. Выполнив команду id, злоумышленник выясняет, что у него есть не только доступ к серверу, но и root-права.
Мы показали, что захватить корпоративный сервер злоумышленнику удаётся за несколько минут.
Как предупредить уязвимости и атаки при сериализации и десериализации
На мой взгляд, главный совет для безопасности вашего сервера — отказаться от десериализации пользовательских данных совсем. Это полностью исключит вероятность таких атак.
Если в вашем случае отказаться от десериализации нельзя, важно обеспечить безопасную и правильную обработку данных. Вот несколько советов, как это сделать:
Сериализованные данные нужно шифровать и использовать механизмы подписи или хэширования. Чтобы не дать возможность злоумышленнику их каким-то образом подменить.
Вместо разрешения на десериализацию любого объекта используйте белые списки для указания доверенных классов.
Используйте надежные и безопасные библиотеки.
Попробуйте использовать менее рискованные форматы или методы передачи данных, при условии, что они подходят для вашего сервиса. Возможно, вам вообще не нужна сериализация в классическом смысле, а можно просто сохранить данные в JSON.
Разбирайте конкретные практические задачи с примерами кода и безопасной реализацией на языке программирования, который вы используете в работе.
Выводы
В этой статье мы подробно рассмотрели вопрос небезопасной десериализации, показали на практическом примере, как может действовать атакующий, и обсудили рекомендации по предотвращению таких уязвимостей.
В заключение хочется подчеркнуть, что наиболее значимый фактор в обеспечении безопасности программного обеспечения — человеческий фактор.
Технические средства защиты, например, статический анализатор кода, динамический анализ безопасности и проведение пентестов, несомненно, играют важную роль. Они помогают выявлять потенциальные проблемы в коде и являются неотъемлемой частью процесса разработки. Однако эти инструменты не способны полностью заменить человеческую экспертизу.
Основа безопасного программирования — это обучение и развитие навыков разработчиков. Понимание основ безопасности, осведомленность о распространенных уязвимостях и методиках их предотвращения — ключевые аспекты в написании безопасного кода. Инвестиции в обучение разработчиков и повышение их осведомленности по вопросам безопасности не только помогают минимизировать риски, но и способствуют созданию более качественного и надежного программного обеспечения.
Таким образом, хотя технические средства защиты необходимы, решающую роль в обеспечении безопасности приложений играет компетентность и знания разработчиков. Они являются первой и самой важной линией защиты в борьбе с уязвимостями программного обеспечения.