BurpSuite外掛開發指南之 Java 篇

wyzsk發表於2020-08-19
作者: Her0in · 2016/05/27 16:53

此文接著 《BurpSuite外掛開發指南之 API 下篇》 。在此篇中將會介紹如何使用Java 開發 BurpSuite 的外掛,重點會介紹利用 Java 的 Swing 包開發帶有 GUI 的 Burp 外掛。

《BurpSuite 外掛開發指南》系列文章如下:

注:此係列文章是筆者利用業餘時間所寫,如有錯誤,望讀者們及時指正,另外此係列文章屬於入門級別的科普文,目的是普及Burp外掛的編寫技術。

0x00 Java 介面簡介


知其然更要知其所以然。在真正動手編寫 Burp 外掛之前,有必要對Burp提供的各個介面有一定的瞭解,同時要有一定的程式設計經驗和能力。那麼,在此篇中讀者則有必要了解 Java 的介面技術。

介面(英文:Interface)在 Java 程式語言中是一個比較抽象的東西。熟悉 OOP 的同學可以用“類”的思想來理解介面。但是,要明白的是,類與介面有相似的地方同時也有很多不同的地方。

介面的宣告

介面的宣告語法格式如下:

#!java
[可見度] interface 介面名稱 [extends 其他的類名] {
        // 宣告變數
        // 抽象方法
}

例如,Burp 的 介面宣告原型如下:

#!java
package burp;

public interface IBurpExtender
{
    void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks);
}

介面的實現

一個介面可以被另外一個介面繼承,也可以被一個類實現。當類實現介面的時候,類要實現介面中所有的方法。否則,類必須宣告為抽象的類。類使用implements關鍵字實現介面。在類宣告中,Implements關鍵字放在class宣告後面。不熟悉Java程式設計的讀者要牢記這幾點。

實現一個介面的語法如下:

#!java
... implements 介面名稱[, 其他介面1, 其他介面2..., ...] ...

例如,編寫 Burp 外掛必須編寫的 BurpExtender 類實現 IBurpExtender 和 IProxyListener 介面程式碼如下:

#!java
package burp;

public class BurpExtender implements IBurpExtender, IProxyListener{

    // 實現 IBurpExtender 介面的 registerExtenderCallbacks 方法
    @Override
    public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
        // TODO here
    }

    // 實現 IProxyListener 介面的 processProxyMessage 方法
    @Override
    public void processProxyMessage(boolean messageIsRequest,
            IInterceptedProxyMessage message) {
        // TODO here
    }
}

需要注意的是,在Burp提供的介面文件中,並不是所有的介面都可以用類實現,只有在介面的描述中說明了“該介面可以被實現”時,所對應的介面才可以被你所編寫的類實現其方法。

0x01 Java Swing 和 AWT 包簡介


Java Swing 是 Java Foundation Classes(JFC)的一部分。在 Swing 中,包含了很多強大靈活的,跨平臺的 GUI 控制元件。Swing 元件遵循(MVC)模型 - 檢視 - 控制器架構,並提供了三個通用的頂層容器類 JFrame,JDialog 和 JApplet。在開發帶有 GUI 的 BurpSuite 外掛時,一般不會直接用到這三個頂層容器類,具體要看個人的設計和需求。

下面是一些最常用的控制元件:

  • JLabel 標籤控制元件,JLabel 的物件是在容器中放置一個文字標籤。
  • JButton 按鈕控制元件。
  • JColorChooser 顏色選擇控制元件,用於讓使用者操作和選擇顏色。
  • JCheckBox 選擇框控制元件,支援分組。
  • JRadioButton 單選框控制元件,支援分組。
  • JList 列表控制元件。
  • JComboBox 組合框控制元件。
  • JTextField 文字框控制元件。
  • JPasswordField 密碼輸入框控制元件。
  • JTextArea 多行文字控制元件。
  • ImageIcon 繪製圖示的控制元件。
  • JScrollbar 捲軸控制元件,支援水平和垂直滾動。
  • JFileChooser 選擇檔案對話方塊。
  • JProgressBar 進度條控制元件。
  • JPanel 皮膚控制元件,此控制元件在開發外掛時會經常用到。

Swing 是在 AWT 的基礎上構建的一套新的圖形介面系統,所以 AWT 是 Java 實現圖形介面的基礎,圖形控制元件的事件監聽和響應也是由 AWT 完成的。不過,編寫 Burp 外掛所用到的圖形元件和事件並不多,很容易上手。

有關更多 GUI 元件的知識,請讀者自行百度瞭解。在此不做過多闡述。

0x02 自定義 Burp UI 標籤


編寫 GUI 的 Burp 外掛在實際使用時更加易於操作和表達資訊。當然,編寫起來也十分簡單,只需遵循一定的“套路”,就可以了。

最終編寫好的基本的樣式如下圖所示:

程式碼如下:

#!java
/*
 *  BurpSuite 外掛開發指南之 Java 篇
 *  writend by Her0in 
 */
package burp;

