🙌

HTTPリクエストの値を追加・削除・編集しよう

に公開

初期設定

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

この記事のゴール

Burp Suiteを流れるHTTPリクエストの中の要素を追加・削除・編集することです。自由に値を行き来させたいときはあると思うので、その一助になればと思っています。
主に、レスポンスで得た値をリクエストにくっつけるという形になります。(もちろんほかもある)

公式サンプルコード

公式サンプルコードはとても優秀なので、公式のコードをオーバーライドする形で記載していきます。

JavaDoc

取得できるリクエスト・レスポンスの中身

リクエスト・レスポンスの中身は基本的に全て追加・削除・編集できると考えて良いです。
Bodyはもちろん、Headerやパラメータ、クエリなどおよそ追加・削除・編集したいと考えるものはすべてできると考えていいでしょう。

基本構成

リクエスト取得の記事レスポンスの記事と同じです。今回は基本的にリクエスト部分のみを掲載していきます。

リクエストを取得する前に(再掲)

リクエスト取得の記事でも記載しましたが、かなり大事なのでもう一度記載しておきます。以降は記事の長さを短くするために handleHttpRequestToBeSentメソッドのみの記載とします。その他はリクエスト取得の記事とだいたい同じです。

Scope範囲内であるかを判定する(再掲)

Burp Suiteにはスコープという機能があります。これは脆弱性診断対象サイト以外へのサイトへのリクエスト・レスポンスの改ざんを防ぐためにあります。
今回からリクエストやレスポンスに関しての処理を記載していきます。この記事では改ざんはしませんが、今後はそういう処理を書いて脆弱性診断をすることがあるかと思います。その際に万が一にもスコープ外のサイトへのリクエスト・レスポンスの改ざんが発生しないようにする必要があります。

そこで isInScope()を使用することで、Extention内でそのリクエストがスコープ内かどうかを判定してくれます。
基本的にスコープ内のリクエストに対してのみ、何かを行うような挙動をするようにしましょう。

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

        // リクエストがスコープ内かどうかを判定する。
        if(requestToBeSent.isInScope()){
            // リクエストをどうのこうのする処理を記述する。
        }
        return continueWith(requestToBeSent);
    }

リクエストヘッダを編集する

ヘッダの編集とボディの編集について共通して言えることですが、Burp Suiteを流れるリクエストそのものに対して追加・削除・編集をするわけではありません。
新しくリクエストのコピーを作成して、そのコピーに対して各作業を行ったあと、それをリクエストとして送信するという流れになります。

リクエストヘッダに新しい要素を追加する

何かの値を取得する部分については、過去の記事を参考にしてください。今回はCookieの値をヘッダにくっつけていこうと思います。

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

  • requestToBeSent.withAddedHeader("HeaderName", "Value")
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
    Annotations annotations = requestToBeSent.annotations();

    // リクエストのコピーを格納する変数を用意する。
    HttpRequest recreateRequest = requestToBeSent;

    // リクエストがスコープ内かどうかを判定する。
    if (requestToBeSent.isInScope()) {

        // 取得した値「cookieValue」に値があるか
        if (cookieValue != null) {

            // レスポンスで取得したCookieの内容をHeaderにくっつける。
            recreateRequest = requestToBeSent.withAddedHeader("cookieForBurp", cookieValue);
            // 送信時にログに吐かせて確認。
            logging.logToOutput("[Request] set Header CookieValue:" + cookieValue);
        }
    }
    return continueWith(recreateRequest,annotations);
}

実行した結果は以下のようになります。画像ではそのレスポンスから受け取ったような記載ですが、Cookieの値を固定にしているので厳密にはその前に受け取った別のレスポンスから取得しています。

ちなみにExtention側で追加・削除・編集を行った際には、HTTP Historyタブにはその痕跡は表示されません。確認したい場合は、自分でlogToOutput()を使って出力させるか、Loggerタブなどで確認するようにしましょう。

リクエストヘッダの要素を削除する

リクエストのいらない要素を削除していきましょう。正直これはあんまり使う部分はなさそうですが、こういうときに使うよ!っていう方はちょっと教えてください。
使用するAPIは以下のとおりです。

  • requestToBeSent.withRemovedHeader("HeaderName")
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
    Annotations annotations = requestToBeSent.annotations();

    // リクエストのコピーを格納する変数を用意する。
    HttpRequest recreateRequest = requestToBeSent;

    // リクエストがスコープ内かどうかを判定する。
    if (requestToBeSent.isInScope()) {

        // 取得した値「cookieValue」に値があるか
        if (cookieValue != null) {

            // ヘッダからUser-Agentを削除。
            recreateRequest = requestToBeSent.withRemovedHeader("X-Api-Key");
        }
    }
    return continueWith(recreateRequest,annotations);
}

