淘先锋技术网

首页 1 2 3 4 5 6 7

0x00 基础

burpsuite api:

0274627feed42ff4785a8ba667cce8cc.png

interface:

用java开发插件就把这个burp文件夹放到工程目录即可

ad125cee5b8084ce2e4d9c9dafea0d99.png

javadoc

7d1060ae29e2ec198c3f36ea080c27a0.png

在线版

推荐用 Java,执行效率高,不会出现奇奇怪怪的问题……

940b43925e71d65ef5ae989b8fce8ceb.png

//图片来源于网络

插件入口和帮助接口类:

IBurpExtender、IBurpExtenderCallbacks、IExtensionHelpers、IExtensionStateListener

IBurpExtender接口类是Burp插件的入口,所有Burp的插件均需要实现此接口,并且类命名为BurpExtender。 IBurpExtenderCallbacks接口类是IBurpExtender接口的实现类与Burp其他各个组件(Scanner、Intruder、Spider……)、各个通信对象(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、Request、Response、Parameter几大消息对象,通过对通信消息头、消息体的数据处理,来达到控制HTTP消息传递的目的。

0x01 常用的接口和方法

public interface IBurpExtender

void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks)

demo:

public class BurpExtender implements IBurpExtender, ITab, IContextMenuFactory, ActionListener{

public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {

callbacks.setExtensionName("burp-info-extractor");

this.hps = callbacks.getHelpers();

this.cbs = callbacks;

callbacks.registerContextMenuFactory(this);

public interface IBurpExtenderCallbacks

demo:

callbacks.setExtensionName(“burp-info-extractor”);

callbacks.registerContextMenuFactory(this);

public interface IExtensionHelpers

IRequestInfo analyzeRequest(IHttpRequestResponse request);

IResponseInfo analyzeResponse(byte[] response);

demo:

reqHeaders = self._helpers.analyzeRequest(requestResponse).getHeaders()

public interface IScannerCheck

List doPassiveScan(IHttpRequestResponse baseRequestResponse);

demo:

def doPassiveScan(self, baseRequestResponse):

islaunchBurpUnauthChecker = int(self.launchBurpUnauthCheckerCheckBox.isSelected())

if (not islaunchBurpUnauthChecker) or (self.isFilterSuffix(baseRequestResponse)) or (self.isFilterStatusCode(baseRequestResponse)):

return

scan_issues = []

newRequestResponse = self.sendUnauthenticatedRequest(baseRequestResponse)

#print str(self._helpers.analyzeRequest(baseRequestResponse).getUrl()) + '\n'

issue = self.compareResponses(newRequestResponse, baseRequestResponse)

scan_issues.append(issue)

return scan_issues

def consolidateDuplicateIssues(self, isb, isa):

return -1

public interface IHttpListener

void processHttpMessage(int toolFlag,

boolean messageIsRequest,

IHttpRequestResponse messageInfo);

toolFlag在public interface IBurpExtenderCallbacks中可查看

int TOOL_SUITE = 0x00000001;

int TOOL_TARGET = 0x00000002;

int TOOL_PROXY = 0x00000004;

int TOOL_SPIDER = 0x00000008;

int TOOL_SCANNER = 0x00000010;

int TOOL_INTRUDER = 0x00000020;

int TOOL_REPEATER = 0x00000040;

int TOOL_SEQUENCER = 0x00000080;

int TOOL_DECODER = 0x00000100;

int TOOL_COMPARER = 0x00000200;

int TOOL_EXTENDER = 0x00000400;

demo:

def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):

if messageIsRequest and toolFlag==4:

public interface IHttpRequestResponse

byte[] getRequest();

byte[] getResponse();

demo:

reqBodyByte = requestResponse.getRequest().tostring()[reqBodyOffset:]

public interface IContextMenuFactory

List createMenuItems(IContextMenuInvocation invocation);

demo:

public List createMenuItems(IContextMenuInvocation invocation) {

// TODO Auto-generated method stub

selectedItems = invocation.getSelectedMessages();

List menu = new ArrayList();

JMenuItem itemManualTesting = new JMenuItem("Send rsp to BIE");

itemManualTesting.setActionCommand("sendRSPToBIE");

itemManualTesting.addActionListener(this);

menu.add(itemManualTesting);

return menu;

}

开发burpsuite插件关键在于处理http请求和响应

可以参考

再以jython为例:

获取header:通过IRequestInfo对象

reqHeaders = self._helpers.analyzeRequest(requestResponse).getHeaders()

获取parameter:通过IRequestInfo对象

paramList = self._helpers.analyzeRequest(requestResponse).getParameters()

for para in paramList:

paramType= para.getType()

if (paramType == 0) or (paramType == 1):

paramKey = para.getName()

paramValue = para.getValue()

#参数共有7种格式,0是URL参数,1是body参数,2是cookie参数,6是json格式参数

获取body:通过String格式的request截取

reqBodyOffset = self._helpers.analyzeRequest(requestResponse).getBodyOffset()

reqBodyByte = requestResponse.getRequest().tostring()[reqBodyOffset:]

更新参数值:

if paramKey.lower() in authParamsList:

newAuthParam = self._helpers.buildParameter(paramKey, newAuthParamValue, paramType)

newRemoveGetPostAuthParamsRequest = self._helpers.updateParameter(newRemoveGetPostAuthParamsRequest, newAuthParam)

更新header:

newHeaders = []

newAuthHeaderVal = self.replaceHeaderValWithTextField.getText()

for header in reqHeaders:

headerName = header.split(':')[0]

# if headerName.lower() not in self.authParamsList:

# newHeaders.append(header)

#return self._helpers.buildHttpMessage(newHeaders, None)

if headerName.lower() in self.authParamsList:

header = headerName + ": " + newAuthHeaderVal

newHeaders.append(header)

else:

newHeaders.append(header)

更新body:

if paramType == 6:

paramKey = para.getName()

paramValue = para.getValue()

print paramKey + ":" + paramValue

reqJsonBodyOffset = self._helpers.analyzeRequest(requestResponse).getBodyOffset()

reqJsonBodyString = requestResponse.getRequest().tostring()[reqJsonBodyOffset:]

print reqJsonBodyString

reqJsonBodyStringDict = json.loads(reqJsonBodyString)

#reqJsonBodyStringDict = ast.literal_eval(reqJsonBodyString)

for authParamName in authParamsList:

if authParamName in reqJsonBodyStringDict.keys():

reqJsonBodyStringDict[authParamName] = newAuthParamValue

重新构造请求包:

newRemoveGetPostAuthParamsRequest = self._helpers.buildHttpMessage(jsonReqHeaders, newReqJsonBodyString)

return self._callbacks.makeHttpRequest(requestResponse.getHttpService(), newRequest)

0x02 开发插件

未授权访问漏洞检测:

敏感参数提取:

信息提取:

burp-unauth-checker

需求

自动化检测未授权访问

autorize

authz

authmatrix

auto repeater

上几个插件都挺好,但是还是不太符合,想要的是在浏览的时候就能自动检测是否有未授权访问漏洞。

实现

python编写,实现IScannerCheck接口doPassiveScan方法

authParams.cfg文件存储授权的参数,如token,cookie等

在UI输入框增加授权参数要以英文逗号(,)分隔,并点击save按钮保存,其他操作不需要点击save按钮。

show post body即显示post数据的body内容。

show rspContent即显示响应body内容,建议尽量不开启。

一些授权参数是在get/post参数中的,如user/list?token=xxx,这时可以勾选replace GET/POST Auth Params with替换授权参数值。

默认过滤后缀列表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.lower() in self.authParamsList:

header = headerName + “: ” + newAuthHeaderVal

2-

get/post请求的参数,常规操作buildParameter,updateParameter即可。

json参数,直接将body数据解析为字典再替换授权参数值,然后再将字典转字符串,最后构造新请求数据包。

if paramType == 6:

paramKey = para.getName()

paramValue = para.getValue()

print paramKey + ":" + paramValue

reqJsonBodyOffset = self._helpers.analyzeRequest(requestResponse).getBodyOffset()

reqJsonBodyString = requestResponse.getRequest().tostring()[reqJsonBodyOffset:]

print reqJsonBodyString

reqJsonBodyStringDict = json.loads(reqJsonBodyString)

#reqJsonBodyStringDict = ast.literal_eval(reqJsonBodyString)

for authParamName in authParamsList:

if authParamName in reqJsonBodyStringDict.keys():

reqJsonBodyStringDict[authParamName] = newAuthParamValue

有两个问题

1-字典有【u’’】,

2-还有将字符串转为字典,json数据有空格和单引号

json.loads重新构造的json数据有空格

尝试使用

d = json.dumps(s, separators=(‘,’, ‘:’))

发现类型是str不方便处理,loads()没有separators参数

ast.literal_eval()也一样有空格和单引号……

想直接replace掉空格,但是有些数据可能会有空格……

两个问题的解决方案:

reqJsonBodyStringDict = json.loads(reqJsonBodyString)

……#替换授权参数值

newReqJsonBodyString = json.dumps(reqJsonBodyStringDict,separators=(‘,’, ‘:’))

即先用json.loads()将字符串转字典进行处理后再将字典用json.dumps()转换为字符串来构造请求数据包。

最后再对比原请求和替换了授权参数值的响应body

compareResponses:

if (str(nBody).split() == str(oBody).split()):

一致则为未授权访问漏洞。

暂不提供在ui界面删除授权参数的功能,如要删除直接在authParams.cfg里面删除,切记要将光标移动到最后一个授权参数(末行)的结尾。

坑点

1】dopassivescan的request不能直接用,要复制一个再用,否则会出现请求只能read-only的异常,因为这个请求响应已经完成了,再编辑是没意义的。

解决:

newRemoveGetPostAuthParamsRequest = newRemoveAuthHeaderRequest

2】python中的空要用None,java是null

效果图

0c931a62aac0cb249e84c5dfb4645e2c.png

c1f3f77b56c5d6a6a2c1f5c15922e835.png

burp-sensitive-param-extractor

需求

检测并提取请求参数中的敏感参数名,如userid,username,方便测试越权漏洞,并形成敏感参数字典。

实现

使用python开发,实现IHttpListener接口,processHttpMessage方法。

param-regular.cfg:参数正则配置文件,id表示检测请求参数中包含id的参数,如userid,idcard等

支持4种参数检测:

self.requestParamDict[‘urlParams’] = []

self.requestParamDict[‘BodyParams’] = []

self.requestParamDict[‘cookieParams’] = []

self.requestParamDict[‘jsonParams’] = []

先获取请求的所有类型参数,放到requestParamDict再findSensitiveParam最后write2file。

界面右侧的列表即参数正则,可实时增删,删除只需单击列表元素再点击删除按钮即可。

IHttpListener好像无法实现请求关键词参数高亮,IScanIssue-ScanIssue-self._callbacks.applyMarkers可以,暂不实现参数高亮了。

无法处理较复杂的请求json参数,比如多层次嵌套,这种情况较少,暂不做处理。

坑点

1】据说json的get请求参数可能无法获取最底层键值对?

解决:这种请求的情况较少见,暂不处理。

效果图

08ad31ae93d07e41e3958a99d0a4cff2.png

burp-info-extractor

需求

快速提取数据中有价值的信息,如HTTP响应数据包中的用户名,密码等。

比如一个api(/user/list)返回大量用户名/密码,大多数是json格式(jsonarray),就可以使用此工具快速提取信息。

实现

使用java开发,实现IContextMenuFactory接口createMenuItems方法。

采用两种提取方式:

1.json格式提取

2.正则提取

【1】json格式提取:

采用google gson

【2】正则提取

re库常规操作即可

坑点

1】

现象:

send rsp to bie中空行问题,复制的http请求和手动换行复制body没问题,直接send to 的请求就无法以\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

public void actionPerformed(ActionEvent e) {

// TODO Auto-generated method stub

rspBodyArea.setText(“”);

}

效果图

9c578f983aa17bafdacd2d01246020c0.png

0x03 常见问题

1.多次加载插件出现outofmomoryerror

原因:内存被占满了,重启burp或者加大burp的内存,在启动 Burp 时设置 JVM 的 XX 参数即可,如: java -XX:MaxPermSize=1G -jar burp.jar

2、如何调试

jython目前只能想到print大法……

java的目前我也是用println大法,虽然有可以联动ide进行调试的方法,但还是要编译jar,比较麻。

3、py开发的插件用到第三方库,如requests,但是即使本机安装了requests库,加载插件时候还是提示找不到

原因:jython和python的库不同

解决:

在插件目录放进第三方库即可

或者填入第三方库的位置,如site-package

25b4ed439d8f873b299e734b0f98df96.png

0x04 结语

学习优秀的插件,不用重复造轮子。

参考官方API。

0x05 参考资料