📘

各種機能へアクセスしよう

に公開

初期設定

この記事を参考に、環境を整えてください。

この記事のゴール

Burp Suiteの各機能をExtention側から制御することです。
Loggingについては別枠で記事を書いているためそちらを御覧ください。

公式サンプルコード

JavaDoc

ニッチなものもあと少しありますが、省略します。

基本構成

特に指定することもありませんが、ここでいきなり過去の記事と変わっても意味がないのでリクエスト記事やレスポンス記事と同様の構成で行きたいと思います。
なお、この記事を読んでいる人はすでにBurp Suite本体もある程度触っていると思うので、各機能についての説明は割愛します。

状態がスイッチする機能

Interceptのようなスイッチするタイプは、isInterceptEnabled()のような現在の状態を確認する関数が用意されています。
そのため、if文で確認してから状態遷移をするという形になります。
時間と組み合わせることで、診断時間の終了時刻以降にIntercepterとTasks(Scan)からリクエストの送信をせき止める。みたいな使い方ができます。

Intercepter

Burp SuiteのProxy機能の門番であるこの機能を制御するためには、以下の3つのAPIを使用します。

  • isInterceptEnabled()
  • disableIntercept()
  • enableIntercept()

isInterceptEnabled()は、Interceptが起動していてリクエスト・レスポンスが止まっている状態をTrue、そうでない場合はFalseを返します。

class httpRequestResponseHandler implements HttpHandler {
    private final Logging logging;
    private final JsonUtils jsonUtils;
    private final MontoyaApi api;

    public httpRequestResponseHandler(MontoyaApi api) {
        this.logging = api.logging();
        this.jsonUtils = api.utilities().jsonUtils();
        this.api = api;
    }

    @Override
    public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
        Annotations annotations = requestToBeSent.annotations();

        if (api.proxy().isInterceptEnabled()) {
            api.proxy().disableIntercept();
        } else {
            api.proxy().enableIntercept();
        }

        return continueWith(requestToBeSent, annotations);
    }
// ...レスポンス処理を省略
}

TaskExecutionEngine

Burp SuiteのDashboardタブに存在する、Tasks部分の処理を制御する部分のことです。

使用するAPIは2つです。getState()は先のisInterceptEnabled()と同様の位置づけになります。

  • getState()
  • setState(TaskExecutionEngineState)
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
    Annotations annotations = requestToBeSent.annotations();

    // Tasksが動作している状態だったら。
    if (api.burpSuite().taskExecutionEngine().getState() != TaskExecutionEngineState.RUNNING) {
        // Tasks全体を一時停止させる。
        api.burpSuite().taskExecutionEngine().setState(TaskExecutionEngineState.PAUSED);
    } else {
        // Tasks全体を再開(実行状態)させる。
        api.burpSuite().taskExecutionEngine().setState(TaskExecutionEngineState.RUNNING);
    }

    return continueWith(requestToBeSent, annotations);
}

受け身型の機能

Burp Suiteの機能の多くはこっち側で、RepeaterやIntruderなどに代表されます。送られてきたHttpリクエストや一部の文字列に対してその機能を使うものです。
いくつか条件を指定して、その条件に当てはまるものを対象の機能に送信したあと、Burp Suite上で対象の機能を動かして確認する。という流れになります。
だいたい同じような形で説明文も同一になりがちなので、省略して記載していきます。

Comparer

差分比較までをExtentionで行うことはできず、Comparerに対象のデータを送信するのみになります。
使用するAPIは以下のとおりです。

  • sendToComparer(ByteArray)

リクエスト・レスポンスの両方に対応しているため、ByteArray型に変換して送信してください。

@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
    Annotations annotations = requestToBeSent.annotations();

    // ByteArray型に変換したあとで送信する。
    ByteArray byteArray = requestToBeSent.toByteArray();
    api.comparer().sendToComparer(byteArray);

    return continueWith(requestToBeSent, annotations);
}

Decoder

これもあとは画面で確認するタイプです。デコードやエンコードもできずただ値を送るのみです。

  • sendToDecoder(ByteArray)
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
    Annotations annotations = requestToBeSent.annotations();

    // ByteArray型に変換したあとで送信する。
    ByteArray byteArray = requestToBeSent.toByteArray();
    api.decoder().sendToDecoder(byteArray);

    return continueWith(requestToBeSent, annotations);
}

Intruder

