写在前面
这一章中主要介绍了BurpSuite工具的扩展模块如何去编写,整体学习下来的感受呢,讲真并不太好。这里主要是因为Java语言和Python的不同、函数的调用方法不同等等问题,最后我还是觉得这块如果想要深入的话还是学习Java,然后再去开发BurpSuite的扩展会比较好。
这一章的脚本我并没有进行测试,所以说呢,我并不知道是否真的能够使用,可能还会有一些错误(中间有一部分是我自己进行了更改)。这些对于我来说就当做是扩宽知识面、了解一些Python如何去编写BurpSuite扩展就OK了,其他就不再继续深究了。
哦对了忘了说一句,这涨所有的东西想要运行起来的话需要自行准备BurpSuite和jython两个环境。
bhp_fuzzer.py
代码
import burp
import random
from java.util import ArrayList, List
class BurpExtender(burp.IBurpExtender,burp.IIntruderPayloadGeneratorFactory):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
callbacks.registerIntruderPayloadGeneratorFactory(self)
return
def getGeneratorName(self): # type: () -> str
return "BHP Payload Generator"
def createNewInstance(self, attack): # type: (IIntruderAttack) -> IIntruderPayloadGenerator
return BHPFuzzer(self, attack)
class BHPFuzzer(burp.IIntruderPayloadGenerator):
def __init__(self,extender,attack):
self._extender = extender
self._attack = attack
self._helpers = extender._helpers
self.max_payloads = 10
self.num_iterattions = 0
return
def hasMorePayloads(self): # type: () -> bool
if self.num_iterattions == self.max_payloads:
return False
else:
return True
def getNextPayload(self, baseValue): # type: (array) -> attay
# getNextPayload获取的是一个byte[]对象,所以Python这里需要进行bytes to string
# Python3 使用str()函数或decode()函数进行处理
payload = "".join(str(x) for x in baseValue)
# 将所有的payload拼接成一个字符串,下面在mutate_payload函数中会用随机数offset进行切片取值
payload = self.mutate_payload(payload)
self.num_iterattions += 1
return payload
def reset(self): # type: () -> None
self.num_iterattions = 0
return
def mutate_payload(self,original_payload):
picker = random.randint(1,3)
offset = random.randint(0,len(original_payload)-1)
payload = original_payload[:offset]
# 切片取值
if picker == 1:
payload += "'"
if picker == 2:
payload += "<script>alert(1)</script>"
if picker == 3:
chunk_length = random.randint(len(payload[offset:]),len(payload)-1)
repeater = random.randint(1,10)
for i in range(repeater):
payload += original_payload[offset:offset+chunk_length]
payload += original_payload[offset:]
return payload
关于这个脚本
这个脚本主要有三个测试内容,插入一个'
,来测试SQL注入;插入一个反射型XSS的Payload,测试XSS漏洞;最后一个功能比较迷惑,切片截取标记的片段的部分,这个标记片段是从BurpSuite的intruder模块中标记的,然后将这个截取的部分重新插入到标记片段处。
总的来说没什么功能,仅仅只是让你知道一下最基本burp扩展Python脚本的写法,这个扩展并没有什么实际的作用
另外脚本里不能写入中文注释,否则在导入扩展时会报出编码错误。
bhp_bing.py
代码
import burp
from javax.seing import JMenuItem
from java.util import List,ArrayList
from java.net import URL
import socket
import urllib
import json
import re
import base64
import numpy as np
bing_api_key = ""
class BurpExtender(burp.IBurpExtender,burp.IContextMenuFactory):
def registerExtenderCallbacks(self, callbacks): # type: (IBurpExtenderCallbacks) -> None
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
self.context = None
callbacks.setExtensionName("BHP Bing")
callbacks.registerContextMenuFactory(self)
return
def createMenuItems(self, invocation): # type: (IContextMenuInvocation) -> List[JMenuItem]
self.context = invocation
menu_list = ArrayList()
menu_list.add(JMenuItem("Send to Bing",actionPerformed=self.bing_menu))
return menu_list
def bing_menu(self,event):
http_traffic = self.context.getSelectedMessages()
print("%d requests highlighted" % len(http_traffic))
for traffic in http_traffic:
http_service = traffic.getHttpService()
host = http_service.getHost()
print("User selected host: %s" % host)
self.bing_search(host)
return
def bing_search(self,host):
is_ip = re.match("[0-9]+(?:\.[0-9]+){3}",host)
if is_ip:
ip_address = host
domain = False
else:
ip_address = socket.gethostbyname(host)
domain = True
bing_query_string = "'ip:%s'" % ip_address
self.bing_query(bing_query_string)
if domain:
bing_query_string = "'domain:%s'" % host
self.bing_query(bing_query_string)
def bing_query(self,bing_query_string):
print("Performing Bing search: %s" % bing_query_string)
quoted_query = urllib.parse.quote(bing_query_string,safe="(:/)")
requests_url = f"https://api.datamarket.azure.com/Bing/Search/Web?$format=json&$top=20&Query={quoted_query}"
headers =[
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
"Connection: close",
f"Authorization:Basic: {base64.b64encode(bing_api_key)}"
]
boby = "test"
requests_body = self._helpers.buildHttpMessage(headers,boby)
json_boby = self._callbacks.makeHttpRequest(requests_url,443,True,requests_body).tostring()
json_boby = json_boby.split("\r\n\r\n",1)[1]
try:
r = json.loads(json_boby)
if len(r["d"]["results"]):
for site in r["d"]["results"]:
print("*" * 100)
print(site['Title'])
print(site["Url"])
print(site["Description"])
print("*" * 100)
j_url = URL(site['Url'])
if not self._callbacks.isInScope(j_url):
print("Adding to Burp scope")
self._callbacks.includeInScope(j_url)
except:
print("No results from Bing")
pass
return
关于这个脚本
这个脚本还是比较头大的,我这里并没有注册Bing API
,也就没有测试,中间最主要的一点就是如何让BurpSuite发送一个HTTP请求,这么说可能会显得有点简单,最为主要的是如何发送一个符合自己预期的HTTP请求,比如说设置HTTP Body
、更换或设置headers
。
其次,这里所使用的是BurpSuite所提供的函数,跟以往我们自己使用Python是完全不同,并且由于是BurpSuite提供的函数,那么就会带有部分Java的特性,比如说Python没有的数据类型——数组。
解决以上问题我给出的办法就是——学Java吧,用Java开发这个BurpSuite扩展。就这样
bhp_wordlist.py
代码
from burp import IBurpExtender
from burp import IContextMenuFactory
from javax.swing import JMenuItem
from java.util import List,ArrayList
from java.net import URL
import re
from datetime import datetime
from html.parser import HTMLParser
class TagStripper(HTMLParser):
'''
去掉HTTP响应包中的HTML标签
'''
def __init__(self):
super(TagStripper, self).__init__()
self.page_text = []
def handle_data(self, data: str) -> None:
self.page_text.append(data)
def handle_comment(self, data: str) -> None:
self.handle_data(data)
def strip(self,html):
self.feed(html)
return "".join(self.page_text)
class BurpExtender(IBurpExtender, IContextMenuFactory):
def __init__(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
self.context = None
self.host = set()
self.wordlist = set(["password"])
callbacks.setExtensionName("BHP Wordlist")
callbacks.registerContextMenuFactory(self)
return
def createMenuItems(self, invocation): # type: (IContextMenuInvocation) -> List[JMenuItem]
self.context = invocation
menu_list = ArrayList()
menu_list.add(JMenuItem("Create Wordlist",actionPerformed=self.wordlist_menu))
return menu_list
def wordlist_menu(self,event):
http_traffic = self.context.getSelectedMessages()
for traffic in http_traffic:
http_service = traffic.getHttpService()
host = http_service.getHost()
self.host.add(host)
http_response = traffic.getResponse()
if http_response:
self.get_words(http_response)
self.display_wordlist()
return
def get_words(self,http_response):
headers,body = http_response.tostring().strip('\r\n\r\n',1)
if headers.lower().find("content-type: text") == -1:
return
tag_stripper = TagStripper()
page_text = tag_stripper.strip(body)
pattern = re.compile(r'[a-zA-Z]\w{2,}',re.S)
words = re.findall(pattern, page_text)
for word in words:
if len(word) <= 12:
self.wordlist.add(word.lower())
return
def mangle(self,word):
year = datetime.now().year
suffixes = ["","1","!",year]
mangled = []
for password in (word,word.capitalize()):
for suffix in suffixes:
mangled.append(f"{password,suffix}")
return mangled
def display(self):
print(f"#!comment: BHP Wordlist for site(s) %s" % ",".join(self.hosts))
for word in sorted(self.wordlist):
for password in self.mangle(word):
print(password)
return
关于这个脚本
这个我没有进行过多的研究,简单来说这里摆烂了,对我来说感觉并没有太大的作用。程序里最主要起作用的是get_words(self,http_response)
然后改了一下他正则的写法,最后由mangle(self,word)
对获取的字段进行加工。
其中一些使用的BurpSuite中的方法
makeHttpRequest()
这个方法有两种写法:
-
IHttpRequestResponse makeHttpRequest( IHttpService httpService, byte[] request, boolean forceHttp1)
-
byte[] makeHttpRequest(java.lang.String host, int port, boolean useHttps, byte[] request, boolean forceHttp1)
IHttpRequestResponse makeHttpRequest()
byte[] request
对象可以使用Helpers.buildHttpMessage()
进行创建,Python调用方法为self._helpers.buildHttpMessage()
。对应makeHttpResquest()
Python的调用方法为self._callbacks.makeHttpResquest()
。
在Python中,buildHttpMessage
方法第一个参数为List []
,第二个参数为array
,但是这里处理数组的时候有一些问题。众所周知——Python是没有数组的,有的是list
、tuple
、dict
,有一说是list
具有其他语言中的数组特性。这个说法并没能进行验证,Pycharm中使用list一直会报错type error
。
List < String > headers = new ArrayList <> ();
headers.add("POST /console/j_security_check HTTP/1.1");
headers.add("Host: " + url.getHost() + ":" + url.getPort());
headers.add("Content-Type: application/x-www-form-urlencoded");
headers.add("Cookie:ADMINCONSOLESESSION=pTsBVcsdVx2g20mxPJyyPDvqTwQmQDtw7R541DGJGGXD2qh4rDBJ!1211788216");
String user = "user";
String pwd = "pwd";
body = "userName=" + user + "&password=" + pwd + "&submit=+Login+";
byte[] loginMessage = helpers.buildHttpMessage(headers, body.getBytes());
IHttpRequestResponse resp = callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), loginMessage);
byte[] httpResponse = resp.getResponse();
// 另一种request创建
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
IHttpRequestResponse checkUUID = this.callbacks.makeHttpRequest(httpService, insertionPoint.buildRequest(this.helpers.stringToBytes(uuid)));
另外,IHttpService
对象在burp中可以通过抓取的数据包所生成的对象通过.getHttpService()
方法进行生成,可以直接利用,如果需要自定义目标则需要使用第二种写法。
byte[] makeHttpRequest()
这个方法说实话有点懵,怎么说呢,byte[] request
这个对象一直没有弄明白怎么写,看了一些Demo,很多人选择直接下面的方式使用方法
URL url = new URL(VERSION_URI + "?v=" +
currentVersion.getVersionString() +
"&t=" +
(automatic ? "a" : "m") + // reports if automated or manual update
"&b=" +
(CO2Config.isLoadedFromBappStore(AboutTab.this.callbacks) ? "y" : "n") // loaded from a bappstore version?
);
byte[] request = callbacks.getHelpers().buildHttpRequest(url);
byte[] response = callbacks.makeHttpRequest("burpco2.com", 80, false, request);
参考资料
- 初探Burp Suite API 开发
- burp-api-drops
- burp.IBurpExtenderCallbacks.makeHttpRequest()方法的使用及代码示例
- Burp Suite官方API文档_Package burp
写在最后
这一章学起来还是比较吃力,但是也不用过度纠结,你说自己看懂书中,没关系,书中很多都是结合Java的内容去编写的,如果真的想去研究这部分,建议先熟悉BurpSuite API
,知道API中有哪些方法,什么方法可以起到什么作用,什么方法在Python中怎么调用?在Java中怎么调用?这个过程势必会消耗很大一笔时间。
个人看来,这一章起到一个介绍的作用吧,如果感兴趣当然可以继续深究,如果不感兴趣,也不会有什么过多的影响,知道有这么个东西就行了。
Comments | NOTHING