• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья Автоматизация OWASP ZAP, Часть 3, Автоматизация тестирования через API

Приветствую снова всех. Извиняюсь за долгое отсутствие, некоторые данную часть ждали больше всего. К сожалению не смог выпустить все оперативно в силу различных причин (в т.ч. и лени :) )
Итак, для тех, кто не знаком, советую ознакомиться с предыдущими вводными частями:
Автоматизация OWASP ZAP. Часть 1. Вводная часть
Автоматизация OWASP ZAP. Часть 2. Запуск в Docker, доступ к API

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

Определения

Сессия - это сессия в рамках которой происходит работа ZAP. Сессии можно создавать, загружать, сохранять. Сессия стартует по факту вместе с ZAP. Ей можно дать имя, и она будет сохраняться. Если открыть новую сессию с таким же именем как и предыдущая, то сессия пересоздастся.
Контекст - по факту выборка того, на что надо обратить внимание. Т.е. набор URL, того, что надо исключить, набор технологий (базы данных, языки программирования и т.д.). Тут же настройка аутентификации, авторизации, отслеживания сессий(для сканирования под Login пользователем) (это вообще отдельная статья может быть по премудростям аутентификации, если будет интересно, смогу в будущем описать или ответить в личке).
Паук и ajax-паук - ну тут стандартно, первый смотрит в ответах урлы и ходит по ним, с обозначенной глубиной. Второй предназначен для JavaScript, т.е. он запускает браузер и через браузер пытается выдернуть динамически формируемые урлы. (Для пауков как раз и важна авторизация и управление сессиями про которые я описал в контексте).
Активное сканирование - это как раз и есть нужный нам модуль. Тут ZAP береn накопленное все добро из прокси и пауков (из статей выше я писал, что я натравливаю end-to-end регрессионные тесты) и делает сканирование (т.е. вставляет пейлоады в различные параметры, в зависимости от настроек активного сканирования).

Код автоматизации и его структура

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

Давайте рассмотрим структуру репки:
Код:
├── Dockerfile
├── Jenkinsfile
Тут в корне, как я писал ранее, находится Dockerfile (чтобы запускать скрипт из докера). И Jenkinsfile. Последний у нас используется дженкинсом, и описывает джобу которую он выполняет после прохождения end-to-end тестов. Т.е. по факту там написано, что надо скачать уже сбилженный докер из registry(развернут у нас же) и запустить его. Образ оказывается в registry в через Gitlab CI/CD и строится каждый раз когда изменения мержатся в мастер, но это уже лирическое отступление.

Далее перейдем к папке scripts где все и находится.

Код:
.
├── api_scan.py
├── configs
├── defectdojo
├── regression_scan.py
├── scan_core
└── slack
Здесь есть два файла. Это и есть основные скрипты описывающие действия ЗАП и других модулей. Их будем рассматривать выше.
slack - здесь описан класс для интеграции со слэк. Делает базовые вещи (шлет сообщения, отчеты, и может удалять отчеты и файлы) через модуль requests.
defectdojo - тут просто один файл который я взял вот отсюда (репозиторий defectDojo). В файле __init__ создал наследованный класс и определил для него нужные мне методы.
configs - тут хранятся различные переменные/настройки которые используются в скриптах.

scan_core тут основные функции обращений к API ZAP и описаны. Кратко пройдемся по папкам:
Код:
├── api_conf.py
├── colors.py
├── __init__.py
├── jobs
│   ├── __init__.py
│   ├── reports.py
│   ├── scans.py
│   └── spiders.py
├── setup
│   ├── auth.py
│   ├── init_context.py
│   ├── __init__.py
│   ├── init_spider.py
│   ├── policy.py
│   ├── proxy.py
│   └── session.py
└── shared_core.py

api_conf.py - тут конфиги различных АПИ. необходимо открыть и отредактировать своими значениями.
shared_core.py какие то общие функции.
Папка setup - тут находятся различные функции предназначенные для настройки ZAP.
job - тут функции которые выполняют различную работу (запускают пауков, активное сканирование, и строит отчеты и отправляет их. Тут же в reports описана интеграция с redmine).

Описание скрипта

Как упоминалось ранее, в папке scripts находятся 2 файла:
Код:
.
├── api_scan.py
└── regression_scan.py

api_scan.py предназначен для сканирования АПИ приложения. Т.е. он подгружает спецификацию и сканирует её. Тут есть недостаток у ЗАП, что он заполняет данные своими данными, поэтому для лучшего тестирования лучше взять у тестировщиков валидные данные и создать отдельный файл, а также запускать сканирование через zap-api-scan.py (который поставляется с ZAP в докере). Кому интересно, объясню позже, расписывать очень долго. Но для пробы пера, сойдет. Так же как доп. материал, советую ознакомиться со статьей авторов:
Обратите внимание, тут должны быть установлены доп. модули: Replacer и OpenAPI (В докере последнее имеется).

Краткие действия в файле:
1. Выключаются все ранее созданные реплэйсеры (они автоматически вставляют данные в запросы отправляемые ZAP, в моем случае это хедер с токеном авторизации или иные данные которые помешают получить токен авторизации). Создаем контекст и задаем ему настройки.​
2.
Python:
token = requests.post(config.site + "auth", json=config.log_pass).json()[config.token_data][/INDENT]
# Load API from url
print(f'Remove replace rule {config.replacer_name} ==> {zap.replacer.remove_rule(config.replacer_name)}')
print(f'Add replacer rule {config.replacer_name} ==> ' + zap.replacer.add_rule(description=config.replacer_name,
                                                                               enabled=True,
                                                                               matchtype="REQ_HEADER",
                                                                               matchstring="Access-Token",
                                                                               matchregex=False,
                                                                               replacement=token))
