update
233
HaE/HaE.py
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
# Author: Vulkey_Chen
|
||||||
|
# Blog: gh0st.cn
|
||||||
|
# Team: MSTSEC
|
||||||
|
|
||||||
|
import json, re, jsbeautifier
|
||||||
|
|
||||||
|
from burp import IBurpExtender, ITab, IHttpListener, IMessageEditorTabFactory, IMessageEditorTab
|
||||||
|
from javax.swing import JPanel, JLabel, JButton, JTextArea, JTextField, JCheckBox, JTabbedPane, JScrollPane, SwingConstants
|
||||||
|
from java.awt import BorderLayout
|
||||||
|
|
||||||
|
from java.io import PrintWriter
|
||||||
|
|
||||||
|
# color list
|
||||||
|
colors = ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'pink', 'magenta', 'gray']
|
||||||
|
|
||||||
|
# config
|
||||||
|
configFile = "config.json"
|
||||||
|
|
||||||
|
# 获取配置文件内容
|
||||||
|
def getConfig():
|
||||||
|
config = ""
|
||||||
|
with open(configFile, 'r') as content:
|
||||||
|
config = json.load(content)
|
||||||
|
return config
|
||||||
|
|
||||||
|
# 寻找内容
|
||||||
|
def findContent(info, message):
|
||||||
|
info = getConfig()
|
||||||
|
results = {}
|
||||||
|
for i in info:
|
||||||
|
regex = re.compile(info[i]['regex'])
|
||||||
|
regexRes = regex.findall(message)
|
||||||
|
if regexRes != []:
|
||||||
|
results[i] = ','.join(list(set(regexRes)))
|
||||||
|
return results
|
||||||
|
|
||||||
|
class BurpExtender(IBurpExtender, ITab,IHttpListener, IMessageEditorTabFactory):
|
||||||
|
def registerExtenderCallbacks(self, callbacks):
|
||||||
|
self._callbacks = callbacks
|
||||||
|
self._helpers = callbacks.getHelpers()
|
||||||
|
callbacks.setExtensionName("HaE(Highlighter and Extractor)")
|
||||||
|
self._stdout = PrintWriter(callbacks.getStdout(), True)
|
||||||
|
callbacks.registerHttpListener(self)
|
||||||
|
callbacks.registerMessageEditorTabFactory(self)
|
||||||
|
print 'HaE(Highlighter and Extractor)\nAuthor: Vulkey_Chen\nBlog: gh0st.cn\nTeam: MSTSEC'
|
||||||
|
self._callbacks.customizeUiComponent(self.getUiComponent())
|
||||||
|
self._callbacks.addSuiteTab(self)
|
||||||
|
self.endColors = []
|
||||||
|
|
||||||
|
def getTabCaption(self):
|
||||||
|
return 'HaE'
|
||||||
|
|
||||||
|
def createNewInstance(self, controller, editable):
|
||||||
|
return MarkINFOTab(self, controller, editable)
|
||||||
|
|
||||||
|
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
|
||||||
|
if messageIsRequest:
|
||||||
|
return
|
||||||
|
content = messageInfo.getResponse()
|
||||||
|
r = self._helpers.analyzeResponse(content)
|
||||||
|
msg = content[r.getBodyOffset():].tostring()
|
||||||
|
# msg 为响应正文信息
|
||||||
|
info = getConfig()
|
||||||
|
results = findContent(info, msg)
|
||||||
|
colorList = []
|
||||||
|
if results != {}:
|
||||||
|
for i in results:
|
||||||
|
if info[i]['highlight'] == 1 :
|
||||||
|
if info[i]['color'] == 'red':
|
||||||
|
messageInfo.setHighlight(info[i]['color'])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
colorList.append(info[i]['color'])
|
||||||
|
|
||||||
|
if not messageInfo.getHighlight():
|
||||||
|
colorsList = [colors.index(i) for i in colorList]
|
||||||
|
colorsList.sort()
|
||||||
|
# print(colorsList)
|
||||||
|
self.helper(colorsList)
|
||||||
|
endColor = [colors.index(x) for x in self.endColors]
|
||||||
|
# print(endColor)
|
||||||
|
messageInfo.setHighlight(colors[min(endColor)])
|
||||||
|
|
||||||
|
# 颜色升级
|
||||||
|
def helper(self, mylist):
|
||||||
|
l = len(mylist)
|
||||||
|
i = 0
|
||||||
|
stack = []
|
||||||
|
while i < l:
|
||||||
|
if not stack:
|
||||||
|
stack.append(mylist[i])
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
if mylist[i] != stack[-1]:
|
||||||
|
stack.append(mylist[i])
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
stack[-1] -= 1
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if len(stack) == len(set(stack)):
|
||||||
|
self.endColors = [colors[i] for i in stack]
|
||||||
|
else:
|
||||||
|
self.helper(stack)
|
||||||
|
|
||||||
|
def addConfig(self, event):
|
||||||
|
nameText = self.nameTextField.getText()
|
||||||
|
regexText = self.regexTextField.getText()
|
||||||
|
colorText = self.colorTextField.getText()
|
||||||
|
isHighlight = int(self.highlightCheckBox.isSelected())
|
||||||
|
isExtract = int(self.extractCheckBox.isSelected())
|
||||||
|
if colorText in colors:
|
||||||
|
with open(configFile, 'r+') as content:
|
||||||
|
dicts = json.load(content)
|
||||||
|
# 解决r+写入问题
|
||||||
|
content.seek(0,0)
|
||||||
|
content.truncate()
|
||||||
|
if nameText in dicts:
|
||||||
|
self.tipString.setText("Name is existed!")
|
||||||
|
elif not(isHighlight or isExtract):
|
||||||
|
self.tipString.setText("Highlight or Extract?")
|
||||||
|
else:
|
||||||
|
dicts[nameText] = {"regex": regexText, "highlight": isHighlight, "extract": isExtract, "color": colorText}
|
||||||
|
content.write(jsbeautifier.beautify(json.dumps(dicts)))
|
||||||
|
#print(dicts)
|
||||||
|
self.tipString.setText("Save Successfully!")
|
||||||
|
else:
|
||||||
|
self.tipString.setText("Not in colors list.")
|
||||||
|
|
||||||
|
def reloadConfig(self, event):
|
||||||
|
with open(configFile, 'r') as content:
|
||||||
|
self.configTextArea.setText(content.read())
|
||||||
|
|
||||||
|
def getUiComponent(self):
|
||||||
|
self.HaEPanel = JPanel()
|
||||||
|
self.HaEPanel.setBorder(None)
|
||||||
|
self.HaEPanel.setLayout(BorderLayout(0, 0))
|
||||||
|
self.panel = JPanel()
|
||||||
|
self.HaEPanel.add(self.panel, BorderLayout.NORTH)
|
||||||
|
self.panel.setLayout(BorderLayout(0, 0))
|
||||||
|
self.tabbedPane = JTabbedPane(JTabbedPane.TOP)
|
||||||
|
self.panel.add(self.tabbedPane, BorderLayout.CENTER)
|
||||||
|
self.setPanel = JPanel()
|
||||||
|
self.tabbedPane.addTab("Set", None, self.setPanel, None)
|
||||||
|
self.setPanel.setLayout(BorderLayout(0, 0))
|
||||||
|
self.setPanel_1 = JPanel()
|
||||||
|
self.setPanel.add(self.setPanel_1, BorderLayout.NORTH)
|
||||||
|
self.nameString = JLabel("Name")
|
||||||
|
self.setPanel_1.add(self.nameString)
|
||||||
|
self.nameTextField = JTextField()
|
||||||
|
self.setPanel_1.add(self.nameTextField)
|
||||||
|
self.nameTextField.setColumns(10)
|
||||||
|
self.regexString = JLabel("Regex")
|
||||||
|
self.setPanel_1.add(self.regexString)
|
||||||
|
self.regexTextField = JTextField()
|
||||||
|
self.setPanel_1.add(self.regexTextField)
|
||||||
|
self.regexTextField.setColumns(10)
|
||||||
|
self.extractCheckBox = JCheckBox("Extract")
|
||||||
|
self.setPanel_1.add(self.extractCheckBox)
|
||||||
|
self.highlightCheckBox = JCheckBox("Highlight")
|
||||||
|
self.setPanel_1.add(self.highlightCheckBox)
|
||||||
|
self.setPanel_2 = JPanel()
|
||||||
|
self.setPanel.add(self.setPanel_2)
|
||||||
|
self.colorString = JLabel("Color")
|
||||||
|
self.setPanel_2.add(self.colorString)
|
||||||
|
self.colorTextField = JTextField()
|
||||||
|
self.setPanel_2.add(self.colorTextField)
|
||||||
|
self.colorTextField.setColumns(5)
|
||||||
|
self.addBottun = JButton("Add", actionPerformed=self.addConfig)
|
||||||
|
self.setPanel_2.add(self.addBottun)
|
||||||
|
self.tipString = JLabel("");
|
||||||
|
self.setPanel_2.add(self.tipString)
|
||||||
|
self.configPanel = JPanel()
|
||||||
|
self.tabbedPane.addTab("Config", None, self.configPanel, None)
|
||||||
|
self.configPanel.setLayout(BorderLayout(0, 0))
|
||||||
|
self.configString = JLabel("This is config file content.")
|
||||||
|
self.configString.setHorizontalAlignment(SwingConstants.CENTER)
|
||||||
|
self.configPanel.add(self.configString, BorderLayout.NORTH)
|
||||||
|
self.configTextArea = JTextArea()
|
||||||
|
self.configTextArea.setEnabled(False)
|
||||||
|
self.configTextArea.setTabSize(4)
|
||||||
|
self.configTextArea.setLineWrap(True)
|
||||||
|
self.configTextArea.setRows(20)
|
||||||
|
self.configPanel.add(self.configTextArea, BorderLayout.SOUTH)
|
||||||
|
self.scrollPane = JScrollPane(self.configTextArea)
|
||||||
|
self.configPanel.add(self.scrollPane, BorderLayout.SOUTH)
|
||||||
|
self.reloadButton = JButton("Reload", actionPerformed=self.reloadConfig)
|
||||||
|
self.configPanel.add(self.reloadButton, BorderLayout.CENTER)
|
||||||
|
return self.HaEPanel
|
||||||
|
|
||||||
|
class MarkINFOTab(IMessageEditorTab):
|
||||||
|
def __init__(self, extender, controller, editable):
|
||||||
|
self._extender = extender
|
||||||
|
self._helpers = extender._helpers
|
||||||
|
self._editable = editable
|
||||||
|
self._txtInput = extender._callbacks.createTextEditor()
|
||||||
|
self._txtInput.setEditable(editable)
|
||||||
|
|
||||||
|
def getTabCaption(self):
|
||||||
|
return "MarkINFO"
|
||||||
|
|
||||||
|
def getUiComponent(self):
|
||||||
|
return self._txtInput.getComponent()
|
||||||
|
|
||||||
|
# 非响应 没有匹配到不返回Tab标签页
|
||||||
|
def isEnabled(self, content, isRequest):
|
||||||
|
r = self._helpers.analyzeResponse(content)
|
||||||
|
msg = content[r.getBodyOffset():].tostring()
|
||||||
|
info = getConfig()
|
||||||
|
if not isRequest:
|
||||||
|
content = findContent(info, msg)
|
||||||
|
if content != {}:
|
||||||
|
for i in content:
|
||||||
|
if info[i]['extract'] == 1 :
|
||||||
|
return True
|
||||||
|
|
||||||
|
# 设置Tab的内容
|
||||||
|
def setMessage(self, content, isRequest):
|
||||||
|
# 判断是否有内容
|
||||||
|
if content:
|
||||||
|
if not isRequest:
|
||||||
|
r = self._helpers.analyzeResponse(content)
|
||||||
|
msg = content[r.getBodyOffset():].tostring()
|
||||||
|
info = getConfig()
|
||||||
|
contents = findContent(info, msg)
|
||||||
|
result = ""
|
||||||
|
for i in contents:
|
||||||
|
if info[i]['extract'] == 1 :
|
||||||
|
result += "[{}] {}\n".format(i,contents[i])
|
||||||
|
self._txtInput.setText(result)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
26
HaE/config.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"Email": {
|
||||||
|
"color": "yellow",
|
||||||
|
"highlight": 1,
|
||||||
|
"regex": "[\\w-]+(?:\\.[\\w-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?",
|
||||||
|
"extract": 1
|
||||||
|
},
|
||||||
|
"Chinese IDCard": {
|
||||||
|
"color": "orange",
|
||||||
|
"highlight": 1,
|
||||||
|
"regex": "[1-9]\\d{5}(?:19|20)\\d\\d(?:0[1-9]|1[012])(?:0[1-9]|[12]\\d|3[01])\\d{3}(?:\\d|X)",
|
||||||
|
"extract": 1
|
||||||
|
},
|
||||||
|
"Chinese Mobile": {
|
||||||
|
"color": "yellow",
|
||||||
|
"highlight": 1,
|
||||||
|
"regex": "[^0-9]+(1[3-9]\\d{9})[^0-9]+",
|
||||||
|
"extract": 1
|
||||||
|
},
|
||||||
|
"Internal IP Address": {
|
||||||
|
"color": "yellow",
|
||||||
|
"highlight": 1,
|
||||||
|
"regex": "(?:10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(?:172\\.(?:(?:1[6-9])|(?:2\\d)|(?:3[01]))\\.\\d{1,3}\\.\\d{1,3})|(?:192\\.168\\.\\d{1,3}\\.\\d{1,3})",
|
||||||
|
"extract": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
161
README.md
@@ -1,2 +1,159 @@
|
|||||||
# HaE
|
# HaE - 信息高亮与提取者
|
||||||
HaE - BurpSuite Highlighter and Extractor
|
|
||||||
|
## 前言
|
||||||
|
|
||||||
|
HaE(Highlight and Extractor),是基于MarkINFO插件(地址:https://github.com/gh0stkey/BurpSuite-Extender-MarkInfo )的基础进行重构。
|
||||||
|
|
||||||
|
用处:
|
||||||
|
- 高亮标记请求,针对高亮的请求进行深度挖掘
|
||||||
|
- 敏感信息泄露发现
|
||||||
|
|
||||||
|
## 设计想法
|
||||||
|
|
||||||
|
语言:Python
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
功能:
|
||||||
|
- 自定义正则
|
||||||
|
- 自定义高亮颜色
|
||||||
|
- 自定义高亮或提取
|
||||||
|
|
||||||
|
## 设计过程
|
||||||
|
|
||||||
|
### 可视化界面
|
||||||
|
|
||||||
|
UI设计(基于Eclipse可视化设计),基于Java Swing
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
然后将Java代码转换为Python代码即可(**有很多坑~**)
|
||||||
|
|
||||||
|
使用BurpSuite接口:`ITab`创建Tab
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 高亮颜色
|
||||||
|
|
||||||
|
将BurpSuite的所有高亮颜色集成:(仅支持:`red, orange, yellow, green, cyan, blue, pink, magenta, gray`)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 配置文件格式
|
||||||
|
|
||||||
|
选用JSON格式,格式为
|
||||||
|
|
||||||
|
```
|
||||||
|
name: {"regex": regexText, "highlight": isHighlight, "extract": isExtract, "color": colorText}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 颜色优先级和升级
|
||||||
|
|
||||||
|
定义Colors变量:
|
||||||
|
|
||||||
|
`colors = ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'pink', 'magenta', 'gray']`
|
||||||
|
|
||||||
|
利用下标的方式进行优先级排序,当满足2个同颜色条件则以优先级顺序上升颜色。(例如:**两个正则,颜色为橘黄色,该请求两个正则都匹配到了,那么将升级为红色**)
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
贴一些案例,仅供参考,还有更多玩法,可以自我琢磨~
|
||||||
|
|
||||||
|
### 环境设置
|
||||||
|
|
||||||
|
进入Extender - Options - Python Environment
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
载入Jython的Jar包以及载入python的包路径。
|
||||||
|
|
||||||
|
加载插件,选择HaE.py文件:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
加载成功:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
### RUN IT
|
||||||
|
|
||||||
|
#### 添加自定义正则
|
||||||
|
|
||||||
|
```
|
||||||
|
名字:Email
|
||||||
|
|
||||||
|
正则:[\\w-]+(?:\\.[\\w-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?
|
||||||
|
|
||||||
|
高亮颜色:red
|
||||||
|
|
||||||
|
是否高亮和提取:是
|
||||||
|
```
|
||||||
|
|
||||||
|
转到HaE标签页,进行设置,点击Add按钮即可添加
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
HaE - Config查看是否进行配置,点击Reload按钮:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 高亮请求
|
||||||
|
|
||||||
|
在Proxy - HTTP History中可以看见高亮请求,响应标签页中含有`MarkINFO`标签,其中将匹配到的邮箱提取了出来
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 正则优化(参考Demo)
|
||||||
|
|
||||||
|
在正则匹配手机号、身份证号码的时候(纯数字类)会存在一些误报(这里匹配身份证号码无法进行校验,误报率很高),但手机号处理这一块可以解决:
|
||||||
|
|
||||||
|
原正则:
|
||||||
|
|
||||||
|
```
|
||||||
|
(1[3-9]\d{9})
|
||||||
|
```
|
||||||
|
|
||||||
|
误报场景:`12315188888888123`,这时候会匹配到`15188888888`,而实际上这一段并不是手机号,所以完全可以修改正则为:
|
||||||
|
|
||||||
|
```
|
||||||
|
[^0-9]+(1[3-9]\d{9})[^0-9]+
|
||||||
|
```
|
||||||
|
|
||||||
|
也就是要求匹配的手机号前后不能为0-9的数字。
|
||||||
|
|
||||||
|
## 实战用法
|
||||||
|
|
||||||
|
### CMS指纹识别
|
||||||
|
|
||||||
|
例如:识别Discuz,名字:CMS-Discuz,正则:`Powered by Discuz!`,高亮颜色:blue
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Add保存到配置文件中:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
请求识别:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### OSS对象存储信息泄露
|
||||||
|
|
||||||
|
名字:INFO-OSS
|
||||||
|
|
||||||
|
正则:`[A|a]ccess[K|k]ey[I|i]d|[A|a]ccess[K|k]ey[S|s]ecret`
|
||||||
|
|
||||||
|
高亮颜色:cyan
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Add保存到配置文件中:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
请求中识别并提取:
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
BIN
images/15844769689459.jpg
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
images/15845160114052.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
images/15845160387850.jpg
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
images/15845162741518.jpg
Normal file
|
After Width: | Height: | Size: 549 KiB |
BIN
images/15845164967615.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
images/15845168078333.jpg
Normal file
|
After Width: | Height: | Size: 389 KiB |
BIN
images/15845168915243.jpg
Normal file
|
After Width: | Height: | Size: 337 KiB |
BIN
images/15845169108559.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
images/15845171413470.jpg
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
images/15845172203307.jpg
Normal file
|
After Width: | Height: | Size: 177 KiB |
BIN
images/15845175423506.jpg
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
images/15845485039330.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
images/15845485770190.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
images/15845486471590.jpg
Normal file
|
After Width: | Height: | Size: 407 KiB |
BIN
images/15845490590739.jpg
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
images/15845490802944.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
images/15845492243895.jpg
Normal file
|
After Width: | Height: | Size: 198 KiB |