# -*- coding: utf-8 -*-
from burp import IBurpExtender, IHttpListener, ITab
from javax.swing import (JPanel, JButton, JTextField, JLabel, JComboBox,
JTable, JScrollPane, JTextArea, JSplitPane,
BoxLayout, JTree)
from javax.swing.table import DefaultTableModel, DefaultTableCellRenderer
from javax.swing.tree import DefaultMutableTreeNode, DefaultTreeModel
from javax.swing.border import TitledBorder
from javax.swing.event import TreeSelectionListener
from java.awt import BorderLayout, Dimension, Insets, Color, EventQueue, Font
from java.awt.event import MouseAdapter
import re
class BurpExtender(IBurpExtender, IHttpListener, ITab):
def registerExtenderCallbacks(self, callbacks):
self.callbacks = callbacks
self.helpers = callbacks.getHelpers()
callbacks.setExtensionName("7illight")
callbacks.registerHttpListener(self)
self.cached_keywords = []
self.discovered_map = {}
self.dir_index_check_results = {}
self.init_gui()
callbacks.addSuiteTab(self)
def getTabCaption(self):
return "7illight"
def getUiComponent(self):
return self.main_panel
def init_gui(self):
self.main_panel = JPanel(BorderLayout())
# Discovered JS URLs
self.js_root_node = DefaultMutableTreeNode("Discovered JS URLs")
self.js_tree_model = DefaultTreeModel(self.js_root_node)
self.js_tree = JTree(self.js_tree_model)
js_scroll = JScrollPane(self.js_tree)
js_scroll.setBorder(TitledBorder("Auto JS Mapper"))
# Directory Index Check Results
self.dir_table_model = DefaultTableModel(["URL", "Status", "Result"], 0)
self.dir_table = JTable(self.dir_table_model)
dir_scroll = JScrollPane(self.dir_table)
dir_scroll.setBorder(TitledBorder("Directory Index Checker"))
# Keyword Highlighter
keyword_panel = JPanel()
keyword_panel.setLayout(BoxLayout(keyword_panel, BoxLayout.X_AXIS))
self.scope_selector = JComboBox(["Both", "Request", "Response"])
self.color_selector = JComboBox(["red", "orange", "yellow", "green", "cyan", "blue", "pink", "magenta", "gray"])
self.keyword_field = JTextField(15)
add_button = JButton("Add", actionPerformed=self.add_keyword)
keyword_panel.add(self.scope_selector)
keyword_panel.add(self.color_selector)
keyword_panel.add(self.keyword_field)
keyword_panel.add(add_button)
self.keyword_table_model = DefaultTableModel(["Scope", "Color", "Keyword"], 0)
self.keyword_table = JTable(self.keyword_table_model)
keyword_scroll = JScrollPane(self.keyword_table)
keyword_scroll.setBorder(TitledBorder("Keyword Highlights"))
# Main Split Pane
left_split = JSplitPane(JSplitPane.VERTICAL_SPLIT, js_scroll, dir_scroll)
left_split.setResizeWeight(0.5)
right_split = JSplitPane(JSplitPane.VERTICAL_SPLIT, keyword_panel, keyword_scroll)
right_split.setResizeWeight(0.1)
self.main_split = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left_split, right_split)
self.main_split.setResizeWeight(0.5)
self.main_panel.add(self.main_split, BorderLayout.CENTER)
def add_keyword(self, event):
scope = self.scope_selector.getSelectedItem()
color = self.color_selector.getSelectedItem()
keyword = self.keyword_field.getText().strip()
if keyword:
self.cached_keywords.append((scope, color, keyword))
self.keyword_table_model.addRow([scope, color, keyword])
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
if toolFlag not in [self.callbacks.TOOL_PROXY, self.callbacks.TOOL_REPEATER]:
return
if messageIsRequest:
request_info = self.helpers.analyzeRequest(messageInfo)
url = request_info.getUrl().toString()
if url.endswith("/") and url not in self.dir_index_check_results:
self.check_directory_indexing(url, messageInfo)
else:
response = messageInfo.getResponse()
response_info = self.helpers.analyzeResponse(response)
body = response[response_info.getBodyOffset():].tostring().decode('utf-8', 'ignore')
# Extract JS URLs
headers = response_info.getHeaders()
for header in headers:
if "content-type:" in header.lower() and "javascript" in header.lower():
self.extract_js_urls(body, request_info.getUrl())
# Keyword Highlight
self.highlight_message(messageInfo, response_info, body)
def extract_js_urls(self, body, base_url):
found_urls = set(re.findall(r'["\'](/[^\'"\s]+)["\']', body))
for path in found_urls:
full_url = base_url.getProtocol() + "://" + base_url.getHost() + path
if full_url not in self.discovered_map:
self.discovered_map[full_url] = True
self.js_tree_model.insertNodeInto(DefaultMutableTreeNode(full_url), self.js_root_node, self.js_root_node.getChildCount())
self.js_tree_model.reload()
def check_directory_indexing(self, url, messageInfo):
request_bytes = self.helpers.buildHttpRequest(self.helpers.stringToBytes(url))
response = self.callbacks.makeHttpRequest(messageInfo.getHttpService(), request_bytes).getResponse()
response_info = self.helpers.analyzeResponse(response)
body = response[response_info.getBodyOffset():].tostring().decode('utf-8', 'ignore').lower()
if "index of" in body or "directory listing for" in body:
result = "VULNERABLE"
else:
result = "Safe"
self.dir_index_check_results[url] = result
self.dir_table_model.addRow([url, response_info.getStatusCode(), result])
def highlight_message(self, messageInfo, response_info, body):
body_lower = body.lower()
request_lower = self.helpers.bytesToString(messageInfo.getRequest()).lower()
for scope, color, keyword in self.cached_keywords:
if (scope == "Response" and keyword in body_lower) or \
(scope == "Request" and keyword in request_lower) or \
(scope == "Both" and (keyword in body_lower or keyword in request_lower)):
messageInfo.setHighlight(color)
break