Делаю Запрос и получаю токен. Удаляю реплэйсер (если был), и создаю новый с полученным токеном. В моем случае это Header вида Token: dsadasdasdsadsadsa4321dsa
3.
Python:
zap.openapi.import_url(url=config.site + config.spec_path, hostoverride=config.site)
Импортируем описание АПИ. После этого в ZAP должно создастся дерево запросов.​
4. Ниже настраиваем параметры активного сканирования (количество потоков, исключаемые из сканирования параметры и urls).​
5. Старт сканирования. С обработкой ошибок и отправлением уведомлений в SLACK​
6. Последними двумя строками, в случае если сканирование завершилось, создаем html отчет и отправляем его в слак.​

regression_scan.py
Настройки сканирования в данном файле можно задавать флагами. Описание флагов можно получить через опцию --help.
По умолчанию скрипт делает активное сканирование (без паука) и и отсылает результаты в Slack и DefectDojo (менеджер уязвимостей).

Давайте быстренько пробежимся по скрипту:
Python:
if args.new_session:[/INDENT]
[INDENT=2]    set_session.new_session()
Создает новую сессию. Это надо перед тем, как стартовать end-to-end тесты. Данный флаг не надо использовать с другими флагами. У нас это запускается Jenkins в prejob (на самом деле создаем новую сессию через curl).​
Python:
    context_id = context_init.set_contex_properties(contextname=conf.contextName,
                                                    include_url=conf.contextIncludeURL,
                                                    exclude_url=conf.contextExcludeURL,
                                                    technology=conf.contextTechnology)
    # Remove "Default context" for exclude all scans not in scope.
    context_init.remove_default_context()
    policy_name = import_scan_policy(policy_name=conf.ImportedPolicyName)
    print(f"{policy_name} was applied for ascan")
Создаем контекст с определенным листом технологий, и исключающими УРЛс. Удаляем дефолтный контекст (чтобы не интересующие нас сайты случайно не залетели в отчет).​
Т.к. у меня тонкая настройка политики, то я ранее создал её в интерфейсе ZAP и положил в папку, которой делаю volume в Docker с ZAP. Тут я её подгружаю. Так же имеются методы, которые позволяют создать политику с собственным именем и выставить для всех пейлоадов определенные одинаковые параметры. (Все значения параметров определяются в конфигах в папке configs).​
Далее не буду копировать код, но если указано, что надо запустить паука, то запускается паук и после его отработки аналогично скрипту и его описанию выше, настраиваются параметры активного сканирования.​
Python:
 # Start Ascan
    try:
        print(f"Start ASCAN with Context {conf.contextName} and policy {policy_name}")
        scans.start_ascan(context_name=conf.contextName, scan_policy=policy_name)
    except ValueError:
        print("Scan_id does not exist. Proxy is empty.")
        slack.post_message_to_slack("ERROR! Proxy is empty!")
        sys.exit()
    except Exception as e:
        print("Error:", e)
        slack.post_message_to_slack("Error: " + str(e))
        sys.exit()
Тут стартует активное сканирование, и обрабатываются ошибки с их отправкой в Slack.​
В следующем модуле генерируются и отправляются отчеты:​
Python:
slack.upload_file(file=html_report)
отправляем файл с отчетом в Slack.​
Python:
add_redmine_issue_notes(type_of_scan='Regression')
отправляем отчет в редмайн (предварительно создал отдельный проект)​
Python:
xml_report = report_gen(type_file='xml')
        dd = DefectDojoTB(product_name=r_conf.dd_name_of_product, engagement_name=r_conf.dd_name_of_engagement)

        print('Upload report to DefectDojo:', dd.import_tb_scan(scan_type=r_conf.dd_scan_type,
                                                                file=xml_report,
                                                                scan_date=datetime.datetime.now().strftime('%Y-%m-%d'),
                                                                tags=r_conf.dd_scan_tag))
Создаем объект класса DefectDojo и далее загружаем xml отчет в заранее созданный product и engagement.​

Заключительное слово
Благодарю всех, кто осилил. По хорошему все это добро надо разбивать на несколько частей. + У ЗАП много еще потайных мест и вещей которые не сразу понятны. К сожалению, я не имею возможности/времени ими поделиться, если будет много вопросов возможно и составлю по ним описания. Зависит от активности и интереса комьюнити.
Так же возможно не все работает, т.к. мною не все функции были протестированы, особенно темное пятно в Пауке(т.к. у меня нет в нем необходимости на настоящий момент). А также не до конца понятен алгоритм Аякс паука. Точнее какой url ему скармливать, в моих приложениях он не очень активно что-то находит.

Так же у ЗАП есть механизмы внутреннего скриптования. Про них можно много рассказывать тоже, и некоторые вещи без скриптов в самом ZAP в современных приложениях к сожалению не реализуемы. Данной области я касался лишь слегка, но большинство вещей все-таки можно выполнить стандартными возможностями OWASP ZAP.​
 
Последнее редактирование:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!