実行した結果は以下のようになります。リクエストに必要なX-Api-Keyがなくなったので、上で通っていたはずのリクエストが通らなくなりましたね。

リクエストヘッダの要素を編集する

まぁまぁ使いたいときは多いんじゃないかなと思います。というのも、BAppにある汎用的なExtentionはどうしても細かいところまでは手が届かないことが多いからです。使っているExtentionが脆弱性診断をしている対象サイトの特性に合わないなどはよく聞く話ですね。

使用するAPIは以下のとおりです。ちなみに削除と追加の組み合わせでもできます。

  • requestToBeSent.withUpdatedHeader("HeaderName","Value")
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
    Annotations annotations = requestToBeSent.annotations();

    // リクエストのコピーを格納する変数を用意する。
    HttpRequest recreateRequest = requestToBeSent;

    // リクエストがスコープ内かどうかを判定する。
    if (requestToBeSent.isInScope()) {

        // 取得した値「cookieValue」に値があるか
        if (cookieValue != null) {

            // ヘッダのX-Api-Keyの値を更新。
            recreateRequest = requestToBeSent.withUpdatedHeader("X-Api-Key","UpdatedValue!!ByExtention");
        }
    }
    return continueWith(recreateRequest,annotations);
}

実行した結果は以下のようになります。値が編集された結果、削除のときと同様に通らなくなっています。

リクエストクエリの値を追加する。

編集するのは何もヘッダの部分だけではないですよね。GETリクエスト送信時にくっついているクエリパラメータもその一つです(ヘッダに内包されてるケド。細かいことはなし!)。
では、それも対象にとって行きましょう。

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

  • HttpParameter.urlParameter("ParameterName","Value")
  • requestToBeSent.withAddedParameters(HttpParamter)
  • recreateRequest.withAddedParameters(HttpParameter.urlParameter("ParameterName", "Value"))

今回はクエリパラメータの追加を対象に取っているためurlParamter()を採用していますが、この他にもボディパラメータを編集したいときにはbodyParamter()を、Cookieを編集したいときにはcookieParameter()を使うことができます。

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

    // リクエストのコピーを格納する変数を用意する。
    HttpRequest recreateRequest = requestToBeSent;

    // リクエストがスコープ内かどうかを判定する。
    if (requestToBeSent.isInScope()) {

        // パラメータ系をまとめて管理するListを作成する。
        List<HttpParameter> queryParameter = new ArrayList<HttpParameter>();
        // クエリパラメータはurlParameterで作っていれる。
        queryParameter.add(HttpParameter.urlParameter("ParameterFromList", "AddedParameterByExtention"));
        // あとは新しいリクエストにくっつけてドーン。
        recreateRequest = requestToBeSent.withAddedParameters(queryParameter);

        // 1つだけくっつけて送信したい場合はこういうのもあり。
        recreateRequest = recreateRequest.withAddedParameters(HttpParameter.urlParameter("Parameter", "AddedParameterByExtention"));
    }
    return continueWith(recreateRequest,annotations);
}

実行した結果は以下のようになります。リクエストクエリに新しく値が追加されていますね。

リクエストボディを編集する

リクエストボディを新しく追加する

使用するAPIは以下のとおりです。Burp SuiteのJsonUtilsを使用するとJavaでJSONを処理するときに必要なあれやこれやをする必要がないので楽ですね。以下の例にもありますが、newJsonの部分は以下のようにlocation : newJsonがJsonの体をなしているなら大丈夫みたいです。もちろんlocationには以前説明した記法が使えると思うので、試してみてください。

  • jsonUtils.add("Json","location","newJson")
  • recreateRequest.withBody("String")
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
    Annotations annotations = requestToBeSent.annotations();

    // リクエストのコピーを格納する変数を用意する。
    HttpRequest recreateRequest = requestToBeSent;

    // リクエストがスコープ内かどうかを判定する。
    if (requestToBeSent.isInScope()) {
        // JSONとしてパースできるか判定する。
        if (jsonUtils.isValidJson(requestToBeSent.bodyToString())) {
            // Body部分だけ取得。
            String json = requestToBeSent.bodyToString();
            // JSONの一番上の階層に "addParamter": "value" を追加する。
            recreateRequest = recreateRequest.withBody(jsonUtils.add(json, "addParamter", "'value'"));
        }
    }
    return continueWith(recreateRequest,annotations);
}

