简介
接到一个安全测试任务,数据包使用安全控件进行了加密。通过开发插件,实现明文测试,最终发现了2个越权。
加解密过程分析
- 访问网站首页,需要先安装一个控件。安装完成后,访问网站发现数据包加密处理。
- 按照以前的测试思路,先打开发浏览器开发工具,根据关键字“encrypt”进行搜索,搜索得的到的结果非常多,不知道从何分析起。
- 无意间查看开发工具的网络请求模块,发现请求127.0.0.1的流量中,有“encrypt”、“decrypt”等关键字(如果Burp 原本抓不到 127.0.0.1 的流量,可在浏览器代理插件的不代理地址中添加 “<-loopback>”)。
分析encrypt接口发现该接口是加密使用的,其请求body是明文数据(json格式)字符串,返回body是对应的密文字符串及hash值。分析decrypt接口发现该接口是解密使用的,其请求body是密文字符串,返回body是对应的明文字符串值。整体过程如下图
插件开发
已经知道了加密、解密过程。为了实现明文测试,需要开发插件支持,插件需要完成以下功能:
- 针对请求体/返回体的密文,对密文进行解密(得到明文,方便repeater模块修改明文)。
- 针对repeater模块的明文请求,自动完成加密,然后发送请求数据包。
整体架构如下:
# -*- coding: UTF-8 -*-
from burp import IBurpExtender, IMessageEditorTabFactory, IMessageEditorTab, IProxyListener, IHttpListener
from java.io import PrintWriter
from javax.swing import JPanel, JScrollPane, JTextArea, SwingUtilities
from java.awt import BorderLayout
import json
import traceback
class BurpExtender(IBurpExtender, IMessageEditorTabFactory, IProxyListener, IHttpListener):
def registerExtenderCallbacks(self, callbacks):
# 注册回调和帮助器对象
self.callbacks = callbacks
self.helpers = callbacks.getHelpers()
self.stdout = PrintWriter(callbacks.getStdout(), True)
# 设置扩展名称并注册消息编辑器标签工厂
callbacks.setExtensionName("Encrypt And Decryption")
callbacks.registerMessageEditorTabFactory(self)
# 注册代理监听器
callbacks.registerProxyListener(self)
self.stdout.println("Encrypt And Decryption")
def createNewInstance(self, controller, editable):
# 创建自定义标签的新实例
return CustomTab(self, controller, editable)
class CustomTab(IMessageEditorTab):
def __init__(self, extender, controller, editable):
# 初始化自定义标签
self.extender = extender
self.controller = controller
self.editable = editable
self.tabPanel = JPanel(BorderLayout())
# 使用JTextArea实现自动换行
self.textArea = JTextArea()
self.textArea.setLineWrap(True)
self.textArea.setWrapStyleWord(True)
self.textArea.setEditable(editable)
scrollPane = JScrollPane(self.textArea)
self.tabPanel.add(scrollPane, BorderLayout.CENTER)
self.currentMessage = None
self.isRequest = False
self.cache = {}
self.originalText = ""
def getTabCaption(self):
# 返回标签的标题
return "Encrypt And Decryption"
def getUiComponent(self):
# 返回UI组件
return self.tabPanel
def isEnabled(self, content, isRequest):
# 确定标签是否应启用
self.isRequest = isRequest
return True
def setMessage(self, content, isRequest):
# 设置当前消息,并根据请求/响应进行解密
self.currentMessage = content
if content is None:
self.textArea.setText("")
else:
try:
if isRequest:
# 处理请求体解密
info = self.extender.helpers.analyzeRequest(content)
body = content[info.getBodyOffset():]
body_string = body.tostring().decode('utf-8', errors='replace')
jsonBody = json.loads(body_string)
# 获取密文字符串
enStr = jsonBody["enStr"]
dencryptData = self.decrypt(enStr)
jsonBody["enStr"] = dencryptData
formattedBody = json.dumps(jsonBody, indent=4)
self.textArea.setText(formattedBody.encode("utf-8").decode("utf-8"))
else:
# 处理响应体解密
info = self.extender.helpers.analyzeResponse(content)
body = content[info.getBodyOffset():]
body_string = body.tostring().decode('utf-8', errors='replace')
jsonBody = json.loads(body_string)
# 获取密文字符串
enStr = jsonBody["enStr"]
dencryptData = self.decrypt(enStr)
jsonBody["enStr"] = dencryptData
formattedBody = json.dumps(jsonBody, indent=4)
self.textArea.setText(formattedBody.encode("utf-8").decode("utf-8"))
except Exception as e:
# 处理解密过程中发生的错误
self.extender.stdout.println("Error occurred: {} at line {}".format(str(e), traceback.format_exc()))
self.extender.stdout.println("Traceback: {}".format(traceback.format_exc()))
self.textArea.setText(body_string)
self.originalText = body_string
def getMessage(self):
# 获取当前消息,如果已修改则更新消息内容
if self.currentMessage is None:
return None
if self.textArea.isEditable() and self.isTextModified():
if self.isRequest:
info = self.extender.helpers.analyzeRequest(self.currentMessage)
else:
info = self.extender.helpers.analyzeResponse(self.currentMessage)
headers = info.getHeaders()
body = self.textArea.getText().encode('utf-8')
self.currentMessage = self.extender.helpers.buildHttpMessage(headers, body)
return self.currentMessage
def isModified(self):
# 判断文本是否已被修改
return self.textArea.isEditable() and self.isTextModified()
def getSelectedData(self):
# 获取选中的文本
return self.textArea.getSelectedText()
def isTextModified(self):
# 判断文本内容是否被修改
return self.textArea.getText() != self.originalText
def decrypt(self, enStr):
'''
解密函数
:param enStr:
:return:
'''
pass
“针对repeater模块的明文请求,自动完成加密”使用burp开发时没有成功,没有找到原因。处于项目时间紧迫,使用了mitmproxy作为burp的上游代理,开发脚本,完成对明文加密。
from mitmproxy import http
import json
def request(flow: http.HTTPFlow) -> None:
if (flow.request.host == "targetHost") and not checkSuffix(flow.request.path) and "targetPath" in flow.request.path and flow.request.method == "POST":
if "application/json" in flow.request.headers.get("content-type"):
try:
bodyJson = flow.request.json()
# 如果是请求是明文进行加密操作
if ":" in bodyJson["enStr"]:
bodyJson["enStr"] = encrypt(bodyJson["enStr"])
# 发送密文请求到目标服务器
flow.request.set_text(json.dumps(bodyJson))
except Exception as e:
print("error", str(e))
def checkSuffix(url):
extension = url.split('.')[-1].lower()
return extension in ['js', 'png', 'jpg', 'jpeg']
def encrypt(plan_txt):
'''
加密方法
:param plan_txt:
:return:
'''
pass
测试结果
通过以上插件,修改数据包的参数发现越权2个(常规思路)。