Автоматизация Acunetix API + SQLMAP

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор petrinh1988
Источник https://xss.is


В какой-то момент понял, что трачу время на банальные операции: загружаю таргеты в окуня, запускаю сканирование на SQLi, удачные сканирования перекидываю в мап. Не порядок, тем более у Acunetix 100% должен быть API. В целом, данную заметку можно рассматривать, как знакомство с API Acunetix на полезном примере.

Сразу оговорюсь, что не буду здесь рассматривать сопутствующие части, такие как получение таргета для добавления, создание очереди сканирования в SQLMAP или организация сетевого взаимодействия между элементами цепи. Эти части у всех могут быть организованы по своему. Кто-то базу входящих таргетов сложит в обычный текстовый файл, кто-то в базу sqllite. Тоже касается и сетевых нюансов, окунь и sqlmap могут работать в рамках одной машины, могут быть на разных вирталках или вовсе разных серверах. Поэтому, по максимуму постараюсь оставить все за кадром. На выходе хочу получить рабочий скрипт, который максимально автоматизирует процесс работы.

Схему работы скрипта я придумал такую:
  1. Запуск сканирований в Acunetix
    1. Смотрим количество активных сканирований
    2. Если количество меньше 7 (в моем случае это комфортное число), добавляем новын таргетв и стартуем их. Иначе идем к п.2.
  2. Запускаем сканирование в sqlmap уязвимостей из Acunetix
    1. Ищем новые зависи с sqli
    2. Если есть, добавляем уязвимости в очередь, если нет - спим.
При подготовке материала я использовал следующее ПО:
1. Acunetix Version: 24.2.240226074 для Windows отученную от жадности Pwn3rzs
2. Postman
3. VS Code

Исследование API Acunetix

Открываю Acunetix -> Администратор -> Профиль и в самом низу нахожу то, что хотел:

1731664479964.png


Супер! Ключ есть, документация есть. Из документации узнаем стандартный адрес REST API: https://127.0.0.1:3443/api/v1/ Самое время поиграться в Postman, после накидать нужный скрипт, например, на Python.

Acunetix очень хороший инструмент, но то, как организован в интерфейсе доступ к данным… зачастую логика разработчиков непонятна. Это подсказывало, что работа с API не станет легкой прогулкой. И да, чутье не подвело. Документация API не самая точная. С другой стороны, это некий тест на минимум знаний в пентестинге — сможешь догадаться, как пользоваться API, добро пожаловать. Ну а если нет, то зачем ты вообще установил окуня?

Ссылка на локальную документацию API: https://localhost:3443/Acunetix-API-Documentation.html#-scans именно ей я пользовался и на нее всю дорогу ругался.

Авторизация REST API

Тут все просто. Токен лежит в профиле, а передавать его нужно обычным заголовком X-Auth, без танцев с бубном:

1731668055296.png



Получаем активные сканирования

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

Bash: Скопировать в буфер обмена
Код:
curl -X GET https://127.0.0.1:3443/api/v1/scans \
  -H 'Accept: application/json' \
  -H 'X-Auth: API_KEY'

Для фильтрации предусмотрены GET-параметры:
c - Cursor indicating which index is the head of the next batch of elements (generally coupled with a limit).
l - Maximum number of items returned. Parameter defaults to 100 if not passed. Limit ranges accepted are less than 100 or greater than 1 (1 < limit < 100).
q - Query to filter results based on a number of filters.
s - none

Черт с ним с “s”, вероятно в других запросах этот параметр и имеет смысл, смотрим чего можно положить в “q”:
Код: Скопировать в буфер обмена
Код:
target: Specific target to filter for.
threat: Level of severity to filter scans by.
business_criticality: Level of business criticality to filter scans for.
scan_status: Scan state to filter by. Multiple values can be added and are comma-separated (e.g. ?scan_status=completed,queued)
profile_id: Scan type to filter scans by (e.g. Crawl Only).
group_id: Target group to filter scans by.

Нас интересует scan_status, но вот первая нестыковка. В примерах справки выше, обращение через “q” выглядит так: ?q=scan_status:processing. Здесь же нам предлагается использовать scan_status, как самостоятельный параметр. Окей, попробуем по всякому.

Request: https://127.0.0.1:3443/api/v1/scans?q=scan_status:processing

