burpsuite插件开发总结
0x00基础
burpsuite api:
接口:
用java开发插件就把这个burp文件夹放到工程目录即可
Java文档
在线版
https://portswigger.net/burp/extender/api/index.html
官方教程:https :
//portswigger.net/burp/extender/
https://portswigger.net/blog/writing-your-first-burp-suite-extension
https://portswigger.net/blog/archive?y=2012_12_01_archive.html
推荐用Java,执行效率高,不会出现奇奇怪怪的问题……
//图片图片网路
插件入口和帮助接口类:
IBurpExtender,IBurpExtenderCallbacks,IExtensionHelpers,IExtensionStateListener
IBurpExtenderCallbacks接口类是IBurpExtender接口的实现类与Burp其他各个组件(扫描仪,入侵者,蜘蛛……),各个通信对象(HttpRequestResponse,HttpService,SessionHandlingAction)之间的纽带。
IExtensionHelpers,IExtensionStateListener这两个接口类是插件的帮助和管理操作的接口定义。
UI相关接口类:
IContextMenuFactory,IContextMenuInvocation,ITab,ITextEditor,IMessageEditor,IMenuItemHandler
种类接口类主要是定义Burp插件的UI显示和动作的处理事件,主要是软件交互中使用。
Burp工具组件接口类:
IInterceptedProxyMessage,IIntruderAttack,IIntruderPayloadGenerator,IIntruderPayloadGeneratorFactory,IIntruderPayloadProcessor,IProxyListener,IScanIssue,IScannerCheck,IScannerInsertionPoint,IScannerInsertionPointProvider,IScannerListener,IScanQueueItem,IScopeChangeListener
这些接口类的功能非常好理解,Burp在接口定义的命名中使用了的见名知意的规范,看到接口类的名称,基本可以将这个接口作为适用于其中的工具组件。
HTTP消息处理接口类:
ICookie,IHttpListener,IHttpRequestResponse,IHttpRequestResponsePersisted,IHttpRequestResponseWithMarkers,IHttpService,IRequestInfo,IParameter,IResponseInfo
这些接口的定义主要是围绕HTTP消息通信过程中涉及的Cookie,请求,响应,参数几大消息对象,通过对通信消息头,消息体的数据处理,来达到控制HTTP消息传递的目的。
— https://t0data.gitbooks.io/burpsuite/content/chapter16.html
0x01常用的接口和方法
公共接口IBurpExtender
void registerExtenderCallbacks(IBurpExtenderCallbacks回调)
演示:
公共 类 BurpExtender 实现 IBurpExtender,ITab,IContextMenuFactory,ActionListener { 公共 无效 registerExtenderCallbacks(IBurpExtenderCallbacks 回调){ 回调。setExtensionName(“ burp-info-extractor”); 这个。hps =回调。getHelpers(); 这个。cbs =回调; 回调。registerContextMenuFactory(this);
公共接口IBurpExtenderCallbacks
演示:
callbacks.setExtensionName(“ burp-info-extractor”);
callbacks.registerContextMenuFactory(this);
公共接口IExtensionHelpers
IRequestInfo analyticsRequest(IHttpRequestResponse请求); IResponseInfo analyticsResponse(byte [] response); 演示: reqHeaders = 自我._helpers.analyzeRequest(requestResponse).getHeaders()
公共接口IScannerCheck
列表< IScanIssue > doPassiveScan(IHttpRequestResponse baseRequestResponse); 演示: def doPassiveScan(self,baseRequestResponse): islaunchBurpUnauthChecker = INT(自.launchBurpUnauthCheckerCheckBox.isSelected()) 如果(不是islaunchBurpUnauthChecker )或(self .isFilterSuffix(baseRequestResponse))或(self .isFilterStatusCode(baseRequestResponse)): 返回 scan_issues = [] newRequestResponse = self .sendUnauthenticatedRequest(baseRequestResponse) #print str(self._helpers.analyzeRequest(baseRequestResponse).getUrl())+'\ n' 问题= 自我.compareResponses(newRequestResponse,baseRequestResponse) scan_issues.append(issue) 返回scan_issues 高清 consolidateDuplicateIssues(自我,ISB,ISA): 返回 - 1
公共接口IHttpListener
无效processHttpMessage(int toolFlag,
布尔messageIsRequest,
IHttpRequestResponse messageInfo);
toolFlag在公共接口IBurpExtenderCallbacks中可查看
/ **
*用于标识Burp Suite整体的标志。
* /
整数TOOL_SUITE = 0x00000001;
/ **
*用于标识打Bur目标工具的标志。
* /
整数TOOL_TARGET = 0x00000002;
/ **
*用于标识打p代理工具的标志。
* /
整数TOOL_PROXY = 0x00000004;
/ **
*用于标识Burp Spider工具的标志。
* /
整数TOOL_SPIDER = 0x00000008;
/ **
*用于标识Burp Scanner工具的标志。
* /
整数TOOL_SCANNER = 0x00000010;
/ **
*用于标识Burp Intruder工具的标志。
* /
整数TOOL_INTRUDER = 0x00000020;
/ **
*用于标识打p中继器工具的标志。
* /
整数TOOL_REPEATER = 0x00000040;
/ **
*用于标识Burp Sequencer工具的标志。
* /
整数TOOL_SEQUENCER = 0x00000080;
/ **
*用于标识Burp Decoder工具的标志。
* /
整数TOOL_DECODER = 0x00000100;
/ **
*用于标识Burp比较器工具的标志。
* /
整数TOOL_COMPARER = 0x00000200;
/ **
*用于标识Burp Extender工具的标志。
* /
整数TOOL_EXTENDER = 0x00000400;
演示:
def processHttpMessage(self,toolFlag,messageIsRequest,messageInfo):
如果messageIsRequest和toolFlag == 4:
公共接口IHttpRequestResponse
byte [] getRequest();
byte [] getResponse();
演示:
reqBodyByte = requestResponse.getRequest()。tostring()[reqBodyOffset:]
公共接口IContextMenuFactory
List < JMenuItem > createMenuItems(IContextMenuInvocation调用); 演示: public List < JMenuItem > createMenuItems(IContextMenuInvocation invocation){ // TODO自动生成的方法stub selectedItems = invocation 。getSelectedMessages(); List < JMenuItem > menu = 新的 ArrayList < JMenuItem >(); JMenuItem itemManualTesting = 新的 JMenuItem(“将rsp发送到BIE”); itemManualTesting 。setActionCommand(“ sendRSPToBIE”); itemManualTesting 。addActionListener(this); 菜单。add(itemManualTesting); 返回菜单; }
开发burpsuite插件关键在于处理http请求和响应
可以参考
https://github.com/bit4woo/burp-api-drops
再以jython为例:
获取标题:通过IRequestInfo对象
reqHeaders = self._helpers.analyzeRequest(requestResponse).getHeaders()
获取参数:通过IRequestInfo对象
paramList = 自我._helpers.analyzeRequest(requestResponse).getParameters() 用于对在paramList: paramType = para.getType() 如果(paramType == 0)或(paramType == 1): paramKey = para.getName() paramValue = para.getValue()
#参数共有7种格式,0是URL参数,1是body参数,2是cookie参数,6是json格式参数
获取正文:通过字符串格式的request截取
reqBodyOffset = self._helpers.analyzeRequest(requestResponse).getBodyOffset()
reqBodyByte = requestResponse.getRequest()。tostring()[reqBodyOffset:]
更新参数值:
如果paramKey.lower()在authParamsList: newAuthParam = self ._helpers.buildParameter(paramKey,newAuthParamValue,paramType) newRemoveGetPostAuthParamsRequest = self ._helpers.updateParameter(newRemoveGetPostAuthParamsRequest,newAuthParam)
更新标题:
newHeaders = [] newAuthHeaderVal = self .replaceHeaderValWithTextField.getText() 对于头在reqHeaders: headerName = header.split(':')[ 0 ] #如果headerName.lower()不在self.authParamsList中: #newHeaders.append(header)# 返回self._helpers.buildHttpMessage(newHeaders,None) 如果headerName.lower( )在 自己的.authParamsList中: 标头= headerName + “:” + newAuthHeaderVal newHeaders.append(header) 其他: newHeaders.append(header)
更新正文:
如果paramType == 6: paramKey = para.getName() paramValue = para.getValue() 打印paramKey + “:” + paramValue reqJsonBodyOffset = self ._helpers.analyzeRequest(requestResponse).getBodyOffset() reqJsonBodyString = requestResponse.getRequest()。tostring()[reqJsonBodyOffset:] 打印reqJsonBodyString reqJsonBodyStringDict = json.loads(reqJsonBodyString) #reqJsonBodyStringDict = ast.literal_eval(reqJsonBodyString) 对于authParamName在authParamsList: 如果authParamName在reqJsonBodyStringDict.keys(): reqJsonBodyStringDict [authParamName] = newAuthParamValue
重新构造请求包:
newRemoveGetPostAuthParamsRequest = self ._helpers.buildHttpMessage(jsonReqHeaders,newReqJsonBodyString) 返回 自身._callbacks.makeHttpRequest(requestResponse.getHttpService(),newRequest)
0x02开发插件
未授权访问权限检测:
https://github.com/theLSA/burp-unauth-checker
敏感参数提取:
https://github.com/theLSA/burp-sensitive-param-extractor
信息提取:
https://github.com/theLSA/burp-info-extractor
burp-unauth-checker
需求
自动化检测未授权访问
aauthize
authz
authmatrix
自动转发器
上几个插件都挺好,但是还是不太符合,想要的是在浏览的时候可以自动检测是否有未授权访问权限。
实现
python编写,实现IScannerCheck接口doPassiveScan方法
authParams.cfg文件存储授权的参数,如令牌,cookie等
在UI输入框增加授权参数要以英文逗号(,)分隔,并单击保存按钮保存,其他操作不需要点击保存按钮。
显示帖子正文即显示帖子数据的正文内容。
show rspContent即显示响应正文内容,建议尝试不开启。
一些授权参数是在get / post参数中的,如user / list?token = xxx,这时可以重置替换替换授权参数值的GET / POST Auth参数。
默认过滤后缀列表filterSuffixList =“ jpg,jpeg,png,gif,ico,bmp,svg,js,css,html,avi,mp4,mkv,mp3,txt”
应对一些特殊情况,设置了排除的授权参数列表excludeAuthParamsList
onlyIncludeStatusCode:设置检测的响应码,仅只检测200的响应
原本想直接取消掉授权参数,但是可能造成响应失败,所以把授权参数值替换成自定义的数据,如:cookie:[空],token = unauthp
sendUnauthenticatedRequest发送替换了授权参数值的请求
授权参数分两种
1-在http的header中,如cookie,authorization等
2-在http参数中,如post数据中的token等
实现:
1-直接将header的授权参数值替换为:
if headerName。 self.authParamsList中的lower():
header = headerName +“:” + newAuthHeaderVal
2-
get / post请求的参数,常规操作buildParameter,updateParameter可。jsonParameter
,直接将正文数据解析为字典再替换授权参数值,然后再将字典转换字符串,最后构造新请求数据包。
如果paramType == 6: paramKey = para.getName() paramValue = para.getValue() 打印paramKey + “:” + paramValue reqJsonBodyOffset = self ._helpers.analyzeRequest(requestResponse).getBodyOffset() reqJsonBodyString = requestResponse.getRequest()。tostring()[reqJsonBodyOffset:] 打印reqJsonBodyString reqJsonBodyStringDict = json.loads(reqJsonBodyString) #reqJsonBodyStringDict = ast.literal_eval(reqJsonBodyString) 对于authParamName在authParamsList: 如果authParamName在reqJsonBodyStringDict.keys(): reqJsonBodyStringDict [authParamName] = newAuthParamValue
有两个问题
1-字典有【u“】,
2-还有将字符串转为字典,json数据有空格和单引号
json.loads重新构造的json数据有空格
尝试使用
d = json.dumps(s,分隔符=(’,’,’:’))
发现类型是str不方便处理,loads()没有separators参数
ast.literal_eval()也一样有空格和单引号……
想直接替换掉空间,但是有些数据可能会有空间……
两个问题的解决方案:
reqJsonBodyStringDict = json.loads(reqJsonBodyString)
……#替换授权参数值
newReqJsonBodyString = json.dumps(reqJsonBodyStringDict,separators =(’,’,’:’))
即先用json.loads()将串联转换字典进行处理后再将字典用json.dumps()转换为字符串来构造请求数据包。
最后再对比原请求和替换了授权参数值的响应body
compareRespons:
如果(str(nBody).split()== str(oBody).split()):
一致则为未授权访问突破。
临时不提供在ui界面删除授权参数的功能,如要删除直接在authParams.cfg内部删除,切记将光标移动到最后一个授权参数(末行)的结尾。
坑点
1] dopassivescan的request不能直接用,要复制一个再用,否则会出现请求只能只读的异常,因为这个请求响应已经完成了,再编辑是没意义的。
解决:
newRemoveGetPostAuthParamsRequest = newRemoveAuthHeaderRequest
2】python中的空要用None,java是null
效果图
打敏感参数提取器
需求
检测并提取请求参数中的敏感参数名,如用户名,用户名,方便测试越权突破,并形成敏感参数字典。
实现
使用python开发,实现IHttpListener接口,processHttpMessage方法。
param-regular.cfg:参数正则配置文件,id表示检测请求参数中包含id的参数,如userid,idcard等
支持4种参数检测:
self.requestParamDict [‘urlParams’] = []
self.requestParamDict [‘BodyParams’] = []
self.requestParamDict [‘cookieParams’] = []
self.requestParamDict [‘jsonParams’] = []
先获取请求的所有类型参数,放到requestParamDict再找到SensitiveParam最后写入2文件。
界面右侧的列表即参数正则,可实时增删,删除只需单击列表元素再单击删除按钮即可。
IHttpListener似乎无法实现请求关键字参数高亮,IScanIssue-ScanIssue-self._callbacks.applyMarkers可以,暂不实现参数高亮了。
无法处理较复杂的请求json参数,某些多重层次结构,这种情况下,暂不做处理。
坑点
1】所谓的json的get请求参数可能无法获取最连续键值对?
解决:这种请求的情况可能见,暂不处理。
效果图
打bur信息提取器
需求
快速提取数据中毒性的信息,如HTTP响应数据包中的用户名,密码等。
例如一个api(/ user / list)返回大量用户名/密码,大多数是json格式(jsonarray),就可以使用此工具快速提取信息。
实现
使用java开发,实现IContextMenuFactory接口createMenuItems方法。
采用两种提取方式:
1.json格式提取
2.正则提取
【1】json格式
提取:采用google gson
【2】正则
提取re库常规操作即可
坑点
1】
现象:
发送rsp到bie中空行问题,复制的http请求和手动换行复制body没问题,直接发送到的请求就无法以\ n \ n获取body,可能是有\ t,\ r,\ n之类的字符
解决:
rspBody1 = rspBody1.replaceAll(“ \ r \ n | \ r | \ n | \ t”,“”);
2】
现象:
runnable里面run(),无法直接使用动作监听,如:
cleanRspBodyButton.setActionCommand(“ cleanrspbody”);
cleanRspBodyButton.addActionListener(BurpExtender);
解决:
cleanRspBodyButton.addActionListener(new ActionListener(){
@Override
公共无效actionPerformed(ActionEvent e){
// TODO自动生成的方法存根
rspBodyArea.setText(“”);
}
效果图
0x03常见问题
1.多次加载插件出现内存不足错误
原因:内存被占满了,重启burp或增加burp的内存,在启动Burp时设置JVM的XX参数即可,如:java -XX:MaxPermSize = 1G -jar burp.jar
2,如何调试
jython目前只能想到print大法……
java的当前我也是用println大法,虽然有可以联动ide进行调试的方法,但还是要编译jar,比较麻。
3,py开发的插件用到第三方库,如要求,但即使本机安装了要求库,加载插件时候还是提示找到
原因:jython和python的库不同
解决:
在插件目录放进第三方库即可
或者填入第三方库的位置,如site-package
0x04结语
学习优秀的插件,不用重复造轮子。
参考官方API。
网站地址:https://www.hackzl.cn;发布者:hack之路,转转请注明出处:https://www.hackzl.cn/index.php/2020/12/15/2440/