import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class BurpExtender implements IBurpExtender, ITab{

    public PrintWriter stdout;
    public IExtensionHelpers hps;
    public IBurpExtenderCallbacks cbs;

    public JPanel jPanelMain;

    @Override
    public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks)         {

        callbacks.setExtensionName("BurpExtender");

        this.hps = callbacks.getHelpers();
        this.cbs = callbacks;
        this.stdout = new PrintWriter(callbacks.getStdout(), true);

        this.stdout.println("hello burp!");

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {

                jPanelMain = new JPanel();

                JButton jButton = new JButton("老司機,快點我!");

                jButton.addMouseListener(new MouseAdapter() {

                    @Override
                    public void mouseClicked(MouseEvent e){
                        stdout.println("嗶...");
                    }

                });


                // 將按鈕新增到 主皮膚 jPanelMain 中. 
                jPanelMain.add(jButton);

                // 設定自定義元件並新增標籤
                cbs.customizeUiComponent(jPanelMain);
                cbs.addSuiteTab(BurpExtender.this);
            }
        });
    }

    // 實現 ITab 介面的 getTabCaption 方法
    @Override
    public String getTabCaption() {
        return "Burp 標籤測試";
    }

    // 實現 ITab 介面的 getUiComponent 方法
    @Override
    public Component getUiComponent() {
        return jPanelMain;
    }
}

從上述程式碼中,讀者也能夠看到,Java 的 Swing 圖形程式設計有點蛋疼,需要一層層的編寫。首先需要新增一個 JPanel 上去,然後在這個 JPanel 中再新增圖形元件,如果還有上層的圖形元件,則需要再新增一個 Panel 型別的控制元件。

在這裡有一個比較快速編寫 Burp GUI外掛的方法,先利用 NetBeans IDE 將圖形介面拖拽式的寫好,然後將上述顯示控制元件的程式碼替換為顯示這個 JFrame 的程式碼。之後編寫相關的事件響應程式碼。

0x03 BurpSuite外掛開發例項之 JSON 水坑 檢測外掛


本小節,筆者將會使用一個例項來“拋磚引玉”式的描述編寫帶有 GUI 的 Burp 外掛。讀者可以把關注點放在圖形控制元件的放置順序和事件處理上,可以無視 JSON 水坑檢測的邏輯是否嚴謹以及誤報率,準確率是否科學等問題。

最終編寫好的外掛如下圖:

頂部的控制元件是一個表格列表控制元件,會放置檢測到的結果。下面兩個 ITextEditor 分別顯示當前 HTTP 資料包的請求資訊和響應資訊。

程式碼就直接貼出來吧,如下:

#!java
/*
 *  BurpSuite 外掛開發指南之 Java 篇
 *  writend by Her0in 
 */
package burp;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.io.PrintWriter;
import java.util.Vector;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;

public class BurpExtender implements IBurpExtender, ITab, IHttpListener{

    public PrintWriter stdout;
    public IExtensionHelpers hps;
    public IBurpExtenderCallbacks cbs;

    public IRequestInfo iRequestInfo;
    public IResponseInfo iResponseInfo;

    public JPanel jPanel_top;
    public JTabbedPane jTabbedPane; 
    public JScrollPane jScrollPane;
    public JSplitPane jSplitPaneV;

    // 自己封裝一個 Table 控制元件
    private Her0inTable jsonTable;

    //請求,響應資訊顯示
    public JPanel jPanel_reqInfo_left;
    public JPanel jPanel_respInfo_right;
    public JSplitPane jSplitPaneInfo;
    public ITextEditor iRequestTextEditor;
    public ITextEditor iResponseTextEditor;

    Boolean bFind = false;
    String strTags = "";

    @Override
    public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {

        callbacks.setExtensionName("JSON 水坑檢測");

        this.hps = callbacks.getHelpers();
        this.cbs = callbacks;
        this.stdout = new PrintWriter(callbacks.getStdout(), true);

        this.stdout.println("hello burp!");

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {

                // 初始化垂直分隔皮膚
                jSplitPaneV = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true);
                jSplitPaneV.setDividerLocation(0.5);
                jSplitPaneV.setOneTouchExpandable(true);

                // 垂直分隔皮膚的頂部
                jPanel_top = new JPanel();
                // 設定垂直分隔皮膚頂部的子控制元件
                // 放置表格控制元件
                jTabbedPane = new JTabbedPane();

                // 初始化 Burp 提供的 ITextEditor 編輯器介面
                iRequestTextEditor = cbs.createTextEditor();
                iRequestTextEditor.setEditable(false);

                iResponseTextEditor = cbs.createTextEditor();
                iResponseTextEditor.setEditable(false);

                // 初始化 jsonTable
                jsonTable = new Her0inTable(iRequestTextEditor, iResponseTextEditor, stdout);

                // 最好放置一個 JScrollPane
                JScrollPane jScrollPane1 = new JScrollPane(jsonTable.getTab());
                jScrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                jScrollPane1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);

                jTabbedPane.scrollRectToVisible(new Rectangle(500, 70));
                jTabbedPane.addTab("JSON 水坑檢測", jScrollPane1);