JSON: Скопировать в буфер обмена
Код:
{
    "code": 16,
    "message": "Validation errors",
    "details": [
        {
            "q": {
                "problems": [
                    {
                        "error_message:": "Unknown filter key",
                        "param_path": "q.scan_status",
                        "code": "invalid_filter"
                    }
                ],
                "src": "url"
            }
        }
    ]
Упс… не то. Попытка использовать, как scan_status в виде отдельного параметра, выдает результат без какой либо фильтрации. Не буду томить. Решение подсказала панель управления Acunetix, там параметр выглядит как “status”. Верный URL запроса такой:

https://127.0.0.1:3443/api/v1/scans?q=status:processing

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

Добавление нового таргета

Для добавления новой цели есть целых два варианта: одиночное и множественное. Вот, что справка говорит про одиночное добавление:

Bash: Скопировать в буфер обмена
Код:
# You can also use wget
curl -X POST https://127.0.0.1:3443/api/v1/targets \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-Auth: API_KEY'

Body:
JSON: Скопировать в буфер обмена
Код:
{
  "address": "string",
  "description": "",
  "type": "default",
  "criticality": 30
}

Другой вариант — добавлять таргеты пачкой. В дальнейшем, этот вариант станет предпочтительным, но об этом позже. Множественное добавление производится через ендпоинт add и принимает массив таргетов и групп, к которым их нужно прикрепить:
Bash: Скопировать в буфер обмена
Код:
curl -X POST https://127.0.0.1:3443/api/v1/targets/add \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-Auth: API_KEY'

Body:
JSON: Скопировать в буфер обмена
Код:
{
  "targets": [
    {
      "address": "string",
      "description": "",
      "type": "default",
      "criticality": 30
    }
  ],
  "groups": [
    "497f6eca-6276-4993-bfeb-53cbbbba6f08"
  ]
}

Конечно же, чтобы добавить таргеты к группам, нам потребуется получить группы: https://127.0.0.1:3443/api/v1/target_groups В ответ получим JSON с массивом groups.

1731668187005.png



Пробую создать новый таргет, но хочу сразу поместить его в группу с идентификатором “633495df-f965-473c-86e8-785eef521a7e”. Учитывая, что документация по API составлена по принципу “лишь бы было”, пытаюсь запихать группу в group_id. Таргет создался, но в группе пусто. Скажу сразу, что через добавление одиночного таргета у меня не получилось создать цель с добавлением в группу. На всякий случай попробовал отследить добавление ручками

Оказалось, что сам окунь добавляет таргет через множественное добавление. Похоже, других способов сразу прицепить группу не существует. А для меня группы важны, я при помощи них группирую… ))) Если серьезно, удобно разбивать по источникам таргетов, чтобы потом можно было проанализировать деятельность. Ну или найти “затерявшийся” таргет.

Мне не принципиально. Буду тогда использовать групповое добавление. Зато, мы увидели, какие параметры реально ждет REST API. Указанные в справке параметры type и criticality, тоже нужны, но мне достаточно их значений по умолчанию.

После создания таргета, вернулся его идентификатор. Он потребуется для запуска, но сначала сделаю шаг назад и поищу запрос, который позволит проверить есть ли url в базе. Логично же, что перед добавлением таргета, нужно проверить нет ли его уже в базе? Как говориться, лучше поздно, чем никогда.

В документации ничего дельного по этому поводу не нашел, поэтому снова смотрю запросы самого Acunetix: https://127.0.0.1:3443/api/v1/targets?q=text_search:*https://pornhub.com
В ответ приходит объект с массивом targets. В коде это превратится в простую проверку количества объектов.

Создаем сканирование через API

Снова смотрю справку с надеждой без надежды, вот описание метода:

Bash: Скопировать в буфер обмена
Код:
curl -X POST https://127.0.0.1:3443/api/v1/scans \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-Auth: API_KEY'

Body
JSON: Скопировать в буфер обмена
Код:
#  Пример из документации АПИ
{
  "target_id": "d3bcdc92-4191-401b-ad0c-42056c6efab9",
  "profile_id": "bfcb6779-b1f9-41fc-92d7-88f8bc1d12e8",
  "report_template_id": "e89ef7db-4101-4c97-b7ab-9249efd2d3cd",
  "schedule": {
    "disable": true,
    "time_sensitive": true,
    "history_limit": 10,
    "start_date": "string",
    "recurrence": "string",
    "triggerable": false
  },
  "max_scan_time": 0,
  "incremental": false
}

Что-то много всего он просит… и, конечно же, никакой развернутой информации по запросу нет. Давайте по порядку. Сначала разберемся с profile_id. Это ничто иное, как профиль сканирования. Запросить профили сканирования можно через метод API : https://127.0.0.1:3443/api/v1/scanning_profiles

Скорее всего, если у вас установлена нуленная версия, профили сканирования будут как у меня:
Спойлер: Полный JSON-ответ
JSON: Скопировать в буфер обмена
Код:
{
    "scanning_profiles": [
        {
            "checks": [],
            "custom": false,
            "name": "Full Scan",
            "profile_id": "11111111-1111-1111-1111-111111111111",
            "sort_order": 10
        },
        {
            "checks": [],
            "custom": false,
            "name": "Critical / High Risk",
            "profile_id": "11111111-1111-1111-1111-111111111112",
            "sort_order": 20
        },
        {
            "checks": [],
            "custom": false,
            "name": "Critical / High / Medium Risk",
            "profile_id": "11111111-1111-1111-1111-111111111119",
            "sort_order": 30
        },
        {
            "checks": [],
            "custom": false,
            "name": "Cross-site Scripting",
            "profile_id": "11111111-1111-1111-1111-111111111116",
            "sort_order": 40
        },
        {
            "checks": [],
            "custom": false,
            "name": "SQL Injection",
            "profile_id": "11111111-1111-1111-1111-111111111113",
            "sort_order": 50
        },
        {
            "checks": [],
            "custom": false,
            "name": "Weak Passwords",
            "profile_id": "11111111-1111-1111-1111-111111111115",
            "sort_order": 60
        },
        {
            "checks": [],
            "custom": false,
            "name": "Crawl Only",
            "profile_id": "11111111-1111-1111-1111-111111111117",
            "sort_order": 70
        },
        {
            "checks": [],
            "custom": false,
            "name": "OWASP Top 10",
            "profile_id": "11111111-1111-1111-1111-111111111129",
            "sort_order": 80
        },
        {
            "checks": [],
            "custom": false,
            "name": "PCI checks",
            "profile_id": "11111111-1111-1111-1111-111111111131",
            "sort_order": 81
        },
        {
            "checks": [],
            "custom": false,
            "name": "Sans Top 25",
            "profile_id": "11111111-1111-1111-1111-111111111132",
            "sort_order": 82
        },
        {
            "checks": [],
            "custom": false,
            "name": "Malware Scan",
            "profile_id": "11111111-1111-1111-1111-111111111120",
            "sort_order": 90
        }
    ]
}

Меня интересует SQL Injection, поэтому использовать буду профиль “11111111-1111-1111-1111-111111111113”

Пробую создать сканирование только с таргетом и профилем сканирования, но нет… нужно все же указывать свойство schedule

1731668475031.png



Чтобы не тратить время впустую, создаю сканирование через интерфейс и копирую оттуда часть запроса:
JSON: Скопировать в буфер обмена
Код:
{
  "target_id": "18d1d575-cb54-47f8-9ca9-124f5345f882",
  "profile_id": "11111111-1111-1111-1111-111111111113",
  "incremental": false,
  "schedule": {
        "disable": false,
        "start_date": null,
        "time_sensitive": false
    }
}

Тестирую в Postman и получаю параметры вновь созданного сканирования. Проверяю в интерфейсе - все ок, сканирование создано!

1731668693920.png



Получаем информацию по уязвимостям:
Вторая часть не менее важная - получить данные по уязвимостям и передать их на сканирование в SQLMAP. Пока, соответственно, разбираем нужные нам методы API Acunetix.

Завершающий шаг знакомства с API. Нам нужен этот ендпоинт:

Bash: Скопировать в буфер обмена
Код:
curl -X GET https://127.0.0.1:3443/api/v1/vulnerabilities \
  -H 'Accept: application/json' \
  -H 'X-Auth: API_KEY'

Как мы договорились в самом начале, никакой информации по параметрам запроса разработчики не предоставляют. Снова полез смотреть запросы окуня. Запрос с фильтрацией по SQL Injection выглядит так:

https://localhost:3443/api/v1/vulne...2d-1a152945cdae;status:!ignored;status:!fixed;

Если точнее, вот сам фильтр: q=vt_id:db04b846-7dec-fb62-f12d-1a152945cdae;

Факт, что тип уязвимости нужно искать по идентификатору, а не тэгу, меня не очень радует. С одной стороны, боль-мень надежно. С другой стороны, при ручном вводе фильтра выдает еще всякие варианты с “SQL Injection”. В общем, чтобы узнать идентификаторы уязвимостей, можно воспользоваться текстовым поиском по типам уязвимостей:

https://localhost:3443/api/v1/vulnerability_types?q=text_search:*sql injection

Обратите внимание на “*”. Без этого поиска не случится, в ответ вы получите сообщение о неправильном операторе.
1731668801989.png



Последним штрихом будет получение деталей уязвимости, а именно: сам реквест с пэйлоадом, указанием уязвимого параметра и тип инъекции. Для этого обращаемся к тому же ендпоинту, только добавляем идентификатор уязвимости. Пример: https://127.0.0.1:3443/api/v1/vulnerabilities/3339540470580643701

1715271660367.png



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

Bash: Скопировать в буфер обмена
Код:
curl -X PUT https://127.0.0.1:3443/api/v1/vulnerabilities/{vuln_id}/status \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-Auth: API_KEY'

Body
JSON: Скопировать в буфер обмена
Код:
{
    "status": "fixed"
}

Например: https://localhost:3443/api/v1/vulnerabilities/3352451120738862639/status

Скрипт автоматизации на Python
Код достаточно простой. Конечно же, не претендующий на идеальность/универсальность или какие-то другие варианты. Более того, я в целом не часто использую Python, это хорошо видно по неказистым конструкциям, а так же по абсолютному непониманию, как в Python правильно бросить исключение и правильно его обработать)))) Но похоже в ИБ это самый используемый язык, поэтому решил писать на нем.

В общем, воспринимайте, как просто одну из возможных реализаций с текстовым файлом на входе. Напомню, что я максимально пытался избежать любых сопутствующих тем, но все же решил оставить один из вариантов реализации очереди запуска сканов sqlmap, чтобы скрипт можно было просто Скачать
View hidden content is available for registered users!
 
Сверху Снизу