Skip to content

Написание Java-скриптов ​

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

Для проверки и запуска нужен Burp с JDK 21 или новее. Выбор каталога и действия запуска описаны в очереди задач.

Файл и точка входа ​

Создайте текстовый файл UTF-8 HelloScript.java:

java
import ru.webvulnfinder.script.AutomationScript;
import ru.webvulnfinder.script.ScriptContext;
import java.time.Duration;

public final class HelloScript implements AutomationScript {
    public HelloScript() { 
        
    }

    @Override
    public void run(ScriptContext context) throws Exception {
        for (int iteration = 1; iteration <= 3; iteration++) {
            context.log("Итерация " + iteration);
            context.sleep(Duration.ofSeconds(1));
        }
    }
}

При создании файла вне редактора имя публичного класса должно совпадать с именем файла; проверка и запуск текущего буфера в форме определяют класс из кода. Класс реализует AutomationScript, имеет публичный конструктор без аргументов и метод public void run(ScriptContext context) throws Exception. Объявление package не используется.

При запуске создаётся новый экземпляр и один раз вызывается run. Переменные, поля, собственные методы, условия, циклы и стандартная библиотека Java работают обычным образом. Для состояния запуска используйте локальные переменные и поля экземпляра. Изменённый файл перечитывается при следующем запуске; уже выполняющийся экземпляр продолжает работать со старым кодом.

Поддерживаемый интерфейс состоит из AutomationScript и ScriptContext пакета ru.webvulnfinder.script и HTTP-типов Montoya HttpRequest и HttpResponse. Для проверки и запуска внутри Burp эти типы доступны автоматически.

ScriptContext ​

В run передаётся контекст конкретного запуска. ScriptContext.VERSION равен 1.

МетодНазначение
HttpResponse send(String service, String color, String request, Duration timeout) throws ExceptionОтправить полный HTTP-запрос через Burp и получить ответ.
HttpRequest request(UUID requestId)Получить сохранённый запрос текущего проекта по UUID с адресом сервиса, заголовками и телом. Недоступный идентификатор вызывает исключение.
HttpResponse send(HttpRequest request, String color, Duration timeout) throws ExceptionОтправить структурированный запрос с применением выбранной сессии.
String bodyText(HttpResponse response)Прочитать тело ответа как UTF-8 без bodyToString().
Map<String, String> variables(String service, String color)Прочитать неизменяемый снимок пользовательских переменных указанной сессии; при их отсутствии карта пустая.
Object json(String text)Разобрать JSON в Map, List, строки, числа, Boolean и null. Некорректный JSON вызывает исключение.
void sleep(Duration delay) throws InterruptedExceptionПодождать неотрицательный интервал с поддержкой отмены.
void checkCancelled()Проверить отмену, прерывание и смену проекта; при отмене выбросить CancellationException.
void log(String message)Добавить строку в журнал этого запуска.
void notifyUser(String message)Отправить непустое сообщение пользователю в Telegram через Backend и записать его в журнал. Вызов ожидает обработки Backend; прочтение сообщения не подтверждается.
void stopAutomation(String reason)Выключить автоисполнение исследования и ИИ и записать непустую причину в журнал скрипта.
void startAutomation()Явно включить или продолжить исследование и ИИ через обычные средства и проверки запуска.

Запросы и сессии ​

service — схема, хост и при необходимости порт: https://example.org:8443. Путь и query задаются в самом запросе. В service нельзя помещать учётные данные, query или fragment.

request — полный текст запроса. Переводы строк записываются как \r\n; заголовки отделяются от тела пустой строкой:

java
String request = "GET /api/profile HTTP/1.1\r\n"
        + "Host: example.org\r\n"
        + "Cookie: sid=placeholder\r\n"
        + "Authorization: Bearer placeholder\r\n"
        + "\r\n";
var response = context.send("https://example.org", "blue", request,
        Duration.ofSeconds(30));

Адрес, путь и поля здесь условные: замените их по протоколу своего сервиса. Для непустого color используется сессия точно этого сервиса и цвета. Контекст обновляет присутствующие в запросе сессионные cookie и заголовки, добавляет цвет PwnFox и настроенный маркер захвата. Новые значения из обмена обрабатываются действующими правилами захвата проекта.

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

Таймаут — от 1 до 300000 мс. Он ограничивает чтение ответа средствами Burp. При отсутствии ответа send выбрасывает исключение. Отмена проверяется до и после обмена; уже начатый запрос может завершиться или дождаться таймаута прежде, чем скрипт остановится.

Запрос по идентификатору ​

