この記事では、非プログラマがBurpSuiteの拡張機能を開発するためAPI文書と格闘した手順を解説します。ペネトレーションテスター/脆弱性診断士としてある程度プログラミング言語は分かるけれども、APIの文書とかを見てもさっぱりわからない...!という人の参考になれば幸いです。
# 0. 参考サイトおよび想定読者
いきなりではありますが、筆者は主に下記の2つを参考にして拡張機能を書き始めました。
1. Burp Extension Development:
- Cyber Menterによる拡張機能開発の入門動画で、非常にわかりやすい内容になっています。
2. Montoya-APIのJavadoc:
筆者は、仕事上プログラミングは効率化のために見よう見まねで使ったものはあるものの、APIなどのドキュメントを読むことはほぼ無く、拡張機能の開発に当たっては上記の1は問題なく理解できるが、自分がやりたいことのために2をどのように使えばいいのか分からない、という状態でした。
従って、本稿の想定読者としても同じような状況の方を想定しています。
# 1. 開発環境の準備
開発環境の準備方法については、参考資料の1が非常に詳しいため、そちらを参照ください。大まかな流れとしては、
1. Java JDKのインストール(バージョン21以下である必要がある)
sudo apt install openjdk-21-jdk
2. InteliJ Community Editionのインストール
の2点となります。
なお、BurpSuite本体のバージョンが古いと正しく動作しない場合があるので、適宜アップデートをしておきましょう。
# 2. プロジェクトの作成
早速、拡張機能を作成していきます。引き続き参考資料1の内容を簡単に記載しておきます。
まず、新規プロジェクトの作成を行います。ここでは、例として「自分が登録したパスワードがHTTPレスポンス中に現れたらアラートを立てる」という拡張機能を作ることとし、プロジェクト名をClearTextPasswdFinderとしています。さらに、Language: Java, Build System: Maven, JDK: JDK21とします。
次に、pom.xmlに下記のdependency情報を追記します。これにより、プロジェクトがmontoya-APIを参照し、Burpsuiteの各機能にアクセス出来るようになるようです。
```xml
<dependencies>
<dependency>
<groupId>net.portswigger.burp.extensions</groupId>
<artifactId>montoya-api</artifactId>
<version>LATEST</version>
</dependency>
</dependencies>
```
dependencyを追記すると、画面右上の方に、青地のmに更新マークのついたボタンが現れるので、こちらをクリックします。
次に、File>Project Structure>Artifacts>+ボタン>Add Jar>From Modulesと進み、OKボタンを押し、さらにInclude in project buildのチェックボックスにチェックを入れてOKボタンを押します。
これでプロジェクトの作成は完了です。
# 3. 拡張機能コードの記述
いよいよ、拡張機能の開発に入ります。参考資料の1をベースにしつつ、API文書を使ってどうやりたいことを実現するのか、ということを中心に解説します。
まず、src>main>java>右クリック>New>Java classから、MAPIというクラスを作成します。
このクラスは、シングルトンクラスとして、拡張機能実行時に受け取るMontoyaAPIオブジェクトを保持しておく役割を果たします。(詳しくは参考資料の1を参照ください。)
```java
import burp.api.montoya.MontoyaApi;
public class MAPI {
private static MontoyaApi INSTANCE;
private MAPI(){}
public static void initialize(MontoyaApi api){
if (INSTANCE == null){
INSTANCE = api;
}
}
public static MontoyaApi getAPI(){
return INSTANCE;
}
}
```
次に、BurpExtensionクラスをimplementしたClearTextPasswdFinderというクラスを作成します。Burpsuite上で拡張機能を読み込むと、このinitializeメソッドが実行されることになるので、基本的な情報をここに記載しておきます。ここまでは拡張機能を作る際のテンプレ部分となります。
```java
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
public class ClearTextPasswdFinder implements BurpExtension {
@Override
public void initialize(MontoyaApi montoyaApi) {
MAPI.initialize(montoyaApi);
MAPI.getAPI().extension().setName("Cleartext Password Finder");
String password = "c56kpyvMs!";
MAPI.getAPI().logging().logToOutput("[*] Function:It looks for password \""+password+"\" in http responses.");
}
}
```
続いて、具体的な拡張機能の中身を作成していきます。
まず、レスポンスの中身を分析するコードを書きますが、参考資料1によれば、HttpHandlerというものを作成し、APIに登録することでHTTP通信を拡張機能から見ることができるようになるようです。
そこで、とりあえず同様の内容をinitializeの中に書いてみます。クラス名は仮にHttpAnalyzerとし、grep対象のパスワードも保管しています。(パスワードのハードコーディングになるので、学習用以外では避けた方が賢明です。)
すると、上記の用にHttpAnalyzer部分が赤くハイライトされます。カーソルを合わせてみると、当然ながら「HttpAnalyzerというシンボルを解決できません(=クラスが見つかりません)」というエラーメッセージが出てきます。そこで、Alt+Enterを押すと解決策がいくつか表示されますので、ここではHttpAnalyzerクラスの作成を選択します。
HttpAnalyzerクラスが作成されると、今度はhandler部分に赤い波線が引かれます。同様にエラーの中身ををみてみると、HttpHandlerクラスを受けとるはずのところにHttpAnalyzerクラスを渡している事が原因であることが分かります。再度Alt+Enterとすると、HttpAnalyzerにおいてHttpHandlerをImplementすればいい、ということがわかりますので、そのまま実行します。
Implementしてみると、2つのメソッドが追加され、メソッド名からそれぞれリクエストとレスポンスに関するアクションを定義するものであると推測できます。
ここでは、レスポンスを分析したいので、handleHttpResponseReceivedメソッドを編集する必要がありそうです。[handleHttpResponseReceivedメソッドの解説](https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/handler/HttpHandler.html)を見ても、どうすればレスポンスを分析できるのか分かりませんが、その引数である[httpResponseReceived](https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/handler/HttpResponseReceived.html)を参照してみると、Cookie()やbody()などのメソッドが用意されており、名称どおりこれがレスポンスを表すオブジェクトとなっているようです。
まず、スコープ内のアイテムに限定して分析対象としたいので、レスポンスに対応したリクエストがどこに送られているのかを把握する方法を捜します。
[httpResponseReceived](https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/handler/HttpResponseReceived.html)のドキュメントを見てみると、スコープに関連しそうなメソッドはありませんが、冒頭に「ButpのhttpResponseに対応するhttpRequestやAnnotation, ToolSourceを取得する機能を持たせたもの」と書いてあり、実際にMethod Summaryの項目を見ていくと、initiatingRequest()というメソッドが存在し、レスポンスの元となったHttpRequestを取得できる事がわかります。
そこで、次に[HttpRequest](https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/message/requests/HttpRequest.html)のドキュメントを参照すると、booleanを返すisInScope()というメソッドが存在することがわかります。
従って、下記の用に、レスポンスに対応するリクエストオブジェクトを取得し、さらにそのオブジェクトが持つisInScope関数を呼び出すことで、レスポンスが分析対象になっているかを判断することが出来ます。
続いて、レスポンスがパスワードを含むかをチェックしていきます。
パスワードの使用をチェックするには、そもそも使用しているpasswordを知る必要があるので、コンストラクタを作り、そこでpasswordを保管するようにしておきます。
具体的には、HttpAnalyzer上でAlt+Insertを押してGenerateメニューを開き、Constructorを選択すると自動でコンストラクタを作成してくれますので、その中でパスワードを受け取って保管するようにしておきます。
併せてClearTextPasswdFinderのinitialize()メソッドでもHttpAnalyzerのコンストラクタにpasswordを渡すように編集します。
レスポンス中のパスワードの検知に戻ります。[httpResponseReceived](https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/handler/HttpResponseReceived.html)のAPIドキュメントを見ると、その中にcontains(String searchTerm, boolean caseSensitive)というメソッドがあります。同メソッドの解説には「HTTPメッセージに特定のsearchTermが含まれているかを確認する」とあり、今回の目的に合致しそうです。
検知したものをlogへアウトプットするために、MAPIからログ機能を呼び出します。ログにはURLを含めたいので、先ほどのinitiatingRequestメソッドを再度活用し、[HttpRequest](https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/message/requests/HttpRequest.html)のurl()メソッドからリクエストのURLを取得、出力するように作成します。
# 4. テスト
一旦、これにて「自分が登録したパスワードがHTTPレスポンス中に現れたらアラートを立てる」という機能は完成したはずですので、テストを行います。
まず、InteliJ上でCtrl+S(保存), Ctrl+F9(ビルド)を押し、ビルドされたjarファイルをBurpsuiteに読み込みます。
次に、webサーバーでパスワードを記入したファイルをサーブしておきます。
続いて、Burpsuiteのproxyと開発した拡張機能をonにした状態でhttp://localhost/test.htmlにアクセスすると、拡張機能のOutputタブにパスワードが検知された旨が表示されて、拡張機能が正常に動作している事が確認できます。
# 5. おわりに
以上、筆者が拡張機能を作る際の流れを大まかにまとめました。
今回の開発を通じて、APIドキュメントの読み方が理解できるようになり、できることの幅が大きく広がったと感じています。初めは難解に思えたAPIドキュメントも、実際に手を動かしてみることで、その使い方や可能性をより深く理解することができました。読者の方々の参考になっていれば幸いです。
Comments