本サイトは、快適にご利用いただくためにクッキー(Cookie)を使用しております。
Cookieの使用に同意いただける場合は「同意する」ボタンを押してください。
なお本サイトのCookie使用については、「個人情報保護方針」をご覧ください。
Web診断に欠かせないWeb Proxyツールとして、Burp Suite、Fidder、OWASP ZAP等があります。
それぞれのツールには一長一短があり、どのツールがよいかという点については意見が分かれるかとは思いますが、 弊社の診断メンバーは圧倒的にBurp Suiteの利用者が多いといえます。これには診断の教育コストの面もありますが、 それとは別にBurp Suiteにはマニアックな機能が多く、これらの一部の機能が診断にとって欠かせなくなっている面があるかと思います。しかしながらBurp Suiteを使い始めた人にとっては、うまく利用することができずに挫折してしまう人も多いとも感じています。最近では、Burp Suiteの日本ユーザ会も発足しており、日本語での情報が入手しやすくなっているため、もっと利用者が増えてくれるのではないかと期待しております。
今回はBurp Suiteをより使いやすくするための拡張を作成したいと思います。
Burp Suite を利用する上での問題
Burp Suiteでよく不満にあげられるのがマルチバイト文字に関する問題です。具体的には表示する日本語文字表示が化けて読めない、文字列のコピーに失敗するなどの問題です。
この問題については Burp Suite のversion 1.6 系になってかなり改善されてきたかと思いますが、いまだに問題点は残っています。 これは Burp Suite 本体に起因する問題のため簡単に解決はできません。
しかしながら軽減する方法は存在します。できないならば、できるものを作成してしまえばよいのです。 Burp Sute には本体を拡張するためのAPIが用意されており、このAPIを利用することによりさまざまな機能を追加することができます。この拡張を利用して文字化けに対する一つの対策となる拡張を作成していきたいと思います。
Burp Suite の拡張機能の利用
まずは、Burp Suite の拡張機能(以降 Extension)について簡単に紹介したいと思います。 Burp SuiteのExtensionは「Extender」⇒「Extensions」タブから必要な拡張を読み込ませることにより行います。
Burp SuiteのExtensionはJavaの他にPythonやRubyでも作成することもできるようになっていますが、本内容では、Javaによる実装をおこなっていきます 。
Extensionを作成するためにはExtender用のAPIを実装することにより呼び出すことにより行います。
Burp Suiteに用意されているAPIは「Extender」タブの「APIs」タブにて確認できます。
今回のExtensionの作成で必要になったAPIについては簡単な説明は行いますが、紹介できなかったAPIについては各自にて確認していただければと思います。
Extensionの設計
Extensionを使って文字化けに対するアプローチはいくつか考えられますが、ここではBurp Suiteでのリクエストとレスポンスを外部アプリに連携するExtensionを作成したいと思います。
外部アプリに連携することがなぜ文字化けに対するアプローチになるかについてですが、テキストエディタに連携する場合を考えてみましょう、最近のメジャーなテキストエディタはファイル内に含まれるバイトコードから文字コードを自動で解釈し適切な文字コードで表示してくれる機能を持っています。そのため、Burp Suiteのリクエストおよびレスポンスの生のバイトを外部のテキストエディタで開かせることで文字化けせずに表示させることが可能です。
文字コードを判定するためのバイト数が少なすぎる場合や、リクエストとレスポンスで異なる文字コードを利用しいているなどの場合は、文字化けして表示できないこともあるかとおもいますが、この場合はエディタでエンコーディングを選択しなおすことにより対応可能です。
また、この場合の外部プログラムは、テキストエディタだけとは限りません、お気に入りのバイナリエディタ等と連携することも可能です。
肝心の外部プログラムとの連携方法についてですが、これについては、Burp Suiteの右クリックメニューから起動する方法にて行うようにします。
ExtensionではBurp Suiteの右クリックメニューを拡張することができExtensionから選択したリクエストおよびレスポンスの値を取得することが可能となっています。
連携するプログラムは既存のものを利用すればよいため、あらたにエディタ機能を拡張する必要がないという利点があります。
欠点としては外部プログラムを起動することによる外部プログラム間との連携に融通がきかない点です。 たとえば起動したエディタからBurp Suite側に変更結果をフィードバックしたいと思っても行う方法は限定されてしまいます。
Extensionの実装
さっそく実際に拡張を作ってみましょう。 ちなみに Extensionを作成するための開発環境についてですがJavaで作成する場合は NetBeansをお勧めます。これは、GUIの表示を必要とするExtensionを作成する場合、画面へのGUI部品の配置が必要ですが、この作業をソースコードエディタだけで行おうとすると部品の配置に非常に苦労するためです。
NetBeansはGUIの部品の配置を視覚的かつ直観的に行え、配置処理で苦労することがないため容易に開発することができます。
Burp SuiteのAPIを取り込み
最初に、Burp SuiteのAPIを作成プロジェクトに取り込みます。
このためにはBurp SuiteのAPIをエクスポートする必要があります。 Burp Suite のAPIは、「Extender」タブの「APIs」タブから、「save interface files」ボタンをクリックするとことによりエクスポートすることができます。
エクスポートしたAPIは作成したプロジェクトのソースディレクトリにコピーします。 ここでは、NetBeansにて extenderLauncher というプロジェクトを作成してsrcディレクトリにコピーしました。
BurpExtenderクラスの作成
「BurpExtenderクラス」は最初に実装すべきクラスです。 このクラスは、「IBurpExtenderインタフェース」を実装することにより行います。Burp Suiteはこの「IBurpExtenderインタフェース」を実装したクラスを最初に呼び出します。
ここで注意しなければいけないのは、「IBurpExtenderインタフェース」を実装したクラスは BurpExtender というクラス名でかつ burp パッケージになければならない点です。異なるクラス名やパッケージにしてしまうと、Burp Suite本体が呼び出すべきクラスを探せなくなるようです。
BurpExtender.java
- import ...;
- public class BurpExtender implements IBurpExtender, IContextMenuFactory {
- private final Config config = new Config();
- @Override
- /* IBurpExtender interface implements method */
- public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
- // 設定の読み込み
- this.config.loadFromXML();
- // コンテキストメニューの登録
- callbacks.registerContextMenuFactory(this);
- }
- private final List menuList = new ArrayList<>();
- @Override
- /* IContextMenuFactory interface implements method */
- public List<JMenuItem> createMenuItems(IContextMenuInvocation invocation) {
- menuList.clear();
- List<Config.LaunchItem> launchItems = this.config.getLauncherList();
- for (Config.LaunchItem item : launchItems) {
- SendToLauncher launch = new SendToLauncher(item);
- menuList.add(launch.createMenuItem(invocation));
- }
- return menuList;
- }
- }
registerExtenderCallbacksが最初に呼び出されるメソッドです。
Burp Suite に右クリックメニューを追加する必要がありますが、これには、「IContextMenuFactoryインタフェース」を使います。「 IContextMenuFactoryインタフェース」は createMenuItems メソッドを持っており、このメソッドで表示したいメニューのリストを返す必要があります。
本ソースでは 「BurpExtenderクラス」に「IContextMenuFactoryインタフェース」を実装しました。 createMenuItems メソッドにて 「Configクラス」で読み込んだ設定情報に従い、createMenuItems メソッド内でメニューの作成を行います。
Configクラスの作成
次に、設定情報を読み込む「Configクラス」を見てみましょう。ここではシンプルにXMLファイルを読み込み、メニューとなるべきLaunchItemのリストを作成しています。
Config.java
- import ...;
- public class Config {
- // config.xml 配置ディレクトリ
- public static String getUserHome() {
- return System.getProperties().getProperty("user.home");
- }
- public final static String CONFIG_XML = "config.xml";
- private final List<LaunchItem> launcherList = new ArrayList<>();
- public void loadFromXML() {
- final Properties prop = new Properties();
- try {
- // %USERPROFILE%/config.xml を読み込み
- InputStream is = new FileInputStream(new File(getUserHome(), CONFIG_XML));
- prop.loadFromXML(is);
- this.launcherList.clear();
- int index = 0;
- while (true) {
- String caption = prop.getProperty(String.format("launch[%d].caption", index), null);
- String target = prop.getProperty(String.format("launch[%d].target", index), null);
- if (caption == null || target == null) {
- break;
- }
- LaunchItem launchItem = new LaunchItem() {
- private String caption;
- private String target;
- @Override
- public void setCaption(String caption) {
- this.caption = caption;
- }
- @Override
- public String getCaption() {
- return caption;
- }
- @Override
- public void setTarget(String target) {
- this.target = target;
- }
- @Override
- public String getTerget() {
- return target;
- }
- };
- launchItem.setCaption(caption);
- launchItem.setTarget(target);
- this.launcherList.add(launchItem);
- index++;
- }
- } catch (IOException ex) {
- }
- }
- public List<LaunchItem> getLauncherList() {
- return this.launcherList;
- }
- public interface LaunchItem {
- public void setCaption(String caption);
- public void setTarget(String target);
- public String getCaption();
- public String getTerget();
- }
- }
「Configクラス」で読み込む config.xml ファイルは以下の形式です。 このファイルは、Javaの「java.util.Propertiesクラス」が出力するXML形式をそのまま利用しています。
config.xml の例
- <?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
- <properties>
- <entry key="launch[0].caption">Editor</entry>
- <entry key="launch[0].target">C:\tool\sakura\sakura.exe</entry>
- <entry key="launch[1].caption">BinEditor</entry>
- <entry key="launch[1].target">C:\tool\Bz\Bz.exe</entry>
- </properties>
launch[x].caption が メニューに表示する項目名
launch[x].target が 起動するプログラムです。
ここでは、Editorというメニューにsakuraエディタを、 BinEditorというメニューにはBzエディタを指定しました。
このExtensionでは config.xml ファイルは"user.home"ディレクトリ直下に置くことを想定しています。 "user.home"ディレクトリは Windowsの場合であれば、USERPROFILE 環境変数が示すディレクトリと同じです。
Extensionの設定情報を設定・取得するための専用のAPIも存在しますがここでは、ここではわかり易さから設定情報はファイルからの読み込みを行いました。
Tip | IBurpExtenderCallbacksクラスのsaveExtensionSetting、loadExtensionSettingメソッドが設定情報を設定・取得するための専用のAPIですので興味のある方は調べてみてください。 |
SendToLauncherクラスの作成
最後に、「Configクラス」で読み込んだ情報を元にメニュークリック後の処理を行うクラスが 「SendToLauncher クラス」です。 actionPerformed メソッドが実際にメニュークリック時の処理を行います。 メニューがクリック後に選択されたリクエストとレスポンスを生のバイト列のまま一旦テンポラリファイルに出力、作成したテンポラリファイルを引数にして実行ファイルを起動する手順を行っています。
SendToLauncher.java
- import ...;
- public class SendToLauncher implements Config.LaunchItem {
- private final Config.LaunchItem launchItem;
- public SendToLauncher(Config.LaunchItem launchItem) {
- this.launchItem = launchItem;
- }
- public String getCaption() {
- return this.launchItem.getCaption();
- }
- public void setCaption(String caption) {
- this.launchItem.setCaption(caption);
- }
- public String getTerget() {
- return this.launchItem.getTerget();
- }
- public void setTarget(String target) {
- this.launchItem.setTarget(target);
- }
- public JMenuItem createMenuItem(IContextMenuInvocation invocation) {
- final IContextMenuInvocation contextMenuInvocation = invocation;
- javax.swing.JMenuItem menuItem = new javax.swing.JMenuItem();
- menuItem.setText(this.getCaption());
- menuItem.addActionListener(new ActionListener() {
- // メニュークリック時
- @Override
- public void actionPerformed(ActionEvent e) {
- IHttpRequestResponse[] messageInfo = contextMenuInvocation.getSelectedMessages();
- if (messageInfo.length > 0) {
- try {
- File[] tmpFiles = new File[messageInfo.length];
- for (int i = 0; i < messageInfo.length; i++) {
- tmpFiles[i] = tempMessageFile(messageInfo[i], i);
- }
- String[] args = new String[tmpFiles.length];
- for (int i = 0; i < args.length; i++) {
- args[i] = tmpFiles[i].toString();
- }
- executeProcess(getTerget(), args);
- } catch (IOException ex) {
- }
- }
- }
- });
- return menuItem;
- }
- // プロセスの起動
- public static Process executeProcess(String target, String args[]) throws IOException {
- List<String> list = new ArrayList<String>(Arrays.asList(args));
- list.add(0, target);
- return Runtime.getRuntime().exec((String[]) list.toArray(new String[0]));
- }
- // テンポラリファイルの作成
- public static File tempMessageFile(IHttpRequestResponse messageInfo, int index) throws IOException {
- File file = File.createTempFile(messageInfo.hashCode() + "." + index + ".", ".tmp");
- file.deleteOnExit();
- try (FileOutputStream fostm = new FileOutputStream(file, true)) {
- if (messageInfo.getRequest() != null) {
- fostm.write(messageInfo.getRequest());
- }
- // 改行
- fostm.write(new byte[]{0x0d, 0x0a});
- if (messageInfo.getResponse() != null) {
- fostm.write(messageInfo.getResponse());
- }
- }
- return file;
- }
- }
これでひととおりExtensionの作成は完了です。
プロジェクトをビルドして、ライブラリ(jarファイル)を作成します。 NetBeansの場合プロジェクトのdistディレクトリに「extenderLauncher.jar」ファイルが作成されます。
作成されたjarファイルをBurp Suiteの「Extender」タブから拡張として認識させます。 おっとその前に、config.xmlは USERPROFILE ディレクトリにあらかじめ置いておきましょう。
拡張を認識させたならば、Burp Suite にリクエストを記録させ、右クリックメニューを表示させてみるとメニューが増えたことを確認できます。
追加された Editorメニューをクリックすることによりエディタを起動できました。
今回は、外部プログラムの起動を行いましたが、応用としてBurp Suiteにて記録したリクエストをサーバに対して送信を行い、サーバではリクエストを元に診断を行うというアイデアもあります。 実際弊社では、このような別サーバの診断ツールとの連携も行っています。
みなさんもこれを機会につくってみてはいかがでしょうか?
今回作成したソースを以下においていますので必要に応じて、利用ください。
おすすめ記事