Community版でもよく使用される機能の一つです。
基本的に使いたいAPIを先に紹介します。

  • sendToIntruder(HttpRequest)
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
    Annotations annotations = requestToBeSent.annotations();

    api.intruder().sendToIntruder(requestToBeSent);

    return continueWith(requestToBeSent, annotations);
}

IntruderのPayload周りもExtentionでやりたい!という方は以下のAPIを使用してください。

  • registerPayloadGeneratorProvider(PayloadGeneratorProvider)
  • registerPayloadProcessor(PayloadProcessor)

このコードは、公式サンプルコード「Custom Intruder Payloads Example Extension」を参考に書いています。

@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
    Annotations annotations = requestToBeSent.annotations();

    PayloadProcessor payloadProcessor = new PayloadProcessor() {
        @Override
        public String displayName() {
            String Name = "PayloadDisplayName";
            return Name;
        }
        @Override
        public PayloadProcessingResult processPayload(PayloadData payloadData) {
            return usePayload(payloadData.currentPayload());
        }
    };

    api.intruder().registerPayloadProcessor(payloadProcessor);

    return continueWith(requestToBeSent, annotations);
}

Organizer

  • sendToOrganizer(HttpRequest)
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
    Annotations annotations = requestToBeSent.annotations();

    api.organizer().sendToOrganizer(requestToBeSent);
    
    return continueWith(requestToBeSent, annotations);
}

Repeater

  • sendToRepeater(HttpRequest)
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
    Annotations annotations = requestToBeSent.annotations();

    api.repeater().sendToRepeater(requestToBeSent);

    return continueWith(requestToBeSent, annotations);
}

Scanner(Pro版のみ)

2025年5月20日現在の最新バージョンv2025.5において、カスタムスキャンコンフィグを使用してのスキャンはできません。
アクセスすることができるのはデフォルトのPassive ScanとActive Scanの2つのみです。
後々はカスタムスキャンコンフィグを使用してのScanができるようになるみたいなので、更新かかったらこの記事も更新します。

使用するAPIは以下のとおりです。

  • api.scanner().startAudit(AuditConfiguration)
  • AuditConfiguration.auditconfiguration(BuiltInAuditConfiguration)
  • audit.addRequest(HttpRequest)
  • api.scanner().registerAuditIssueHandler(issue ->{})
  • issue.name()

このコードでは、Extentionに流れてきたリクエストがスコープ内かつScanner以外から流れてきているリクエストの場合に、Scannerに追加しています。
実用化するには、そもそもHttp Handlerとは独立したクラスで宣言したあと、登録するリクエストの重複チェックなどを行う必要があります。
このあたりの細かい部分は別記事で紹介していこうと思います。

class httpRequestResponseHandler implements HttpHandler {
    private final Logging logging;
    private final MontoyaApi api;
    private final Audit audit;

    public httpRequestResponseHandler(MontoyaApi api) {
        this.logging = api.logging();
        this.api = api;
        // 新しくTasksにActive Scanを追加する。
        this.audit = api.scanner().startAudit(
                AuditConfiguration.auditConfiguration(BuiltInAuditConfiguration.LEGACY_PASSIVE_AUDIT_CHECKS));
    }

    @Override
    public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent){
        Annotations annotations = requestToBeSent.annotations();

        // スコープ内かつ送信元がScannerではないものを対象とする。
        if (requestToBeSent.isInScope() && !requestToBeSent.toolSource().isFromTool(ToolType.SCANNER)) {
            // パラメータがあるリクエストを対象とする。
            if (requestToBeSent.hasParameters()) {
                // 上で宣言したActive Scanにリクエストを追加する。
                audit.addRequest(requestToBeSent);
            }
        }
        // Active Scanで新しく発見されたIssueを取得する(大量に表示される)。
        api.scanner().registerAuditIssueHandler(issue ->{
            logging.logToOutput(issue.name());
        });
        return continueWith(requestToBeSent, annotations);
    }
}

SiteMap


Targetタブで確認できるSitemapに関するAPIです。このAPIでは登録と参照を行うことができますが、削除を行うことはできません。削除はBurp SuiteのGUI上からのみ行うことができます。
APIではリクエスト・レスポンスの登録とIssueの登録のどちらも行うことができます。
Scannerで出力されたものは自動的に登録されますが、CustomScannerを使用してExtentionで独自に判定したものに関しては手動でAuditIssueを作成してSiteMapに追加する必要があります。

使用するAPIは以下のとおりです。

  • api.siteMap()
  • siteMap.requestResponses()
  • SiteMapFilter.prefixFilter("URL")
  • siteMap.issues()
  • siteMap.add(httpRequestResponse)

SiteMapFilter.prefixFilter("URL")で使用するprefixはURLの前方一致なので、https://からそのまま記載するかhttpRequest.url()などから取得した値を使用するなどの方法で入力することができます。

package org.httpRequestResponseHandler;

import java.util.List;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.core.Annotations;
import burp.api.montoya.core.ToolType;
import burp.api.montoya.http.handler.*;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.logging.Logging;
import burp.api.montoya.scanner.audit.issues.AuditIssue;
import burp.api.montoya.scanner.audit.issues.AuditIssueConfidence;
import burp.api.montoya.scanner.audit.issues.AuditIssueSeverity;
import burp.api.montoya.sitemap.SiteMap;
import burp.api.montoya.sitemap.SiteMapFilter;
import static burp.api.montoya.http.handler.RequestToBeSentAction.continueWith;
import static burp.api.montoya.http.handler.ResponseReceivedAction.continueWith;

class httpRequestResponseHandler implements HttpHandler {
    private final Logging logging;
    private final MontoyaApi api;
    private final SiteMap siteMap;

    public httpRequestResponseHandler(MontoyaApi api) {
        this.logging = api.logging();
        this.api = api;
        this.siteMap = api.siteMap();
    }

    @Override
    public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
        Annotations annotations = requestToBeSent.annotations();
        // リクエストがスコープ内かどうかを判定する。
        if (requestToBeSent.isInScope() && !requestToBeSent.toolSource().isFromTool(ToolType.SCANNER)) {

            // SiteMap上に存在するリクエスト・レスポンスをすべて取得する。
            List<HttpRequestResponse> listhHttpRequestResponses = siteMap.requestResponses();
            // SiteMap上に存在するリクエスト・レスポンスのうちFiterに引っかかるものをすべて取得する。
            List<HttpRequestResponse> listhHttpRequestResponses2 = siteMap
                    .requestResponses(SiteMapFilter.prefixFilter("https://assessment-api.proactivedefense.jp"));
            for (HttpRequestResponse requestResponse : listhHttpRequestResponses2) {
                logging.logToOutput("HttpRequestResponse : " + requestResponse.request().url());
            }

            // Sitemap上に存在するすべてのIssuesを取得する。
            List<AuditIssue> lAuditIssues = siteMap.issues();
            // Sitemap上に存在するIssuesのうち、Filterに引っかかるものをすべて取得する。
            List<AuditIssue> lAuditIssues2 = siteMap
                    .issues(SiteMapFilter.prefixFilter("https://assessment-api.proactivedefense.jp/"));
            for (AuditIssue auditIssue : lAuditIssues2) {
                // logging.logToOutput("AuditIssue : " + auditIssue.detail());
            }
        }
        return continueWith(requestToBeSent, annotations);
    }

    @Override
    public ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived responseReceived) {
        Annotations annotations = responseReceived.annotations();

        // レスポンスに紐づくリクエストを取得する。
        HttpRequest httpRequest = responseReceived.initiatingRequest();
        HttpRequestResponse httpRequestResponse = HttpRequestResponse.httpRequestResponse(httpRequest,
                responseReceived);
        // SiteMapにリクエスト・レスポンスの追加をする。
        siteMap.add(httpRequestResponse);

        // Audit Issueを新しく作ってSitemapに追加する。
        final AuditIssue auditIssue = AuditIssue.auditIssue("TEST FOR ADD", "TEST DETAIL", "null",
                "https://assessment-api.proactivedefense.jp/api/getMemo", AuditIssueSeverity.INFORMATION,
                AuditIssueConfidence.CERTAIN, "TEST BACKGROUND", "TEST REMEDIATION BACKGROUND",
                AuditIssueSeverity.FALSE_POSITIVE, httpRequestResponse);
        siteMap.add(auditIssue);

        return continueWith(responseReceived, annotations);
    }

}

実行すると、Contentsに新しく追加されたRequestResponseの組と、そこに追加されたIssue「TEST FOR ADD」が確認できます。
また、現状Sitemapに登録されているリクエスト・レスポンスの組を取得した結果が以下の画像のようになります。

おわり。

Discussion