Burp Suite插件開發-Python


Burp Suite插件開發-Python

​ 相較於挖SRC,我還是喜歡做一點東西。由於我對JAVA並不是很了解,所以選擇Python來做插件開發。在學習過程中遇到很多坑,寫個文檔用於記錄。由於我也不熟悉UI相關的開發,所以UI相關的類暫時就不寫了

前言

熟讀官方的API文檔

打開導出的 index.html

基礎模板

BURP 插件的開發可以簡單理解為對API類的繼承以及對方法的重寫。

#coding=utf-8
from burp import IBurpExtender
import sys

if sys.version[0] == '2':  # 為什么要判斷是不是python2呢?鬼知道后面jython會不會支持python3
    reload(sys)
    sys.setdefaultencoding("utf-8") #設置系統編碼,否則碰到中文的地方都會報錯(即使是設置了coding也沒用)
    
    
class BurpExtender(IBurpExtender):  # 所有插件都必須實現BurpExtender類,並且繼承IBurpExtender
    def registerExtenderCallbacks(self,callbacks): # 該方法在啟動插件時會自動調用,用於注冊插件
        # callbacks是一個IBurpExtenderCallbacks,里面提供了很多基礎方法,如注冊監聽器等
        callbacks.setExtenderName("MyExt")  # 設置插件名稱
    def Myfunc(self,paras): # 自定義方法
        pass

上面的代碼實現了一個沒有任何功能的插件

Python基礎知識

在閱讀其他人寫的Burp插件時,常常會在registerExtenderCallbacks函數中看到self._callbacks = callbacks,此舉是用於注冊全局變量,方便在其他函數中使用該變量(后面會經常用到),且self對象只會在插件卸載時才會被釋放

注意:重寫的方法或者自定義的方法第一個參數均為self,因為是類中的方法。且調用自定義方法需要使用 self.Myfunc() 的方式調用

常用API介紹

Burp的API大體可以分為5類:插件入口類、監聽類、工具類、HTTP消息類、UI類

為了后續實操,所以先將會用到的類簡單介紹一下,重點需要注意方法的參數及返回值兩者的數據類型

插件入口類

IBurpExtender

所有擴展都必須實現這個接口。也就是如上方模板所寫,BurpExtender 必須繼承 IBurpExtender 類

該類下面只有一個方法,並只會在啟動插件的時候調用一次。因此常在該方法內執行一些初始化操作,如定義插件名稱、初始化UI、注冊全局變量、注冊監聽器

注意:打開BURP時會啟動插件,所以也會調用一次該方法

registerExtenderCallbacks

void	registerExtenderCallbacks(IBurpExtenderCallbacks callbacks)

可以看到,方法內的參數為一個 IBurpExtenderCallbacks 對象,具體可看下面

IBurpExtenderCallbacks

Burp Suite 使用此接口將一組回調方法傳遞給擴展,擴展可以使用這些方法在 Burp 中執行各種操作。可能不是很好理解,簡單來說就是該類提供了很多方法,用來告訴BURP應該在什么時候干什么事的

變量

查看API文檔首先可以看到,該類下面有一些靜態變量。這些變量常用來判斷HTTP消息是從哪個地方傳過來的,如 Proxy、Repeater、Intruder等,常在IHttpListener的processHttpMessage方法內用到,暫時可以不用管

方法

只涉及常用方法講解

printError
void	printError(java.lang.String error)

輸出錯誤信息

printOutput
void	printOutput(java.lang.String output)

輸出一般信息

setExtensionName
void	setExtensionName(java.lang.String name)

用於設置插件名稱

getProxyHistory
IHttpRequestResponse[]	getProxyHistory()

用於獲取 Proxy 模塊內所有的歷史請求,並返回一個 IHttpRequestResponse 類型的數組。如果想在安裝插件的時候自動掃描歷史請求,可以使用這個方法

registerProxyListener
void	registerProxyListener(IProxyListener listener)

用於注冊Proxy監聽器,監聽Proxy模塊正在處理的請求和響應的通知。

registerHttpListener
void	registerHttpListener(IHttpListener listener)

用於注冊HTTP監聽器,監聽所有模塊(Proxy、Repeater等模塊)正在處理的請求和響應的通知。

