Тема
Написание 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 и исправь ошибки компиляции».