之前电面被问到是否开发过burp插件,回答没有。。很尴尬。。之前都是用burp自带的功能进行测试,没有了解过插件方面,今天看了看插件,发现好多不错的插件,打算自己魔改一个出来,就以flask-session-manager为基础改一个出来吧,方便平时的测试,后期如果再改的话,可能要改成爆破secret_key的方式来探测是否是弱密钥。
Jython开发环境搭建
本机是Mac,所以只讲一下Mac上的安装方式
brew install jython
$ jython
Jython 2.7.1 (default:0df7adb1b397, Jun 30 2017, 19:02:43)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_201
Type "help", "copyright", "credits" or "license" for more information.
>>>
终端输入出现上面这些就说明装好了,炒鸡简单
配置burp
如图配置就行
Jython 第三方库安装
中途势必会用到flask相关的库,所以先安装第三方库,和平时安装一样,不过要调用jython自带的pip
# dawn @ dawndeMacBook-Pro in /usr/local/Cellar/jython/2.7.1/libexec/bin [15:25:00]
$ ./pip install flask
Requirement already satisfied: flask in /usr/local/Cellar/jython/2.7.1/libexec/Lib/site-packages
Requirement already satisfied: itsdangerous>=0.24 in /usr/local/Cellar/jython/2.7.1/libexec/Lib/site-packages (from flask)
Requirement already satisfied: Werkzeug>=0.14 in /usr/local/Cellar/jython/2.7.1/libexec/Lib/site-packages (from flask)
Requirement already satisfied: Jinja2>=2.10 in /usr/local/Cellar/jython/2.7.1/libexec/Lib/site-packages (from flask)
Requirement already satisfied: click>=5.1 in /usr/local/Cellar/jython/2.7.1/libexec/Lib/site-packages (from flask)
Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/Cellar/jython/2.7.1/libexec/Lib/site-packages (from Jinja2>=2.10->flask)
You are using pip version 9.0.1, however version 19.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
然后新建一个flask_session_attack.py,开始写代码了。。
Jython代码编写
首先引入burp的接口
from burp import IBurpExtender
from burp import IContextMenuFactory
from burp import IBurpExtenderCallbacks
from burp import IHttpRequestResponse
from burp import IHttpListener
在 https://portswigger.net/burp/extender/api/ 查看burp提供的详细接口文档
这个 IBurpExtender 和 IBurpExtenderCallbacks 都是必须引入的,其它的根据具体情况决定是否引入,比如IHttpListener是获取http请求以及响应内容的接口等。
然后找找flask-session-manager源代码,稍微改一下。
import zlib
import ast
from itsdangerous import base64_decode
from flask.sessions import SecureCookieSessionInterface
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
def session_cookie_encoder(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error]{}".format(e)
def session_cookie_decoder(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if (secret_key == None):
compressed = False
payload = session_cookie_value
if payload.startswith(b'.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error]{}".format(e)
def decode(cookie, secret_key):
print(session_cookie_decoder(cookie, secret_key))
def encode(cookie_structure,secret_key):
print(session_cookie_encoder(secret_key,cookie_structure))
然后写BurpExtender类
from javax.swing import JMenuItem
from javax.swing import JOptionPane
class BurpExtender(IBurpExtender, IHttpListener, IContextMenuFactory, IHttpRequestResponse,
IBurpExtenderCallbacks):
# 首先需要继承上面引入的接口,不然没法调用
def registerExtenderCallbacks(self, callbacks):
self._actionName = "decode_flask_session" # 选项名称
self._actionName1 = "encode_flask_session" # 选项名称
self._helers = callbacks.getHelpers()
self._callbacks = callbacks
callbacks.setExtensionName("flask_session_manager") # 插件名称
callbacks.registerHttpListener(self) # 注册
callbacks.registerContextMenuFactory(self) # 注册
return
def createMenuItems(self, invocation):
'''
重写的方法,作用是创建菜单子选项,看函数名就差不多能理解了
'''
menu = []
# invocation 是一个不知道哪来的值,没关系,文档里有这个,看看就懂了。
# getSelectedMessages 也不知道哪来的,同上
responses = invocation.getSelectedMessages()
if len(responses) == 1:
# 可以看到上面已经引用了java的swing包了,这就是jython的特性所在,可以引入java的包使用
# 这里创建了两个子选项,按下动作分别指向两个函数 decode_session 和 encode_session
menu.append(
JMenuItem(self._actionName, None, actionPerformed=lambda x, inv=invocation: self.decode_session(inv)))
menu.append(JMenuItem(self._actionName1,None,actionPerformed=lambda x: self.encode_session()))
return menu
return None
def decode_session(self, invocation):
# 解密函数,因为解密需要cookie和secret_key,所以这里造了一个对话框让用户输入已知的secret_key
# 我不知道JOptionPane怎么用,于是百度了一下 'java swing JOptionPane' 就全有了
secret_key = JOptionPane.showInputDialog(None, "secret_key:", "input", JOptionPane.QUESTION_MESSAGE)
invMessage = invocation.getSelectedMessages()
# request 就是一个完整的请求报文
request = invMessage[0].getRequest().tostring()
# 获取选中的需要解密的cookie所在的位置
select_msg_index = invocation.getSelectionBounds()
# 提取cookie
select_cookie = request[select_msg_index[0]:select_msg_index[1]]
# 调用上面的decode函数进行解密
decode(select_cookie, secret_key)
def encode_session(self):
# cookie_structure是需要加密伪造的json格式的原始数据
# 例如 {u'username': u'admin'}
cookie_structure = JOptionPane.showInputDialog(None, "cookie_structure:", "input", JOptionPane.QUESTION_MESSAGE)
secret_key = JOptionPane.showInputDialog(None, "secret_key:", "input", JOptionPane.QUESTION_MESSAGE)
encode(cookie_structure, secret_key)
注释都写在上面了,差不多就这样了,已经能用了。如果想进一步开发,还是要多看看它给的文档。