registerExtensionStateListener
void	registerExtensionStateListener(IExtensionStateListener listener)

用於注冊插件狀態監聽(在卸載插件時需要)

registerContextMenuFactory
void	registerContextMenuFactory(IContextMenuFactory factory)

用於為自定義上下文菜單項注冊工廠(注冊右鍵菜單時需要)

還有很多類似的register方法

saveBuffersToTempFiles
IHttpRequestResponsePersisted	saveBuffersToTempFiles(IHttpRequestResponse httpRequestResponse)

用於將請求、響應消息對象保存到臨時文件中,減少內存開銷

saveToTempFile
ITempFile	saveToTempFile(byte[] buffer)

用於將傳入的buffer保存到臨時文件,如byte類型請求響應等,並返回一個ITempFile對象

saveConfigAsJson
java.lang.String	saveConfigAsJson(java.lang.String... configPaths)

用於獲取BURP項目級別的配置,傳入configPaths可獲取指定配置,可配合saveTempfile保存文件

loadConfigFromJson
void	loadConfigFromJson(java.lang.String config)

導入項目配置文件

makeHttpRequest
IHttpRequestResponse	makeHttpRequest(IHttpService httpService, byte[] request)

IHttpRequestResponse	makeHttpRequest(IHttpService httpService, byte[] request, boolean forceHttp1)

byte[]	makeHttpRequest(java.lang.String host, int port, boolean useHttps, byte[] request)

byte[]	makeHttpRequest(java.lang.String host, int port, boolean useHttps, byte[] request, boolean forceHttp1)

用於 發起 HTTP/1請求

makeHttp2Request
byte[]	makeHttp2Request(IHttpService httpService, java.util.List<IHttpHeader> headers, byte[] body)

byte[]	makeHttp2Request(IHttpService httpService, java.util.List<IHttpHeader> headers, byte[] body, boolean forceHttp2)

byte[]	makeHttp2Request(IHttpService httpService, java.util.List<IHttpHeader> headers, byte[] body, boolean forceHttp2, java.lang.String connectionIdentifier)

用於 發起 HTTP/2請求

getHelpers
IExtensionHelpers	getHelpers()

此方法用於獲取 IExtensionHelpers 對象,擴展程序可以使用該對象來執行許多有用的任務。

是一個小工具,里面有很多常用的方法供我們使用,讓插件編寫更加方便

工具類

IExtensionHelpers

該接口包含許多輔助方法,擴展可以使用這些方法來協助 Burp 擴展出現的各種常見任務

analyzeRequest

IRequestInfo	analyzeRequest(byte[] request)

IRequestInfo	analyzeRequest(IHttpRequestResponse request)

IRequestInfo	analyzeRequest(IHttpService httpService, byte[] request)

可以看到,該方法重載了三次。傳入不同的參數類型,最終得到的都是一個IRequestInfo對象(請求對象)

這里有一個坑,第一個跟第二個得到的對象存在一點區別

analyzeResponse

IResponseInfo	analyzeResponse(byte[] response)

得到一個IResponseInfo對象(響應對象)

編碼相關

# base64編碼解碼
byte[]	base64Decode(byte[] data)
byte[]	base64Decode(java.lang.String data)
java.lang.String	base64Encode(byte[] data)
java.lang.String	base64Encode(java.lang.String data)

# URL編碼解碼
byte[]	urlDecode(byte[] data)
java.lang.String	urlDecode(java.lang.String data)
byte[]	urlEncode(byte[] data)
java.lang.String	urlEncode(java.lang.String data)

# 字符與byte相互轉換
java.lang.String	bytesToString(byte[] data)
byte[]	stringToBytes(java.lang.String data)

buildHttpMessage

byte[]	buildHttpMessage(java.util.List<java.lang.String> headers, byte[] body)

構建一個請求、響應消息,常用於攔截請求並自動修改其中的參數時會使用

HTTP消息類

IInterceptedProxyMessage

該類表示一條被Proxy模塊攔截的請求

getClientIpAddress

java.net.InetAddress	getClientIpAddress()

獲取被攔截請求的客戶端IP,也就是請求來源IP

getListenerInterface

java.lang.String	getListenerInterface()

獲取被攔截請求的Proxy Listener,返回值:127.0.0.1:8080

可用來針對不同來源的請求做特殊化處理,如PC/手機