実行した結果は以下のとおりです。

ちなみに、以下のような書き方の場合はこうなります。

// JSONの一番上の階層に addParamter: ['valueA','valueB','valueC'] を追加する。
recreateRequest = recreateRequest.withBody(jsonUtils.add(json, "addParamter", "['valueA','valueB','valueC']"));

結果

また、この配列に値を付け足そうとするとこういう形になります。このときのcookieValueは変数名です。ゴリ押し感が半端ないですね。

// JSONの一番上の階層に addParamter: ['valueA','valueB','valueC'] を追加する。
json = jsonUtils.add(json, "addParamter", "['valueA','valueB','valueC']");
// "addParamter"の配列の一番最後に変数cookieValueの値を追加する。
recreateRequest = recreateRequest.withBody(jsonUtils.add(json, "addParamter.[]", "'"+cookieValue+"'"));

結果

リクエストボディの中身を削除する

値を削除するというよりかは、Key:valueのペアを削除することもあるためこういう書き方になります。
使用するAPIは以下のとおりです。

  • jsonUtils.remove("json", "location")
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
    Annotations annotations = requestToBeSent.annotations();

    // リクエストのコピーを格納する変数を用意する。
    HttpRequest recreateRequest = requestToBeSent;

    // リクエストがスコープ内かどうかを判定する。
    if (requestToBeSent.isInScope()) {
        // JSONとしてパースできるか判定する。
        if (jsonUtils.isValidJson(requestToBeSent.bodyToString())) {
            // Body部分だけ取得。
            String json = requestToBeSent.bodyToString();
            // uuidの部分を削除する。
            json = jsonUtils.remove(json, "uuid");

            recreateRequest = recreateRequest.withBody(json);
        }
    }
    return continueWith(recreateRequest,annotations);
}

実行した結果は以下のようになります。値が編集された結果、uuidのKey:valueのペアが削除されています。

リクエストボディの値を編集する

前に同じくやりましょう。uuidの値を編集して行きたいと思います。

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

  • jsonUtils.update("Json","location","newJson")
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
    Annotations annotations = requestToBeSent.annotations();

    // リクエストのコピーを格納する変数を用意する。
    HttpRequest recreateRequest = requestToBeSent;

    // リクエストがスコープ内かどうかを判定する。
    if (requestToBeSent.isInScope()) {
        // JSONとしてパースできるか判定する。
        if (jsonUtils.isValidJson(requestToBeSent.bodyToString())) {
            // Body部分だけ取得。
            String json = requestToBeSent.bodyToString();
            // uuidの値を更新する。
            json = jsonUtils.update(json, "uuid","'"+cookieValue+"'");

            recreateRequest = recreateRequest.withBody(json);
        }
    }
    return continueWith(recreateRequest,annotations);
}

実行した結果は以下のようになります。もともとのuuidの値から変わって、uuidらしさのかけらもない値になっています。

まとめ

リクエストヘッダ・ボディの編集をする記事でした。
リクエストヘッダは以下のAPIを使用して色々なことをやっていきます。

  • リクエストヘッダ追加
    • requestToBeSent.withAddedHeader("HeaderName", "Value")
  • リクエストヘッダ削除
    • requestToBeSent.withRemovedHeader("HeaderName")
  • リクエストヘッダ編集
    • requestToBeSent.withUpdatedHeader("HeaderName","Value")
  • クエリパラメータ追加
    • HttpParameter.urlParameter("ParameterName","Value")
    • requestToBeSent.withAddedParameters(HttpParamter)
    • recreateRequest.withAddedParameters(HttpParameter.urlParameter("ParameterName", "Value"))

リクエストボディは以下のAPIを使用しています。

  • リクエストボディへの要素の追加
    • jsonUtils.add("Json","location","newJson")
    • recreateRequest.withBody("String")
  • リクエストボディの要素の削除
    • jsonUtils.remove("json", "location")
  • リクエストボディの要素の編集
    • jsonUtils.update("Json","location","newJson")

Discussion