                jScrollPane = new JScrollPane(jTabbedPane);
                jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
                jPanel_top.add(jScrollPane, BorderLayout.CENTER);
                jPanel_top.setLayout(null);

                // 新增componentResized事件 否則在改變Burp 主視窗大小時會錯位
                jPanel_top.addComponentListener(new ComponentListener() {

                    @Override
                    public void componentShown(ComponentEvent e) {
                    }

                    @Override
                    public void componentResized(ComponentEvent e) {
                            if(e.getSource() == jPanel_top){
                                    jScrollPane.setSize(jPanel_top.getSize().width - 5,
                                                    jPanel_top.getSize().height - 5);                           
                                    jScrollPane.setSize(jPanel_top.getSize().width - 10,
                                                    jPanel_top.getSize().height - 10);
                            }
                    }

                    @Override
                    public void componentMoved(ComponentEvent e) {
                            // TODO Auto-generated method stub
                    }

                    @Override
                    public void componentHidden(ComponentEvent e) {
                            // TODO Auto-generated method stub  
                    }
                });

                // 設定垂直分隔皮膚底部的子控制元件

                // 顯示請求/響應 資訊的水平分隔皮膚初始化
                jSplitPaneInfo = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
                jSplitPaneInfo.setDividerLocation(0.5);
                jSplitPaneInfo.setOneTouchExpandable(true); 

                // 初始化 請求,響應資訊顯示 皮膚                             
                jPanel_reqInfo_left = new JPanel();
                jPanel_respInfo_right = new JPanel();

                jPanel_reqInfo_left.setLayout(new BorderLayout());
                jPanel_respInfo_right.setLayout(new BorderLayout());

                // 將 Burp 提供的 ITextEditor 編輯器 新增到請求,響應資訊顯示 皮膚中
                jPanel_reqInfo_left.add(iRequestTextEditor.getComponent(),
                                BorderLayout.CENTER);
                jPanel_respInfo_right.add(iResponseTextEditor.getComponent(),
                                BorderLayout.CENTER);

                // 分別新增 請求,響應資訊顯示 皮膚 到 垂直分隔皮膚底部
                jSplitPaneInfo.add(jPanel_reqInfo_left, JSplitPane.LEFT);
                jSplitPaneInfo.add(jPanel_respInfo_right, JSplitPane.RIGHT);

                // 最後,為垂直分隔皮膚新增頂部皮膚和水平分隔皮膚
                jSplitPaneV.add(jPanel_top, JSplitPane.TOP);
                jSplitPaneV.add(jSplitPaneInfo, JSplitPane.BOTTOM);

                // 設定自定義元件並新增標籤
                cbs.customizeUiComponent(jSplitPaneV);
                cbs.addSuiteTab(BurpExtender.this);
            }
        });

        callbacks.registerHttpListener(this);
    }

    // 實現 ITab 介面的 getTabCaption 方法
    @Override
    public String getTabCaption() {
        return "JSON 水坑檢測";
    }

    // 實現 ITab 介面的 getUiComponent 方法
    @Override
    public Component getUiComponent() {
        return jSplitPaneV;
    }


    public void CheckJson(IHttpRequestResponse messageInfo) {
            try {
                this.iRequestInfo = this.hps.analyzeRequest(messageInfo);
                this.iResponseInfo = this.hps.analyzeResponse(messageInfo.getResponse());   
            } catch (Exception e) {
                return ;
            }

//            stdout.println(messageInfo.getHttpService().getHost());

            this.bFind = false;
            java.util.List<IParameter> listIParameters = iRequestInfo.getParameters();  
            strTags = "";
            for (IParameter param : listIParameters) {
                    String strName = param.getName().toLowerCase();
                    if(strName.indexOf("callback") != -1 || strName.indexOf("_callback") !=-1 ||
                                    strName.indexOf("cb") !=-1 || strName.indexOf("_cb") != -1 ||
                                    strName.indexOf("huidiao") !=-1 ){
                            strTags += "# find => " + strName;
                            this.bFind = true;
                    }
            }


            if(this.bFind){
                    Vector<String> vectorRow = new Vector<String>();
                    vectorRow.addElement(new String(Integer.toString(jsonTable.defaultTableModel.getRowCount())));
                    vectorRow.addElement(new String(this.iRequestInfo.getUrl().getHost()));
                    vectorRow.addElement(new String(this.iRequestInfo.getMethod()));
                    if(this.iRequestInfo.getUrl().getQuery() != null){
                            vectorRow.addElement(new String(this.iRequestInfo.getUrl().getPath() + "?" + this.iRequestInfo.getUrl().getQuery()));
                    }else{
                            vectorRow.addElement(new String(this.iRequestInfo.getUrl().getPath()));
                    }
                    vectorRow.addElement(new String(strTags));
                    jsonTable.defaultTableModel.addRow(vectorRow);
                    jsonTable.iHttpList.add(messageInfo);
            }
    }

    @Override
    public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {

        if (!messageIsRequest) {
            //JSON 檢測
            this.CheckJson(messageInfo);
        }
    }
}
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章