前言
用python开发burp插件,需要依赖Jython,需要先下载 Standalone Jar 然后在burp中配置其位置,如图:
然后就可以去在Extensions下添加你自己的插件了(记得把Extensions type选成python)
由于Jython动态产生Java的类的方式,在加载插件时你可能会遇到内存错误,如果你看到像java.lang.OutOfMemoryError: PermGen space
类似的报错,可以通过配置Java版本低于JDK8,通过如下命令启动burp来分配更多的内存java -XX:MaxPermSize=1G -jar burp.jar
,注意,这种方式在JDK8+以上是不允许的
一点心得
特别喜欢乌云上大佬的一段话,这里分享给大家:
相较于阅读许多参考资料从零开始编写插件,笔者更推荐在熟悉了开发文档后直接在已有的源码中“照猫画虎”进行插件的开发。现有的插件,读者可以在 BApp Store 中找到,Python 版本的插件可以直接查看源码进行学习,Java 版本的插件可以在反编译后查看其源码进行学习。
注:安装了 BApp Store 中的插件后,会在 BurpSuite 所在目录下的 bapps 文件夹中找到插件文件。
插件开发“方法论”:
插件型的应用程序在设计时就一定会考虑插件的开发,因此,主程序与插件之间必然有一种“约定”,在开发插件的过程中,只需按照程序开发者设计的这种“约定”开发就好了,读者在阅读参考官方开发文档时只需注意以下三点:
- 接口方法功能
- 接口方法入参(参数类型和参数个数)
- 接口方法的返回值(返回值类型)
在关注上述三点以后,就可以把多个接口方法联系在一起,组织起一定的逻辑,这样,开发的思路就顺理成章了。
关于BurpSuite的开发文档,官方只提供了简单的接口说明,可以在这里找到,或者可以BurpSuite 程序的 “Extender” 标签下的 “APIs” 子标签里找到,BurpSuite 官方并未提供详细的开发文档,只有少量的开发实例,可以在此找到。不过,BurpSuite 官方建立了插件开发者社区和博客,可以帮助开发者解答疑问
java中的接口和类的概念是类似的,但是在用法上还有所区别,由于我自己也不会java,这里就不再深究二者的区别了,如下阐述过程若有不严谨的地方,还请大佬们指正
API介绍
IBurpExtender
public interface IBurpExtender
所有的扩展必须实现此接口,实现的类名必须为“BurpExtender”。在 burp 包中,必须申明为 public ,并且必须提供一个默认的构造器。
此接口实现了以下方法:
#!java
void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks)
此方法将在扩展加载后被调用,它注册了一个 IBurpExtenderCallbacks 接口的实例,IBurpExtenderCallbacks 接口提供了许多在开发插件过程中常用的一些操作。
参数说明:
- callbacks 是一个 IBurpExtenderCallbacks 对象。
一个简单的插件代码如下:
from burp import IBurpExtender
class BurpExtender(IBurpExtender):
def registerExtenderCallbacks( self, callbacks):
# your extension code here
return
加载这个插件什么都不会发生(按理说也不应该有报错)
IBurpExtenderCallbacks
public interface IBurpExtenderCallbacks
此接口中实现的方法和字段在插件开发过程中会经常使用到。 Burp Suite 利用此接口向扩展中传递了许多回调方法,这些回调方法可被用于在 Burp 中执行多个操作。当扩展被加载后,Burp 会调用 registerExtenderCallbacks() 方法,并传递一个 IBurpExtenderCallbacks 的实例。扩展插件可以通过这个实例调用很多扩展 Burp 功能必需的方法。如:设置扩展插件的属性,操作 HTTP 请求和响应以及启动其他扫描功能等等。
此接口提供了很多的方法和字段,在此不一一列举,具体的说明可以在 burp SDK 中的 IBurpExtenderCallbacks.java 或 https://portswigger.net/burp/extender/api/burp/IBurpExtenderCallbacks.html 中查看。
一个简单的Demo
from burp import IBurpExtender
class BurpExtender(IBurpExtender):
def registerExtenderCallbacks( self, callbacks):
callbacks.setExtensionName("Plugin Name") #设置插件名称
return
IContextMenuFactory
public interface IContextMenuFactory
Burp 的作者在设计上下文菜单功能中采用了工厂模式的设计模式,扩展可以实现此接口,然后调用 IBurpExtenderCallbacks.registerContextMenuFactory() 注册自定义上下文菜单项的工厂,返回的是IContextMenuInvocation的实例,可以调用其中的方法。该接口用于实现菜单与一系列操作联合起来
此接口提供了如下方法:
#!java
java.util.List<javax.swing.JMenuItem> createMenuItems(IContextMenuInvocation invocation)
当用户在 Burp 中的任何地方调用一个上下文菜单时,Burp 则会调用这个工厂方法。此方法会根据菜单调用的细节,提供应该被显示在上下文菜单中的任何自定义上下文菜单项。
参数说明:
- invocation – 一个实现 IMessageEditorTabFactory 接口的对象, 通过此对象可以获取上下文菜单调用的细节。
返回值:
此工厂方法将会返回需要被显示的自定义菜单项的一个列表(包含子菜单,checkbox 菜单项等等), 若无菜单项显示,此工厂方法会返回 null。
一个Demo:
from burp import IBurpExtender
from burp import IContextMenuFactory
from javax.swing import JMenu
from javax.swing import JMenuItem
class BurpExtender(IBurpExtender, IContextMenuFactory):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
callbacks.setExtensionName("test")
callbacks.registerContextMenuFactory(self)
def createMenuItems(self, invocation):
menu = []
menu.append(JMenuItem("Test menu", None, actionPerformed=self.testmenu))
# 注意不要写成testmenu(),否则只要请求菜单就会触发testmenu函数,猜测是赋值时触发的
#print(invocation.getSelectedMessages())
return menu
def testmenu(self,event):
print(event)
此时,我在所有的上下文菜单中创建了一个名为Test menu的菜单,通过重写其createMenuItems方法,此时在Burp的任意地方调用上下文菜单都会触发此方法,通过绑定testmenu方法,我可以定义点击该菜单时所触发的行为
其中,event参数不能少,因为会默认传递一个java.awt.event.ActionEvent,如图:
IContextMenuInvocation
public interface IContextMenuInvocation
此接口被用于获取当 Burp 调用扩展提供的 IContextMenuFactory 工厂里的上下文菜单时的一些细节,上文出现的invocation其实就是IContextMenuInvocation的实例,作为createMenuItems中作为参数传递进来,使得我们可以获取到用户点击菜单时的一些额外信息.
此接口中定义了一些属性:
通过这些属性,我们可以区别出这个菜单是在哪个标签页中出现的,进而做一些独特的处理
然后是该接口定义的方法:
#!java
// 此方法可被用于获取本地Java输入事件,并作为上下文菜单调用的触发器,一般不会用到,用来获取鼠标事件的一些详细信息(说白了就是鼠标右键时的一些信息)
java.awt.event.InputEvent getInputEvent()
// 此方法被用于获取上下文中被调用的菜单,返回一个索引,指示调用菜单的上下文环境,所以及定义都在上面图片中
byte getInvocationContext()
// 此方法被用于获取用户选中的Issues的详细信息,返回一个IScanIssue对象的数组,在Target下Site map中的Issues的位置调用
IScanIssue[] getSelectedIssues()
// 此方法被用于获取当前显示的或用户选中的 HTTP 请求/响应的详细信息.返回IHttpRequestResponse对象的数组,代表当调用菜单时用户显示或选择的项目
IHttpRequestResponse[] getSelectedMessages()
// 此方法被用于获取用户所选的当前消息的范围,返回一个int[2]包括当前消息中用户选定的起始和结束位置(偏移),如果用户未选中,则两个偏移都为光标所在位置.如果不是可编辑消息,会返回Null
int[] getSelectionBounds()
// 此方法被用于获取调用上下文菜单的 Burp 工具,返回一个索引,这些索引被定义在IBurpExtenderCallbacks接口.
int getToolFlag()
看一个小Demo:
from burp import IBurpExtender
from burp import IContextMenuFactory
from burp import IBurpExtenderCallbacks
from javax.swing import JMenu
from javax.swing import JMenuItem
class BurpExtender(IBurpExtender, IContextMenuFactory):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
callbacks.setExtensionName("test")
callbacks.registerContextMenuFactory(self)
def createMenuItems(self, invocation):
menu = []
if invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_REPEATER:
menu.append(JMenuItem("Test menu", None, actionPerformed=self.testmenu))
return menu
def testmenu(self, event):
print("aaaa")
上述demo实现了只有在repeater标签下点击右键才会出现Test menu菜单的效果
IHttpRequestResponse
public interface IHttpRequestResponse
此接口用于检索和更新有关 HTTP 消息的详细信息。该接口提供了如下方法:
#!java
// 获取用户标注的注释信息
java.lang.String getComment()
// 获取用户标注的高亮信息
java.lang.String getHighlight()
// 获取请求/响应的 HTTP 服务信息,返回IHttpService的实例,通过此方法我们可以获得一些请求中的信息,包括域名、端口、协议等。
IHttpService getHttpService()
// 获取 HTTP 请求信息
byte[] getRequest()
// 获取 HTTP 响应信息
byte[] getResponse()
// 更新用户标注的注释信息
void setComment(java.lang.String comment)
// 高亮某个请求,color可以自定义,一般用于高亮存在敏感信息的数据包
void setHighlight(java.lang.String color)
// 更新 请求/响应的 HTTP 服务信息
void setHttpService(IHttpService httpService)
// 更新 HTTP 请求信息
void setRequest(byte[] message)
// 更新 HTTP 响应信息
void setResponse(byte[] message)
注意:getxxxxx的方法只能在响应结束后使用(读操作),而setxxxxx的方法只能在响应前使用(写操作)
挑常用的看看用法:
- getHttpService
from burp import IBurpExtender from burp import IHttpListener class BurpExtender(IBurpExtender, IHttpListener): def registerExtenderCallbacks(self, callbacks): self._callbacks = callbacks callbacks.setExtensionName("test") callbacks.registerHttpListener(self) def processHttpMessage(self, toolflag, messageIsRequest, messageInfo): service = messageInfo.getHttpService() print("Host: " + str(service.getHost())) print("Port: "+ str(service.getPort())) print("Protocol: " + str(service.getProtocol())) print("-----------------------------------")
该Demo实现了在有请求响应结束后,输出该请求的Host,端口,协议的操作(本质会转成java,为强类型语言,一定要加str(),否则会报int to str的错误)
- setHighlight
from burp import IBurpExtender from burp import IHttpListener class BurpExtender(IBurpExtender, IHttpListener): def registerExtenderCallbacks(self, callbacks): self._callbacks = callbacks callbacks.setExtensionName("test") callbacks.registerHttpListener(self) def processHttpMessage(self,toolflag,messageIsRequest,messageInfo): messageInfo.setHighlight('blue')
上述代码实现了在http history中将请求标记为蓝色的功能,也可以定制
- setRequest&setResponse两个set的作用是一样的,一个是用来替换请求主体的信息,一个是用来替换响应主体的信息,给出一个解析unicode编码的Demo:
#!/usr/bin/env python #coding=utf8 from burp import IBurpExtender from burp import IHttpListener from burp import IHttpRequestResponse from burp import IResponseInfo import re # Class BurpExtender (Required) contaning all functions used to interact with Burp Suite API print 'stayliv3.github.io' class BurpExtender(IBurpExtender, IHttpListener): # define registerExtenderCallbacks: From IBurpExtender Interface def registerExtenderCallbacks(self, callbacks): # keep a reference to our callbacks object (Burp Extensibility Feature) self._callbacks = callbacks # obtain an extension helpers object (Burp Extensibility Feature) # http://portswigger.net/burp/extender/api/burp/IExtensionHelpers.html self._helpers = callbacks.getHelpers() # set our extension name that will display in Extender Tab self._callbacks.setExtensionName("unicode decode") # register ourselves as an HTTP listener callbacks.registerHttpListener(self) # define processHttpMessage: From IHttpListener Interface def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): # determine what tool we would like to pass though our extension: if toolFlag == 64 or toolFlag == 16 or toolFlag == 32: #if tool is Proxy Tab or repeater # determine if request or response: if not messageIsRequest:#only handle responses response = messageInfo.getResponse() #get Response from IHttpRequestResponse instance analyzedResponse = self._helpers.analyzeResponse(response) # returns IResponseInfo headers = analyzedResponse.getHeaders() #替换iso8859-1 # iterate though list of headers new_headers = [] for header in headers: # Look for Content-Type Header) if header.startswith("Content-Type:"): # Look for HTML response # header.replace('iso-8859-1', 'utf-8') # print header new_headers.append(header.replace('iso-8859-1', 'utf-8')) else: new_headers.append(header) print new_headers body = response[analyzedResponse.getBodyOffset():] body_string = body.tostring() # print body_string u_char_escape = re.search( r'(?:\\u[\d\w]{4})+', body_string) if u_char_escape: # print u_char_escape.group() u_char = u_char_escape.group().decode('unicode_escape').encode('utf8') new_body_string = body_string.replace(u_char_escape.group(),'--u--'+u_char+'--u--') new_body = self._helpers.bytesToString(new_body_string) # print new_body_string messageInfo.setResponse(self._helpers.buildHttpMessage(new_headers, new_body))
注释的比较到位,就不再过多赘述
IHttpService
public interface IHttpService
此接口用于提供关于 HTTP 服务信息的细节。
此接口提供了如下方法:
#!java
// 返回 HTTP 服务信息的主机名或 IP 地址
java.lang.String getHost()
// 返回 HTTP 服务信息的端口
int getPort()
// 返回 HTTP 服务信息的协议
java.lang.String getProtocol()
上面的demo中已经使用过了,比较简单,就不再过多说明了
HttpListener
public interface IHttpListener
该接口只有一个方法:
#!java
void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo)
通过调用 IBurpExtenderCallbacks.registerHttpListener() 注册一个 HTTP 监听器.Burp 里的任何一个工具发起 HTTP 请求或收到 HTTP 响应都会通知此监听器。扩展可以得到这些交互的数据,进行分析和修改.如果在开发插件的时候需要获取到所有的HTTP数据包,包括Repeater工具自定义修改的请求,则必须实现此接口,重写该方法,该接口还定义了如下几个属性:
#!java
// 指示了发起请求或收到响应的 Burp 工具的 ID,所有的 toolFlag 定义在 IBurpExtenderCallbacks 接口中。
int toolFlag
// 指示该消息是请求消息(值为True)还是响应消息(值为False)
messageIsRequest
// 被处理的消息的详细信息,是一个 IHttpRequestResponse 对象
messageInfo
IIntruderAttack
public interface IIntruderAttack
此接口用于定制 Intruder 工具的攻击方式。
此接口提供了以下方法:
#!java
// 获取攻击中的 HTTP 服务信息
IHttpService getHttpService()
// 获取攻击中的请求模版
byte[] getRequestTemplate()
IIntruderPayloadGeneratorFactory
public interface IIntruderPayloadGeneratorFactory
扩展可以实现此接口,并且可以调用 IBurpExtenderCallbacks.registerIntruderPayloadGeneratorFactory() 注册一个自定义的 Intruder 工具的 payload 生成器。
该接口提供了以下方法:
#!java
// 此方法由 Burp 调用,用于创建一个 payload 生成器的新实例。当用户发动一次 Intruder 攻击时,将会使用该方法返回的 payload 生成器的实例
IIntruderPayloadGenerator createNewInstance(IIntruderAttack attack)
// 此方法由 Burp 调用,用于获取 payload 生成器的名称
java.lang.String getGeneratorName()
IIntruderPayloadGenerator
public interface IIntruderPayloadGenerator
此接口被用于自定义 Intruder 工具的 payload 生成器。当需要发起一次新的 Intruder 攻击时,扩展需要注册一个 IIntruderPayloadGeneratorFactory 工厂并且必须返回此接口的一个新的实例。此接口会将当前插件注册为一个 Intruder 工具的 payload 生成器
#!java
此接口提供了如下方法:
// 此方法由 Burp 调用,用于获取下一个 payload 的值
byte[] getNextPayload(byte[] baseValue)
// 此方法由 Burp 调用,用于决定 payload 生成器是否能够提供更多 payload,当所有payload都用过后,应当返回false,否则返回true
boolean hasMorePayloads()
// 此方法由 Burp 调用,用于重置 payload 生成器的状态,这将导致下一次调用 getNextPayload() 方法时会返回第一条 payload
void reset()
一起给一个Demo:
from burp import IBurpExtender
from burp import IIntruderPayloadGeneratorFactory
from burp import IIntruderPayloadGenerator
class BurpExtender(IBurpExtender, IIntruderPayloadGeneratorFactory):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
callbacks.setExtensionName("test")
callbacks.registerIntruderPayloadGeneratorFactory(self);
def getGeneratorName(self):
return "Test payload"
# 由burp调用,创建一个payload生成器的新实例
def createNewInstance(self, attack):
return IntruderPayloadGenerator()
class IntruderPayloadGenerator(IIntruderPayloadGenerator):
# 定义何时结束,可能是payload_list == []类似的
def hasMorePayloads(self):
return False
# 定义下一个payload是什么
def getNextPayload(self, baseValue):
# to do here
return None
# 重新开始所有payload
def reset(self):
pass
此时会出现如下的自定义payload
IIntruderPayloadProcessor
public interface IIntruderPayloadProcessor
扩展可以实现此接口,并且可以调用 IBurpExtenderCallbacks.registerIntruderPayloadProcessor() 注册一个自定义 Intruder 工具的 payload 的处理器。此接口会将当前插件注册为一个 Intruder 工具的 payload 处理器。
该接口提供了以下方法:
#!java
// 此方法由 Burp 调用,用于获取 payload 处理器的名称
java.lang.String getProcessorName()
// 此方法由 Burp 调用,当处理器每次应用 payload 到一次 Intruder 攻击时,Burp 都会调用一次此方法
byte[] processPayload(byte[] currentPayload, byte[] originalPayload, byte[] baseValue)
// processPayload 方法说明:
参数说明:
- currentPayload – 当前已被处理过的 payload 的值
- originalPayload – 在应用处理规则之前的 payload 的原始值
- baseValue – payload 位置的基准值,将用当前已被处理过的 payload 替代
返回值:
返回已被处理过的 payload 的值。 如果返回 null 意味着当前的 payload 将被跳过,并且此次攻击将被直接移动到下一个 payload 。该方法可以用于对已有的payload的进行处理,比如加上某些前缀,跳过带某些关键字的payload等等
一个Demo:
from burp import IBurpExtender
from burp import IIntruderPayloadProcessor
class BurpExtender(IBurpExtender, IIntruderPayloadProcessor):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
callbacks.setExtensionName("test")
callbacks.registerIntruderPayloadProcessor(self);
def getProcessorName(self):
return "Test payload processor"
# 此方法由 Burp 调用,且会在每次使用一个 payload 发动攻击时都会调用一次此方法
def processPayload(self, currentPayload, originalPayload, baseValue):
#to do here
return None
IInterceptedProxyMessage&IProxyListener
IInterceptedProxyMessage这个接口是由注册IProxyListener来实现获取数据包的详细信息的。所以先看IProxyListener. IProxyListener仅获取proxy模块的数据包,和IHttpListener有点像,当proxy标签页中有被拦截的请求时,burp会将相关信息告知IProxyListener
IProxyListener的接口如下:
void processProxyMessage(boolean messageIsRequest,
IInterceptedProxyMessage message)
当一个http信息被burp拦截时自动调用,传入两个参数,messageIsRequest用于判断是请求还是响应,message 是一个IInterceptedProxyMessage的实例,使得扩展程序可以查询或者更新被拦截的http消息,并且控制时候应拦截响应并将其显示给用户以进行手动的查看或修改
接着看,IInterceptedProxyMessage的属性和接口如下:
解释的比较清晰了,这里再给个Demo:
from burp import IBurpExtender
from burp import IProxyListener
from burp import IInterceptedProxyMessage
class BurpExtender(IBurpExtender, IProxyListener):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
callbacks.setExtensionName("test")
callbacks.registerProxyListener(self)
def processProxyMessage(self, messageIsRequest, message):
if messageIsRequest:
print(message.getClientIpAddress())
# drop掉所有请求
message.setInterceptAction(IInterceptedProxyMessage.ACTION_DROP)
IExtensionStateListener
public interface IExtensionStateListener
扩展可以实现此接口,然后调用 IBurpExtenderCallbacks.registerExtensionStateListener() 注册一个扩展的状态监听器。在扩展的状态发生改变时,监听器将会收到通知。注意:任何启动后台线程或打开系统资源(如文件或数据库连接)的扩展插件都应该注册一个监听器,并在被卸载后终止线程/关闭资源。
此接口只提供了一个方法:
#!java
void extensionUnloaded()
在插件被 unload (卸载)时,会调用此方法,可以通过重写此方法,在卸载插件时,做一些善后处理工作。
比较清晰简单,不再给Demo了
IExtensionHelpers
public interface IExtensionHelpers
此接口提供了很多常用的辅助方法,扩展可以通过调用 IBurpExtenderCallbacks.getHelpers 获得此接口的实例,方法比较多,这里列出一些常用的,详细可以看这里
#!java
// 此方法会添加一个新的参数到 HTTP 请求中,并且会适当更新 Content-Length
byte[] addParameter(byte[] request, IParameter parameter)
// 此方法用于分析 HTTP 请求信息以便获取到多个键的值
IRequestInfo analyzeRequest(IHttpService httpService,
byte[] request)
// 此方法用于分析 HTTP 响应信息以便获取到多个键的值
IResponseInfo analyzeResponse(byte[] response)
// 构建包含给定的 HTTP 头部,消息体的 HTTP 消息
byte[] buildHttpMessage(java.util.List<java.lang.String> headers, byte[] body)
// 对给定的 URL 发起 GET 请求
byte[] buildHttpRequest(java.net.URL url)
// bytes 到 String 的转换
java.lang.String bytesToString(byte[] data)
// String 到 bytes 的转
java.lang.String bytesToString(byte[] data)
一般都会在代码中引入self._helpers = callbacks.getHelpers()
来获取该接口的实例
一个Demo:
from burp import IBurpExtender
from burp import IContextMenuFactory
from burp import IHttpListener
class BurpExtender(IBurpExtender,IHttpListener):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
callbacks.setExtensionName('test')
callbacks.registerHttpListener(self)
def processHttpMessage(self,toolflag,messageIsRequest,messageInfo):
response = messageInfo.getResponse()
analyze_response = self._helpers.analyzeResponse(response)
print("status code:"+str(analyze_response.getStatusCode()))
更多的用法结合说明自行探索吧
IParameter&ICookie&IRequestInfo&IResponseInfo
这里面提供了一些对request和responese的分析扩展,可以用这些接口获取到消息更详细的信息,包括headers,参数,cookie等,没什么太多说的,这里只给出接口方法及解释,都比较简单,属于见名知意型的:
- ICookie
#!java // 此方法用于获取 Cookie 的域 java.lang.String getDomain() // 此方法用于获取 Cookie 的过期时间 java.util.Date getExpiration() // 此方法用于获取 Cookie 的名称 java.lang.String getName() // 此方法用于获取 Cookie 的路径 java.lang.String getPath() // 此方法用于获取 Cookie 的值 java.lang.String getValue()
- IParameter
- IRequestInfo
- IResponseInfo
Others
还有一些没有介绍到的接口,要么是不太常用,要么是之前接口的方法中引入的对象或实例.这些想了解直接看手册即可,当然,还有一些手册不推荐使用的方法,这里也不做介绍了
自己实现一个小插件
这里想自己实现一个Copy to python的功能.可以在proxy或repeater页面直接将request请求保存成一个可以直接使用的py文件,省下手动输入参数的时间.
实现代码如下:
# coding=utf-8
from burp import IBurpExtender
from burp import IParameter
from burp import IContextMenuFactory
from burp import IBurpExtenderCallbacks
from javax.swing import JMenu
from javax.swing import JMenuItem
class BurpExtender(IBurpExtender, IContextMenuFactory):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
callbacks.setExtensionName("Copy2py")
callbacks.registerContextMenuFactory(self)
def createMenuItems(self, invocation):
if invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_REPEATER or IBurpExtenderCallbacks.TOOL_PROXY:
menu = []
menu.append(JMenuItem("Copy to py", None, actionPerformed=lambda x, y=invocation: self.copy2py(x, y)))
return menu
def copy2py(self,event, invocation):
for HttpRequestResponse in invocation.getSelectedMessages():
request = HttpRequestResponse.getRequest()
httpService = HttpRequestResponse.getHttpService()
analyze_request = self._helpers.analyzeRequest(httpService, request)
# 设置参数
params = {}
headers = {}
data = {}
avoidList = ['Connection','Cache-Control','Host','Accept-Encoding','Accept-Language','Accept','Content-Type']
paramList = analyze_request.getParameters()
url = str(analyze_request.getUrl()).split("?")[0]
for header in analyze_request.getHeaders():
try:
if header.split(':')[0] in avoidList:
continue
headers[header.split(':')[0]] = header.split(':')[1].strip()
except IndexError:
continue
for param in paramList:
if param.getType() == IParameter.PARAM_BODY:
data[param.getName()] = param.getValue()
elif param.getType() == IParameter.PARAM_URL:
params[param.getName()] = param.getValue()
# 格式化打印
print("import requests\n")
print("url = '" + url + "'")
if params:
print("params = {")
for (key, value) in params.items():
print(" '" + key + "': '" + value + "',")
print("}")
if data:
print("data = {")
for (key, value) in data.items():
if key != '':
print(" '" + key + "': '" + value + "',")
print("}")
if headers:
print("headers = {")
try:
for (key, value) in headers.items():
print(" '" + key + "': '" + value + "',")
print("}\n")
except:
pass
if analyze_request.getMethod() == 'GET':
print("r = requests.get(url, params=params, headers=headers)")
elif analyze_request.getMethod() == 'POST':
print("r = requests.post(url, data=data,headers=headers)")
print("print(r.status_code)")
print("print(r.content)")
实现效果如下:
由于burp本身没有提供写文件的接口,只有保存成临时文件的saveToTempFile, 所以这里采用重定向插件输出到file的方式实现copy to py.
同时,还有一个从burp保存的文件中自动生成py的脚本,一并放在了github上:https://github.com/Gality369/burp-Copy2py
发表评论
您还未登录,请先登录。
登录