Хабрахабр

Бдительная «Лида»: автоматизация тестирования безопасности

Добрый день, уважаемые читатели. Меня зовут Виктор Буров, я разработчик в ISPsystem. В прошлом посте я рассказывал об инструменте для создания автотестов, сегодня поделюсь опытом автоматизации тестирования безопасности.

Ручное тестирование занимало много времени и не гарантировало, что будут найдены все уязвимости. Сначала уязвимости в продуктах у нас искал отдельный сотрудник. Тогда мы решили написать утилиту, которая облегчит жизнь тестировщика, сэкономит его время и позволит проверять продукты после каждого изменения. Выяснив основные закономерности тестирования, мы пришли к выводу, что его можно автоматизировать. Вообще, у нас в компании это стало традицией — называть инструменты тестирования именами тестировщиц.
Проанализировав утилиты поиска уязвимостей, я пришёл к выводу, что им всем необходимо указывать функции для вызова и используемые параметры. Так как тестировщика звали Лида, новое приложение мы назвали в её честь. Мы вновь решили воспользоваться преимуществами унифицированного интерфейса и сформулировали требования к «Лиде».

Требования на старте:

  1. Автоматическое построение списков функций.
  2. Автозаполнение параметров.
  3. Выполнение запросов к API.
  4. Анализ вывода данных после выполнения функций.
  5. Поиск уязвимостей в данных.
  6. Формирование отчётов.
  7. Гибкие настройки.

Реализовать всё это оказалось непросто.

Реализация

Обход форм и списков

Чтобы найти уязвимости в функции, её надо выполнить, передав необходимые параметры. Наш интерфейс строится на основе списков и форм, поэтому автоматизировать сбор данных можно за счёт обработки xml-документов, описывающих структуру элементов интерфейса.

«Лида» открывает список первого уровня. Я решил начать обход с главного меню, рекурсивно заходя во все вложенные списки. Как правило, в нём есть несколько кнопок, вызывающих какие-то функции.

На основе этой информации генерируются значения полей. Если кнопка открывает форму, то результатом вызова будет xml-документ с узлами, содержащими информацию о полях: имя, валидатор, диапазон допустимых значений. Если валидатора нет, генерируется случайная строка. Например, для int будет сгенерировано число. После заполнения всех полей формы отправляется запрос.

Если функция является списком, то он будет открыт и для его элементов будут вызваны функции, привязанные к кнопкам.

При проверке списков возникает проблема — все списки должны иметь набор записей, который обеспечит доступность нажатия всех кнопок в списке.

Поиск SQL-инъекций

SQL-инъекции — наверное, одна из самых распространенных проблем для приложений, в том числе и для наших. Многие вызовы функций порождают выполнение различных запросов к СУБД. Ошибка возникает, когда параметры, пришедшие извне, подставляются в тело запроса «как есть». Последствия таких ошибок могут быть печальными: от несанкционированного получения данных до удаления таблиц.

После выполнения функции приложение ищет значения переданных параметров в получившихся SQL-запросах. Чтобы начать поиск SQL-инъекций, я организовал вывод всех SQL-запросов в файл.

Но в нашем случае существует только один метод для выполнения запросов и добавить в него логирование было несложно. Можно было воспользоваться журналом самого SQL-сервера. Благодаря этому мы точно знаем, какой вызов породил тот или иной запрос.

Если кавычка найдена в той же последовательности, значит, параметр не экранируется — мы нашли место для SQL-инъекций. Когда значение передаваемого параметра найдено, утилита передаёт в этот параметр значение, содержащее одинарную кавычку.

Анализ системных вызовов

Аналогичная проблема возникает, когда мы выполняем какие-либо системные вызовы. Их я решил искать при помощи strace и подобрал для него оптимальные параметры запуска. Пример запуска ISPmanager:

strace -f -s 1024 -e trace=file,process bin/core ispmgr

Так же как и с SQL инъекциями, «Лида» выполняет функцию и анализирует вывод strace на предмет попадания в функции open, unlink, rmdir, chmod chown, chflags, mknod, mkfifo, fcntl, symlink, link, execve, mkdir значений переданных параметров.

Если оно попадает как есть, то потенциальная уязвимость найдена. Если параметр найден, утилита передаёт в него значение, содержащее, к примеру, путь с переходом в директорию выше.

Он позволяет определить, в какой функции не экранируются аргументы запуска исполняемых файлов. Очень полезным оказался анализ функции execve. Эта ошибка очень дорогая, ведь через нее можно получить root-доступ к серверу, просто сменив пароль.

Данный подход может обходится дешевле, чем поиск ошибок собственными силами (тестировщик может ошибку и не найти, а зарплату получит). При нахождении пользователями уязвимости в наших продуктах, компания выплачивает денежное вознаграждение, размер которого зависит от категории уязвимости.

Еще интересная проверка: проверка порядка вызова функций stat и других. Часто сначала проверяют доступ через stat, а затем какие-либо небезопасные действия, что оставляет возможность для подмены. Но такое мы не автоматизировали.

Проверка доступа к чужим объектам

Доступ к чужим объектам мы проверяем из-под пользователя для сущностей другого пользователя и администратора. В этом режиме мы проверяем возможность чтения, изменения и просмотра списков элементов чужого пользователя.

Затем вызывает эти же функции с элементами из-под другого пользователя. «Лида» обходит все доступные от имени владельца или администратора функции и запоминает их элементы. Если такой ошибки не получено, следовательно, с большой вероятностью можно прочитать данные чужого пользователя. В идеальной ситуации ответом должна быть ошибка типа Access или Missed.

В начало таких функций мы добавляем проверку на права доступа к элементу. В некоторых случаях отсутствие ошибки не означает, что можно получить прямой доступ к объектам другого пользователя. Так проверяется не только безопасность, но и корректность ответов сервера.

Валидация API

Валидация нашего API является дополнительным бонусом проверки функций на уязвимости. Анализируя отчеты о работе Лиды мы научились возвращать правильные типы ошибок, сделали наше API более удобным и логичным. В результате, как и с магнитофоном, мы получили не только проверку безопасности, но и в очередной раз проверили наш API на «логичность».

Трудности

Ложные срабатывания

Утилита может работать со всеми нашими продуктами, следовательно, она проверяет много разных функций. В основном ложные срабатывания появлялись в режиме проверки доступа к чужим объектам. Это связано с особенностями работы кнопок и функций.

Казалось, что она полностью отлажена, но при проверках на разных панелях возникали все новые ложные срабатывания. Ложные срабатывания были самой большой проблемой «Лиды». В итоге было несколько этапов их исправления.

Создание сущностей

Основная часть действий в панели выполняется над какой-либо сущностью (доменное имя, база данных и т. д.). Чтобы добиться максимальной автоматизации, «Лида» должна была создавать эти сущности автоматически. Но на практике это оказалось труднореализуемо. Иногда валидация выполняется в коде, поэтому не всегда удаётся подставить значение параметра автоматически. Вторая причина — зависимые сущности. Например, для создания почтового ящика необходимо создать почтовый домен.

Перед запуском тестировщик создаёт сущности вручную и делает снимок машины, так как после проверки сущности будут изменены. Поэтому мы решили не биться за полную автоматизацию. Это позволяет не пропустить проверку группы функций в случае неуспешного создания сущности.

Вызов деструктивных функций

Практически в каждом списке есть функции удаления или выключения сущности. Если выполнять их в порядке следования, то сущность будет удалена до выполнения других функций. Я определяю такие функции и выполняю после других. Дополнительно добавил ключ, который запрещает выполнение таких функций.

Их приходится отслеживать и добавлять в список игнорируемых. Некоторые функции перезагружают сервер.

Во время тестирования безопасности это приводит к тому, что панель запускается без трассировки SQL-запросов или strace — дальнейшая проверка становится бессмысленной. Из-за особенностей логики работы некоторые функции перезапускают панель. Приходится это отслеживать и заново запускать панель в режиме трассировки.

Проверка зависимых параметров

На формах есть поля ввод текста, чекбоксы, выпадающие списки, от значений которых зависит доступность значений других полей. На каждое значение зависимого поля может приходиться отдельный участок кода, следовательно, части когда могут остаться непроверенными.

Для решения этой проблемы я добавил алгоритмы анализа зависимых полей и проверку всех комбинаций зависимых элементов управления.

Проверка функций, недоступных в интерфейсе

Служебные функции недоступны для перехода, но могут содержать уязвимости. Чтобы определить и проверить их, у нас есть специальная функция, возвращающая список всех зарегистрированных функций. Этот список мы сравниваем со списком проверенных функций. Для служебных функций нет метаданных, поэтому проверить обрабатываемые внутри них параметры невозможно.Чтобы хоть как-то проверить такие функции, я передаю в них наши стандартные параметры elid, plid и другие.

Заключение

Мы включили «Лиду» в каждую ночную сборку в Jenkins. По итогу её работы формируется отчет о проверке, информация о подозрительной функции в нем выводится со всеми параметрами.

Тестировщик обрабатывает полученный отчёт: копирует параметры подозрительной функции в браузер и анализирует поведение и лог панели. Закрытую разработчиком задачу теперь проверяет не только тестировщик, но и «Лида». Если уязвимость подтверждается, регистрирует ошибку разработчику.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»