request(UUID) возвращает структурированный burp.api.montoya.http.message.requests.HttpRequest из истории текущего проекта. Скопируйте UUID нужного запроса из проекта. Это идентификатор запроса WebVulnFinder, а не номер строки HTTP history Burp. Запрос другого проекта или недоступный UUID вызывает исключение.

java
var base = context.request(java.util.UUID.fromString("11111111-1111-1111-1111-111111111111"));
// Можно отправить base сразу или создать изменённый запрос:
var request = base.withPath("/api/session/refresh")
        .withHeader("X-Requested-With", "XMLHttpRequest");
var response = context.send(request, "blue", Duration.ofSeconds(30));

Методы withPath, withHeader, withBody создают изменённый запрос; исходный base остаётся доступен для повторного использования. httpService(), method(), path(), headers() и body() позволяют читать его части. Адрес берётся из самого запроса. Для изменения текстового тела используйте, например, base.withBody("{\"refresh\":true}"); для бинарного — перегрузку с ByteArray.

Шаблон восстанавливается из данных, сохранённых в истории: исключённые правилами сохранения заголовки и cookie отсутствуют, сохранённые значения могут быть усечены. Проверьте нужные поля и при необходимости добавьте их через withHeader. Байты сохранённого тела передаются без преобразования в строку. Чтение шаблона само запрос не отправляет; при send применяются текущие значения выбранной сессии.

Чтение ответа ​

Обе перегрузки send возвращают структурированный burp.api.montoya.http.message.responses.HttpResponse Montoya:

МетодЗначение
short statusCode()HTTP-статус.
List<HttpHeader> headers()Заголовки, в том числе повторяющиеся; у каждого доступны name() и value().
String headerValue(String name)Значение заголовка по имени.
ByteArray body()Исходное тело ответа. Для бинарной обработки доступны body().getBytes().

Для обычного чтения текста используйте context.bodyText(response): он читает тело как UTF-8 напрямую, без проблемного response.bodyToString(). Строку можно разбирать обычными операциями Java и java.util.regex. Если конкретный протокол требует другую кодировку, она доступна средствами Java: new String(response.body().getBytes(), java.nio.charset.Charset.forName("windows-1251")).

JSON разбирается так:

java
Object parsed = context.json(context.bodyText(response));
if (!(parsed instanceof java.util.Map<?, ?> data)) {
    throw new Exception("Ожидался JSON-объект");
}
Object token = data.get("token");
if (!(token instanceof String value) || value.isBlank()) {
    throw new Exception("Отсутствует ожидаемый token");
}
// value можно использовать в следующем запросе.

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

Сессионные переменные ​

variables(service, color) возвращает снимок пользовательских переменных из правил захвата проекта без зависимости от Hackvertor. Имена должны соответствовать настройкам проекта:

java
String csrf = context.variables("https://example.org", "blue").get("csrfToken");
if (csrf == null || csrf.isBlank()) {
    context.stopAutomation("Не удалось получить CSRF-токен");
    context.notifyUser("Проверьте обновление авторизации");
    return;
}
String encoded = java.net.URLEncoder.encode(csrf, java.nio.charset.StandardCharsets.UTF_8);
String nextPath = "/api/refresh?csrfToken=" + encoded;

Перечитайте переменные после запроса, если следующий шаг должен использовать свежий захват. Подстановку в путь и тело вы пишете на Java; автоматической замены ${...} нет. Cookie и заголовки применяются отдельно, как описано выше.

Периодические действия и частичный сбой ​

Интервалы, условия успеха и повторы задаёт автор. Например, файл RefreshSession.java:

java
import ru.webvulnfinder.script.AutomationScript;
import ru.webvulnfinder.script.ScriptContext;
import java.time.Duration;
import java.util.Map;

public final class RefreshSession implements AutomationScript {
    public RefreshSession() { }

    @Override
    public void run(ScriptContext context) throws Exception {
        String service = "https://example.org";
        String request = "POST /api/session/refresh HTTP/1.1\r\n"
                + "Host: example.org\r\n"
                + "Cookie: refresh_token=placeholder\r\n"
                + "Content-Length: 0\r\n\r\n";
        while (true) {
            context.checkCancelled();
            var response = context.send(service, "blue", request, Duration.ofSeconds(30));
            boolean success = response.statusCode() == 200
                    && context.json(context.bodyText(response)) instanceof Map<?, ?> data
                    && Boolean.TRUE.equals(data.get("authenticated"));
            if (!success) {
                String reason = "Не подтверждено обновление синей сессии";
                context.stopAutomation(reason);
                context.notifyUser(reason);
                return;
            }
            context.log("Обновление подтверждено");
            context.sleep(Duration.ofMinutes(10));
        }
    }
}

Здесь путь, cookie и authenticated нужно заменить по своему протоколу. Проверка частичного сбоя может включать несколько запросов и условий. Повтор при определённом статусе, его предел и дальнейшее действие также задаются в Java-коде. Для ожидания между попытками используйте sleep.

Журнал и управление автоматизацией ​

log пишет в журнал строки скрипта. notifyUser отправляет сообщение в Telegram текущему пользователю через настроенный Backend, с категорией INFO и заголовком «Уведомление Java-скрипта». Всплывающее окно Burp не открывается. При временной недоступности Telegram сообщение сохраняется для последующей доставки. Ошибка обращения к Backend передаётся вызывающему коду; подтверждение доставки Telegram контракт не возвращает. Записывайте названия шагов и итоги проверок; не включайте в сообщения пароли, cookie, токены и чувствительные тела ответов.

stopAutomation(reason) использует существующую остановку автоисполнения исследования и ИИ. Текущий ИИ-запуск завершается, следующие не запускаются. Ожидающие задачи остаются в таблицах для последующего запуска. Сам скрипт и обычные задачи общей очереди продолжают работать.

Возобновить работу можно через интерфейс либо явным startAutomation(). Запуск использует действующие проверки сессий и готовности исследования. Завершение скрипта, новый токен и ошибка сами работу не возобновляют. Необработанное исключение отмечает скрипт как ошибочный, но само по себе исследование и ИИ не останавливает. Если определённая ошибка требует остановки, обработайте её и вызовите stopAutomation.

Отмена и проверка ​

Запуск виден отдельной строкой в очереди и выполняется независимо от её обычных задач. Пауза очереди не приостанавливает скрипт; используйте отмену его строки. Закрытие панели не отменяет запуск. При смене проекта и выгрузке расширения скрипты отменяются. Одновременно поддерживается до 16 независимых запусков.

В длительных собственных вычислениях вызывайте checkCancelled(). Контекст выбрасывает CancellationException, а sleep также может выбросить InterruptedException; не подавляйте их продолжением бесконечного цикла. Произвольный Java-код, игнорирующий прерывание, нельзя безопасно остановить принудительно внутри Burp. Скрипты — доверенный локальный код с доступом к среде JVM.

Кнопка «Проверить» в форме скрипта компилирует текущий текст редактора и проверяет точку входа, не выполняя статические инициализаторы, конструктор и run. Ошибки содержат файл, строку, столбец и код диагностики. Компиляция не доказывает правильность запросов и условий успеха сервиса.

Для проверки вне Burp можно использовать JDK и JAR расширения:

sh
javac --release 21 -proc:none -encoding UTF-8 -classpath '/path/to/extension.jar:/path/to/montoya-api-2025.8.jar' -d '/tmp/script-check' '/scripts/HelloScript.java'

Для этой команды нужен также JAR Montoya API, соответствующий расширению; в Windows разделитель classpath — ;. Встроенная проверка в Burp добавляет API автоматически. Команда компилирует файл без запуска. Версия 1 контракта задаёт описанные сигнатуры и формат файла; код скрипта должен опираться на них.

Подготовка скрипта через Codex ​

В диалоге или терминальной сессии Codex, открытой из Burp, включите инструмент validate_java_script. Его описание содержит полный контракт написания Java-скриптов. Codex может подготовить вариант, проверить компиляцию, исправить ошибки и повторить проверку без доступа к исходникам расширения.

У инструмента один аргумент source — полный Java-код строкой. Имя публичного класса определяется из кода автоматически. Путь к файлу и имя файла передавать не нужно. Проверка создаёт временный исходник, компилирует его и проверяет точку входа тем же способом, что кнопка «Проверить» в форме скрипта Burp, затем удаляет временные файлы.

Результат содержит valid и diagnostics. При успехе valid: true, диагностика пустая. При ошибке valid: false; ошибки компиляции содержат имя класса/файла, строку, столбец и код диагностики. Статические инициализаторы, конструктор и run не выполняются. Проверка не сохраняет готовый скрипт в каталог пользователя и не проверяет правильность протокола сервиса.

Опишите нужную задачу и укажите идентификаторы запросов или другие данные проекта. Назначение скрипта может быть любым в пределах описанного API: периодические HTTP-действия, проверки, обработка ответов, уведомления и управление процессами. Например: «Напиши Java-скрипт, который раз в пять минут выполняет запрос по UUID …, проверяет JSON-ответ и сообщает об изменении в Telegram. Проверь код через validate_java_script и исправь ошибки компиляции».

Используйте WebVulnFinder только в согласованном scope.