getMessageInfo

IHttpRequestResponse	getMessageInfo()

獲取被攔截的請求/響應消息的IHttpRequestResponse對象

IHttpRequestResponse

此接口用來獲取&更新請求響應

setHighlight

void	setHighlight(java.lang.String color)

高亮請求響應,可傳入red、orange、yellow、green、cyan、blue、pink、magenta、gray值,傳空值則表示清除高亮設置

getHighlight

java.lang.String	getHighlight()

獲取請求是否高亮,若有則返回對應顏色,若沒有則返回None

setComment

void	setComment(java.lang.String comment)

設置備注

getComment

java.lang.String	getComment()

獲取備注

setHttpService

void	setHttpService(IHttpService httpService)

設置請求的服務器地址,需要傳入一個IHttpService對象

getHttpService

IHttpService	getHttpService()

獲取請求的服務器地址IHttpService對象

setRequest

void	setRequest(byte[] message)

設置請求,在需要修改請求內容時用到

getRequest

byte[]	getRequest()

獲取請求,注意此時是byte數組,一般需要用IExtensionHelpers.analyzeRequest(byte[] request)方法轉成IRequestInfo對象

setResponse

void	setResponse(byte[] message)

設置響應,在需要修改響應內容時用到

getResponse

byte[]	getResponse()

獲取響應,注意此時是byte數組,一般需要用IExtensionHelpers.analyzeRespnse(byte[] response)方法轉成IResponseInfo對象

IRequestInfo

HTTP請求對象

getMethod

java.lang.String	getMethod()

獲取請求方法,GET、POST、PUT······

getUrl

java.net.URL	getUrl()

獲取請求的URL,注意此處返回值是一個java.net.URL對象,需要再調用具體的方法獲取URL相關內容

getHeaders

java.util.List<java.lang.String>	getHeaders()

以數組方式返回請求行與請求頭,如["GET / HTTP/1.1", "Host: example.com"]

getParameters

java.util.List<IParameter>	getParameters()

獲取所有請求參數,包含了JSON數據中的參數,返回一個IParameter類型的數組

getContentType

byte	getContentType()

獲取請求頭中的Content-Type,注意此處返回的是一個整形數字,可以與該類中的靜態變量對比

getBodyOffset

int	getBodyOffset()

獲取請求body開始時的偏移量(索引值),常使用如request[analyzedRequest.getBodyOffset():].tostring()獲取整個請求body

IResponseInfo

HTTP響應對象

getStatusCode

short	getStatusCode()

獲取響應狀態碼

getHeaders

java.util.List<java.lang.String>	getHeaders()

以數組方式返回請求行與請求頭,如["HTTP/1.1 200 OK", "Content-Length: 1256"]

getCookies

java.util.List<ICookie>	getCookies()

獲取服務器返回的Set-Cookie字段的ICookie對象列表

getStatedMimeType

java.lang.String	getStatedMimeType()

獲取響應頭中標注的 Content-Type,注意此處返回的是string類型,與 IRequestInfo 中的稍有區別

getInferredMimeType

java.lang.String	getInferredMimeType()

獲取BURP自動判斷響應內容的Content-Type

getBodyOffset

int	getBodyOffset()

獲取響應body開始時的偏移量(索引值),常使用如response[analyzedResponse.getBodyOffset():].tostring()獲取整個響應body

IParameter

用於獲取請求參數的詳情,Key和Value等。This interface is used to hold details about an HTTP request parameter,由官方文檔可以看出來,其並未考慮目前前后端分離網站的情況,未提供獲取響應中的參數,因此只能直接寫獲取響應參數的方法

getName

java.lang.String	getName()

獲取參數名稱

getValue

java.lang.String	getValue()

獲取參數值

getType

byte	getType()

檢索參數類型,比如說是JSON內的參數還是URL里傳輸的參數,具體可以該類中的靜態變量對比

參數名索引

int	getNameStart()

int	getNameEnd()

獲取參數名開始與結束的偏移量(索引)

值索引

int	getValueStart()

int	getValueEnd()

獲取參數值開始與結束的偏移量(索引)

IHttpHeader

getName

java.lang.String	getName()

獲取請求頭名稱

getValue

java.lang.String	getValue()

獲取請求頭的值

ICookie

getName

java.lang.String	getName()

獲取Cookie名稱

getValue

java.lang.String	getValue()

獲取Cookie值

getDomain

java.lang.String	getDomain()

獲取Cookie適用的域名

getPath

java.lang.String	getPath()

獲取Cookie使用的PATH

getExpiration

java.util.Date	getExpiration()

獲取Cookie過期時間

IHttpService

getHost

java.lang.String	getHost()

獲取服務器域名

getPort

int	getPort()

獲取服務器端口

getProtocol

java.lang.String	getProtocol()

獲取服務器使用的協議,HTTP、HTTPS

監聽類

監聽類API只有一個方法,並且會在一定的條件下自動觸發

IProxyListener

Proxy 消息監聽類。使用IBurpExtenderCallbacks.registerProxyListener()方法注冊該監聽器后,便可監聽所有流經Proxy的請求與響應

所有請求/響應均會被

processProxyMessage

void	processProxyMessage(boolean messageIsRequest, IInterceptedProxyMessage message)
# messageIsRequest 表示此次處理的是請求還是響應
# IInterceptedProxyMessage message 表示一個被攔截HTTP消息對象,可通過該對象的	getMessageInfo()方法獲取到具體的請求、響應詳情信息

方法捕獲到,然后在其中完成用戶自定的處理行為

例如:我們想要查看所有請求中是否有使用shiro的系統,並將該請求高亮顯示,便可以這樣實現

圖片是網上找的,沒太多時間重新搭環境

#coding=utf-8
from burp import IBurpExtender
from burp import IProxyListener
import sys

if sys.version[0] == '2':
    reload(sys)
    sys.setdefaultencoding("utf-8")

class BurpExtender(IBurpExtender,IProxyListener):
    def registerExtenderCallbacks(self,callbacks):
        self._helpers = callbacks.getHelpers()
        callbacks.setExtensionName("FindShiro")
        callbacks.registerProxyListener(self)
    def processProxyMessage(self,messageIsRequest,message):
        # 我們只用判斷 響應 頭中是否有 rememberMe 字段就可以了
        if not messageIsRequest:
            RepReq = message.getMessageInfo() # 獲取請求與響應
            Rep_B = RepReq.getResponse() # 獲取響應,byte數據類型
            Rep = self._helpers.analyzeResponse(Rep_B) # 轉換為IResopnse對象
            cookies = Rep.getCookies() # 獲取所有cookie
            for cookie in cookies:
                if cookie.getName() == "rememberMe": # 判斷cookie中是否有rememberMe,有的話就將請求高亮顯示
                    RepReq.setHighlight("red")

可以看到,我們甚至都不需要自己寫一些函數來處理請求響應,BURP API提供了很多常用的類與方法

百度主站並沒有shrio哈,此處是為了方便插件測試的時候所以判斷是不是有 BDSVRTM 這個cookie

IHttpListener

HTTP 消息監聽類。使用IBurpExtenderCallbacks.registerHTTPListener()方法注冊該監聽器后,便可監聽所有請求與響應,包括Proxy、Repeater、Intruder等等所有的 made by any Burp tool 的流量

請求響應會被

processHttpMessage

void	processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo)
# toolFlag表示來源,可在 IBurpExtenderCallbacks 類中看到

方法捕獲到,使用toolFlag判斷來源,如

#coding=utf-8
from burp import IBurpExtender
from burp import IHttpListener
import sys

if sys.version[0] == '2':
    reload(sys)
    sys.setdefaultencoding("utf-8")

class BurpExtender(IBurpExtender,IHttpListener):
    def registerExtenderCallbacks(self,callbacks):
        self._callbacks = callbacks
        callbacks.setExtensionName("PlaceYoucame")
        callbacks.registerHttpListener(self)
    def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
        if toolFlag == self._callbacks.TOOL_PROXY: # 表示來自Proxy模塊
            print("Proxy")
        elif toolFlag == self._callbacks.TOOL_REPEATER: # 表示來自Repeater模塊
            print("Repeater")
        else:
            print("Others")

IExtensionStateListener

插件狀態監聽類。通過調用 IBurpExtenderCallbacks.registerExtensionStateListener() 來注冊一個擴展狀態監聽器。 偵聽器將收到擴展狀態更改的通知。 注意:任何啟動后台線程或打開系統資源(例如文件或數據庫連接)的擴展都應該注冊一個偵聽器並在卸載擴展時終止線程/關閉資源。

當插件被卸載時會調用如下方法:

注意:退出BURP時也會調用哦

extensionUnloaded

void	extensionUnloaded()

通常我們會在其中完成善后工作,如

#coding=utf-8
from burp import IBurpExtender
from burp import IExtensionStateListener
import sys

if sys.version[0] == '2':
    reload(sys)
    sys.setdefaultencoding("utf-8")

class BurpExtender(IBurpExtender,IExtensionStateListener):
    def registerExtenderCallbacks(self,callbacks):
        callbacks.setExtensionName("Unload")
        callbacks.registerExtensionStateListener(self)
        print("Link Start!")
    def extensionUnloaded(self):
        print("主人,你忍心么?還不快插上?")

當然我們也可以做一個自動導入&保存BURP配置的插件

#coding=utf-8
from burp import IBurpExtender
from burp import IExtensionStateListener
import sys
import json

if sys.version[0] == '2':
    reload(sys)
    sys.setdefaultencoding("utf-8")

class BurpExtender(IBurpExtender,IExtensionStateListener):
    def registerExtenderCallbacks(self,callbacks):
        self._callbacks = callbacks
        callbacks.setExtensionName("SaveConfig")
        callbacks.registerExtensionStateListener(self)
        try:
            with open("config.json","r") as f:
                config = f.read()
                callbacks.loadConfigFromJson(config)
        except:
            pass
    def extensionUnloaded(self):
        config = self._callbacks.saveConfigAsJson(os.getcwd())
        with open("config.json","w") as f:
            f.write(config)

從此媽媽再也不用擔心我忘記保存配置了

IScannerListener

過段時間再寫吧

IScopeChangeListener

過段時間再寫吧

UI類

IContextMenuInvocation

當 Burp 使用上下文菜單調用的詳細信息調用擴展提供的 IContextMenuFactory 時,將使用此接口。 自定義上下文菜單工廠可以查詢此接口以獲取調用事件的詳細信息,以確定應顯示哪些菜單項。

getToolFlag

int	getToolFlag()

獲取點擊右鍵動作是在哪個模塊內觸發的,Proxy、Repeater等

getInvocationContext

byte	getInvocationContext()

獲取點擊右鍵動作是在哪里觸發的(詳細信息),具體可對比

getSelectedMessages

IHttpRequestResponse[]	getSelectedMessages()

獲取右鍵內容的的HTTP請求響應(IHttpRequestResponse對象)

getSelectedIssues

IScanIssue[]	getSelectedIssues()

獲取右鍵內容的的掃描IScanIssue對象

注意:至於什么時候使用getSelectedMessages或getSelectedIssues,可根據getInvocationContext獲取的結果加以判斷

IContextMenuFactory

注冊右鍵菜單

該類只有一個方法

createMenuItems

java.util.List<javax.swing.JMenuItem>	createMenuItems(IContextMenuInvocation invocation)

當用戶在 Burp 內的任何位置調用上下文菜單(右鍵)時,該方法將被 Burp 調用

比方說我想實現一個這樣的右鍵菜單,完成一些自定義的事情

那便可以這樣寫:

#coding=utf-8
from burp import IBurpExtender
from burp import IContextMenuFactory
from javax.swing import JMenuItem
import sys

if sys.version[0] == '2':
    reload(sys)
    sys.setdefaultencoding("utf-8")

class BurpExtender(IBurpExtender, IContextMenuFactory):
    def registerExtenderCallbacks(self,callbacks):
    	self._callbacks = callbacks
        callbacks.setExtensionName("myMenu")
        callbacks.registerContextMenuFactory(self)
    def createMenuItems(self, invocation):
        if invocation.getToolFlag() == self._callbacks.TOOL_REPEATER or self._callbacks.TOOL_PROXY:
            menu = []
            menu.append(JMenuItem("PrintHOST", None, actionPerformed=lambda x, y=invocation: self.myFunc(x, y)))
        return menu
    def myFunc(self,event,invocation):
        reqreps = invocation.getSelectedMessages()
        for reqrep in reqreps:
            print(reqrep.getHttpService().getHost())


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM