Last active
May 21, 2021 19:42
-
-
Save jrmdev/e41da1aa4da504b21af64ca6549fd7be to your computer and use it in GitHub Desktop.
Burp Proxy plugin to generate ready to paste text-based evidence for HTTP requests and responses.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## | |
## Evidence Generator Evidence Generator - Burp Extension | |
## | |
## Download Jython and configure it in the Extender options: | |
## http://search.maven.org/remotecontent?filepath=org/python/jython-standalone/2.5.4-rc1/jython-standalone-2.5.4-rc1.jar | |
## | |
## Right click on any request from different Burp Suite tools and send to the extension | |
## | |
from burp import IBurpExtender, ITab, IContextMenuFactory | |
from javax.swing import JPanel, JTextArea, JMenuItem, JScrollPane, JLabel, JTextField, JButton, JOptionPane, JPopupMenu | |
from javax.swing.text import DefaultHighlighter | |
from java.io import PrintWriter | |
from java.util import LinkedList | |
from java.awt import Toolkit | |
from java.awt.event import ActionListener, ComponentListener, MouseAdapter, MouseEvent | |
from java.awt.datatransfer import StringSelection | |
from re import sub, MULTILINE | |
import json | |
import array | |
class BurpExtender(IBurpExtender, IContextMenuFactory): | |
def registerExtenderCallbacks(self, callbacks): | |
self.callbacks = callbacks | |
self.helpers = self.callbacks.getHelpers() | |
self.callbacks.setExtensionName('HTTP Evidence Generator') | |
self.stdout = PrintWriter(self.callbacks.getStdout(), True) | |
self.stderr = PrintWriter(self.callbacks.getStderr(), True) | |
self.stdout.println('Extension loaded') | |
#self.stderr.println('Extension loaded') | |
#self.callbacks.issueAlert('Extension loaded') # Alerts tab | |
self.callbacks.registerContextMenuFactory(self) | |
self.tab = EvidenceGeneratorTab(self.callbacks) | |
self.callbacks.addSuiteTab(self.tab) | |
def createMenuItems(self, invocation): | |
responses = invocation.getSelectedMessages() | |
if responses > 0: | |
ret = LinkedList() | |
MenuItem1 = JMenuItem("Evidence Generator: Generate Evidence") | |
MenuItem1.addActionListener(handleMenuItems(self, responses[0], "MenuItem1")) | |
ret.add(MenuItem1) | |
# To add more: | |
#MenuItem2 = JMenuItem("Evidence Generator: Test") | |
#MenuItem2.addActionListener(handleMenuItems(self, responses[0], "MenuItem2")) | |
#ret.add(MenuItem2) | |
return ret | |
return None | |
class FrameListener(ComponentListener): | |
def __init__(self, tab): | |
self.tab = tab | |
def componentHidden(self, e): | |
pass | |
def componentMoved(self, e): | |
pass | |
def componentShown(self, e): | |
pass | |
def componentResized(self, e): | |
size = e.getComponent().getBounds().getSize() | |
self.tab.textbox1.setBounds(10, 35, size.width-20, 25) | |
self.tab.textbox2_component.setBounds(10, 90, size.width-20, size.height-140) | |
self.tab.button1.setBounds(10, size.height-42, 120, 30) | |
self.tab.button2.setBounds(140, size.height-42, 140, 30) | |
self.tab.button3.setBounds(290, size.height-42, 150, 30) | |
self.tab.button4.setBounds(450, size.height-42, 150, 30) | |
self.tab.button5.setBounds(610, size.height-42, 150, 30) | |
class EvidencePopUp(JPopupMenu, ActionListener): | |
def __init__(self, text_component, encoding='utf-8'): | |
self.text_component = text_component | |
self.text_encoding = encoding | |
self.item = JMenuItem("Beautify JSON") | |
self.item.addActionListener(self) | |
self.add(self.item) | |
def actionPerformed(self, e): | |
if e.getActionCommand() == "Beautify JSON": | |
sel_bytes = self.text_component.getSelectedText() | |
if sel_bytes is None: | |
return | |
text = self.text_component.getText() | |
sel_text = bytearray(sel_bytes).decode(self.text_encoding) | |
(sel_begin, sel_end) = self.text_component.getSelectionBounds() | |
try: | |
o_json = json.loads(sel_text) | |
f_json = json.dumps(o_json, indent=3, sort_keys=False) | |
except Exception as e: | |
print("Cannot beautify JSON: {}".format(repr(e))) | |
return | |
self.text_component.setText(text[0:sel_begin] + array.array('b', f_json.encode(self.text_encoding)) + text[sel_end+1:]) | |
class EvidenceMouseListener(MouseAdapter): | |
def __init__(self, text_component): | |
self.text_component = text_component | |
def mousePressed(self, e): | |
if e.isPopupTrigger(): | |
self.popup(e) | |
def mouseReleased(self, e): | |
if e.isPopupTrigger(): | |
self.popup(e) | |
def popup(self, e): | |
menu = EvidencePopUp(self.text_component) | |
menu.show(e.getComponent(), e.getX(), e.getY()) | |
class EvidenceGeneratorTab(ITab): | |
def __init__(self, callbacks): | |
self.callbacks = callbacks | |
self.helpers = self.callbacks.getHelpers() | |
def getTabCaption(self): | |
return 'HTTP Evidence Generator' | |
def getUiComponent(self): | |
label1 = JLabel("Evidence title:") | |
label1.setBounds(10, 10, 200, 25) | |
label2 = JLabel("Evidence text:") | |
label2.setBounds(10, 65, 200, 25) | |
self.textbox1 = JTextField("", 25) | |
self.textbox2 = self.callbacks.createTextEditor() | |
self.textbox2.setEditable(True) | |
self.textbox2_component = self.textbox2.getComponent() | |
self.textbox2_component.addMouseListener(EvidenceMouseListener(self.textbox2)) | |
self.button1 = JButton("Snip cookies", actionPerformed=self.snip_cookies) | |
self.button2 = JButton("Snip resp. body", actionPerformed=self.snip_resp_body) | |
self.button3 = JButton("Snip selected text", actionPerformed=self.snip_selection) | |
self.button4 = JButton("Keep selected text", actionPerformed=self.keep_selection) | |
self.button5 = JButton("Copy to clipboard", actionPerformed=self.copy_to_clipboard) | |
self.panel = JPanel() | |
self.panel.setLayout(None) | |
self.panel.add(label1) | |
self.panel.add(self.textbox1) | |
self.panel.add(label2) | |
self.panel.add(self.textbox2_component) | |
self.panel.add(self.button1) | |
self.panel.add(self.button2) | |
self.panel.add(self.button3) | |
self.panel.add(self.button4) | |
self.panel.add(self.button5) | |
self.panel.addComponentListener(FrameListener(self)) | |
self.callbacks.customizeUiComponent(self.panel) | |
return self.panel | |
def snip_cookies(self, e): | |
text = self.helpers.bytesToString(self.textbox2.getText()) | |
if 'Cookie: ' in text: | |
text = sub(r"^Cookie: .+$", "Cookie: <Snip>", text, flags=MULTILINE) | |
self.textbox2.setText(text) | |
def snip_resp_body(self, e): | |
text = self.helpers.bytesToString(self.textbox2.getText()) | |
if len(text): | |
index = text.find("Response:") + 10 | |
text = text[:index] + text[index:].split("\n\n", 2)[0] | |
text += "\n\n<!-- Snip -->\n" | |
self.textbox2.setText(text) | |
def keep_selection(self, e): | |
if self.textbox2.getSelectedText(): | |
text = self.helpers.bytesToString(self.textbox2.getText()) | |
index = text.find("Response:") + 10 | |
if text[index:].find("\n\n") > -1: # resp. body not empty | |
resp_body_offset = index + text[index:].find("\n\n") + 2 | |
b1, b2 = self.textbox2.getSelectionBounds() | |
if b1 > resp_body_offset and b2 > resp_body_offset: | |
self.textbox2.setText(text[:resp_body_offset] + "<!-- Snip -->\n" + text[b1:b2] + "\n<!-- Snip -->") | |
def snip_selection(self, e): | |
if self.textbox2.getSelectedText(): | |
text = self.helpers.bytesToString(self.textbox2.getText()) | |
b1, b2 = self.textbox2.getSelectionBounds() | |
self.textbox2.setText(text[:b1] + "<!-- Snip -->" + text[b2:]) | |
def copy_to_clipboard(self, e): | |
text = self.helpers.bytesToString(self.textbox2.getText()) | |
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard() | |
clipboard.setContents(StringSelection(text), None) | |
class handleMenuItems(ActionListener): | |
def __init__(self, extender, messageInfo, menuName): | |
self.extender = extender | |
self.menuName = menuName | |
self.messageInfo = messageInfo | |
self.raw_req = self.extender.helpers.bytesToString(messageInfo.getRequest()).strip() | |
self.raw_res = self.extender.helpers.bytesToString(messageInfo.getResponse()).strip() | |
# Work around MST oddities when copy pasting | |
self.raw_req = self.raw_req.replace("\r", "") | |
self.raw_res = self.raw_res.replace("\r", "") | |
self.raw_req = self.raw_req.replace("\x00", "") | |
self.raw_res = self.raw_res.replace("\x00", "") | |
self.title_field = self.extender.tab.textbox1 | |
self.evidence_field = self.extender.tab.textbox2 | |
self.title_field.setText("") | |
self.evidence_field.setText("") | |
def actionPerformed(self, e): | |
if self.menuName == "MenuItem1": | |
self.evidence_generic(self.messageInfo) | |
#if self.menuName == "MenuItem2": | |
# do stuff | |
def evidence_generic(self, messageInfo): | |
self.title_field.setText("Raw HTTP request / response:") | |
self.evidence_field.setText("Request:\n\n%s\n\nResponse:\n\n%s" % (self.raw_req, self.raw_res)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment