Burp Suite 參數蒐集插件編寫(python)

參考文章

portswigger.
開發「屬於你本身」的Burp Suite插件html

碰到的問題

  1. 環境問題
    教程一大把,下載 jython,而後 BURP 內選擇該環境便可java

  2. 抄一篇文章上的示例代碼,測試測試,看能不能跑通

    好傢伙,直接來一個報錯,ImportError: cannot import name IBurpExtender,導包錯誤。第一步就把我搞糊塗了,卒😭
    解決辦法:
    在插件入口 xxx.py 文件所在的同層級文件夾下新建一個 burp 文件夾,並在 Burp Suite 裏導出 API 文件到這個文件夾裏
    python

  3. API 問題
    看 BURP 官方文檔,以及 示例,或者大師傅們的文章 123git

  4. 沒學 java,連抄代碼頭都是大的github

具體代碼

所需文件已上傳至 Githubjson

  • 1.0 版本:參數存到具體文件中
#!/usr/bin/env python
#coding=utf8

from burp import IBurpExtender
from burp import IHttpListener
from burp import IHttpRequestResponse
from burp import IResponseInfo
from burp import IProxyListener
#從burp中導入這幾個api模塊
import os
import re
import json

print("""
  _____                     _____      _ _           _             
 |  __ \                   / ____|    | | |         | |            
 | |__) __ _ _ __ __ _ ___| |     ___ | | | ___  ___| |_ ___  _ __ 
 |  ___/ _` | '__/ _` / __| |    / _ \| | |/ _ \/ __| __/ _ \| '__|
 | |  | (_| | | | (_| \__ | |___| (_) | | |  __| (__| || (_) | |   
 |_|   \__,_|_|  \__,_|___/\_____\___/|_|_|\___|\___|\__\___/|_|   

 ----- Contact me to improve it.A good idea is also important -----
 _________________________ QQ:2309896932 __________________________
 *************** https://www.cnblogs.com/wjrblogs/ ****************
""")
print "Files will be saved at " + os.getcwd()

def ReadFile(file):
    with open(file,"a+") as f:
        f.seek(0)
        paras = f.read().split("\n")
        return paras


def WriteToFile(file, paras):
    for para in paras:
          while '' in paras:
            paras.remove('')
    if paras == []:
        os.remove(file) # 由於以前建立了一個文件,沒有參數時便刪除
    else:
        paras.sort()
        with open(file,"w") as f:
            for para in paras:
                f.write(para+"\n")


class BurpExtender(IBurpExtender, IHttpListener, IHttpRequestResponse, IProxyListener):
    '''
    定義一個類,這個類繼承了IBurpExtender 使其成爲一個插件模塊
    繼承IHttpListener, 使其能夠接受流經的request和response
    繼承IHttpRequestResponse,使其能夠得到HTTP的詳細信息
    繼承IProxyListener ,註冊成一個代理服務器!
    '''

    def registerExtenderCallbacks(self,callbacks):

        self._callbacks = callbacks
        self._helpers = callbacks.getHelpers()
        self._callbacks.setExtensionName('ParasCollector') # 設定插件名字

        callbacks.registerHttpListener(self)  # 必須得註冊才具備功能
        callbacks.registerProxyListener(self)

    def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
        if toolFlag == 4 or toolFlag == 64:  # flag值表明着不一樣的組隊,此時是 proxy 和 repeater,表示被攔截的消息
            if messageIsRequest: # 若是是一個請求
                request = messageInfo.getRequest() # 得到請求信息
                analyzedRequest = self._helpers.analyzeRequest(request) # 解析
                host = messageInfo.getHttpService().getHost() # 獲取域名
                file = host+".txt"
                lines = ReadFile(file)
                paras1 = analyzedRequest.getParameters() # 獲取參數,包括 json 格式的數據
                for para in paras1:
                    if para.getType() == para.PARAM_COOKIE:
                        temp = str(para.getName())
                        if temp not in lines: # 去重
                            lines.append(temp)
                    else:
                        temp = para.getName()
                        if temp not in lines:
                            lines.append(temp)
                WriteToFile(file,lines)
            if not messageIsRequest: # 若是是個響應
                host = messageInfo.getHttpService().getHost() # 獲取域名
                file = host+".txt"
                lines = ReadFile(file)
                response = messageInfo.getResponse() # 得到響應信息
                analyzedResponse = self._helpers.analyzeResponse(response) # 解析
                # print analyzedResponse.getStatedMimeType()
                if analyzedResponse.getInferredMimeType() == "JSON":
                    body = response[analyzedResponse.getBodyOffset():].tostring() # 獲取返回包
                    paras2 = json.loads(body).keys()
                    for para in paras2:
                        if para not in lines: # 去重
                            print str(para)
                            lines.append(str(para))
                WriteToFile(file,lines)
  • 2.0 版本:UI 可視化界面,全部參數存到 json 文件中
#!/usr/bin/env python
#coding=utf8

from burp import IBurpExtender
from burp import ITab
from burp import IHttpListener
from burp import IMessageEditorController
from burp import IHttpRequestResponse
from java.awt import Component;
from java.io import PrintWriter;
from java.util import ArrayList;
from java.util import List;
from javax.swing import JScrollPane;
from javax.swing import JSplitPane;
from javax.swing import JTabbedPane;
from javax.swing import JTable;
from javax.swing import SwingUtilities;
from javax.swing.table import AbstractTableModel;
from threading import Lock

import os
import json

print("""
  _____                     _____      _ _           _             
 |  __ \                   / ____|    | | |         | |            
 | |__) __ _ _ __ __ _ ___| |     ___ | | | ___  ___| |_ ___  _ __ 
 |  ___/ _` | '__/ _` / __| |    / _ \| | |/ _ \/ __| __/ _ \| '__|
 | |  | (_| | | | (_| \__ | |___| (_) | | |  __| (__| || (_) | |   
 |_|   \__,_|_|  \__,_|___/\_____\___/|_|_|\___|\___|\__\___/|_|   

 ----- Contact me to improve it.A good idea is also important -----
 _________________________ QQ:2309896932 __________________________
 *************** https://www.cnblogs.com/wjrblogs/ ****************
""")
print "Files will be saved at " + os.getcwd()


# 定義保存域名,參數,URL 的類
class LogEntry:
    def __init__(self, host, paras):
        self._host = host
        self._count = len(paras)
        self._paras = paras

class Table(JTable):
    def __init__(self, extender):
        self._extender = extender
        self.setModel(extender)
    
    def changeSelection(self, row, col, toggle, extend):
    
        # show the log entry for the selected row
        logEntry = self._extender._log.get(row)
        self._extender._parasViewer.setText(logEntry._paras)
        # self._extender._currentlyDisplayedItem = logEntry._requestResponse
        
        JTable.changeSelection(self, row, col, toggle, extend)
    


class BurpExtender(IBurpExtender, IHttpListener, IHttpRequestResponse, ITab, IMessageEditorController, AbstractTableModel):
    def registerExtenderCallbacks(self,callbacks):
        self._callbacks = callbacks
        self._helpers = callbacks.getHelpers()
        self._callbacks.setExtensionName('ParasCollector')
        self._log = ArrayList()
        self._lock = Lock()

        # 主窗口
        self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT)

        logTable = Table(self)
        scrollPane = JScrollPane(logTable)
        self._splitpane.setLeftComponent(scrollPane)

        # 詳情
        tabs = JTabbedPane()
        self._parasViewer = callbacks.createTextEditor()
        tabs.addTab("Paras",self._parasViewer.getComponent())
        self._splitpane.setRightComponent(tabs)

        # 定義 UI 組件
        callbacks.customizeUiComponent(self._splitpane)
        callbacks.customizeUiComponent(logTable)
        callbacks.customizeUiComponent(scrollPane)
        callbacks.customizeUiComponent(tabs)

        # 將 UI 組件添加到 BURP 的 UI
        callbacks.addSuiteTab(self)


        # 註冊功能
        callbacks.registerHttpListener(self)

        return


    def getTabCaption(self):
        return "ParasCollector"
    
    def getUiComponent(self):
        return self._splitpane
        

    def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
        if toolFlag == 4:
            # 讀 json 文件取得數據
            self._lock.acquire() # 加鎖,反應會慢一點
            try:
                with open("allparas.json","r") as f:
                    allparas = json.loads(f.read())
            except Exception as ex:
                allparas = {}
                print("shit!!\n")
                print("%s"%ex)

            host = messageInfo.getHttpService().getHost().encode('utf-8')
            paras = allparas.get(host)
            if paras == None:
                paras = []
            # print(type(paras))
            if messageIsRequest: # 若是是一個請求
                request = messageInfo.getRequest() # 得到請求信息
                analyzedRequest = self._helpers.analyzeRequest(request)
                paras1 = analyzedRequest.getParameters()
                for para in paras1:
                    temp = str(para.getName())
                    if temp not in paras: # 去重
                            paras.append(temp)
                if paras !=[]:
                    paras.sort()
                    allparas[host] = paras
            if not messageIsRequest: # 若是是個響應
                response = messageInfo.getResponse() # 得到響應信息
                analyzedResponse = self._helpers.analyzeResponse(response)
                if analyzedResponse.getInferredMimeType() == "JSON":
                    body = response[analyzedResponse.getBodyOffset():].tostring() # 獲取返回包
                    paras2 = json.loads(body).keys()
                    for para in paras2:
                        if para not in paras: # 去重
                            paras.append(str(para))
                if paras !=[]:
                    paras.sort()
                    allparas[host] = paras
            if allparas != {}:
                with open("allparas.json","w+") as f:
                    json.dump(allparas, f, ensure_ascii=False)
            
            row = self._log.size()
            self._log.clear()
            for host in allparas.keys():
                self._log.add(LogEntry(host, '\n'.join(allparas.get(host))))
                self.fireTableRowsInserted(row, row)
            self._lock.release()



    def getRowCount(self):
        try:
            return self._log.size()
        except:
            return 0

    def getColumnCount(self):
        return 1

    def getColumnName(self, columnIndex):
        if columnIndex == 0:
            return "HOST"
        return ""

    def getValueAt(self, rowIndex, columnIndex):
        logEntry = self._log.get(rowIndex)
        if columnIndex == 0:
            return logEntry._host
        return ""

相關文章
相關標籤/搜索