# -*- 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 java.awt import BorderLayout, Dimension
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()
if response is None:
return
response_info = self.helpers.analyzeResponse(response)
body = response[response_info.getBodyOffset():].tostring().decode('utf-8', 'ignore')
request_info = self.helpers.analyzeRequest(messageInfo.getHttpService(), messageInfo.getRequest())
base_url = request_info.getUrl()
headers = response_info.getHeaders()
for header in headers:
if "content-type:" in header.lower() and "javascript" in header.lower():
self.extract_js_urls(body, base_url)
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()
result = "VULNERABLE" if ("index of" in body or "directory listing for" in body) else "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