diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..45e05e5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.0.2] - 2023-04-28 + +### Added + +- Get updated request when changing poc type from combo box in GUI. + +### Fixed + +- HTML POC with multipart encoding "enctype" form attribute. + +## [0.0.1] - 2016-05-09 diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 5aaf419..99b62b0 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -1,19 +1,18 @@ package burp; -import burp.pocs.Pocs; -import burp.tab.TabImpl; -import burp.tab.PocCreatorTab; -import burp.tab.PocTabManager; - import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import javax.swing.JMenuItem; import javax.swing.JOptionPane; -import burp.pocs.IPoc; +import burp.pocs.PocGenerator; +import burp.pocs.Pocs; +import burp.tab.PocCreatorTab; +import burp.tab.PocTabManager; +import burp.tab.TabImpl; +import burp.util.Request; /** * CSRF POC Creator extension for Burp Suite @@ -39,7 +38,7 @@ public BurpExtender() { public void registerExtenderCallbacks(IBurpExtenderCallbacks ibec) { this.burpExtenderCallbacks = ibec; this.pocTabManager = new PocTabManager(); - this.pocs = new Pocs(this.burpExtenderCallbacks.getHelpers()); + this.pocs = new Pocs(); ibec.registerContextMenuFactory(this); ibec.setExtensionName("CSRF PoC Creator"); this.burpExtenderCallbacks.addSuiteTab(new TabImpl("CSRF PoC", this.pocTabManager)); @@ -48,11 +47,9 @@ public void registerExtenderCallbacks(IBurpExtenderCallbacks ibec) { while (pocKeys.hasNext()) { String key = pocKeys.next(); JMenuItem item = new JMenuItem(key); - item.addActionListener(BurpExtender.this); + item.addActionListener(this); this.menuItems.add(item); } - this.burpExtenderCallbacks.printOutput("Burp csrf-poc-creator plugin for Burp Suite Free loaded!"); - this.burpExtenderCallbacks.printOutput("Created by @rammarj"); } /** @@ -84,12 +81,11 @@ public void actionPerformed(ActionEvent e) { for (IHttpRequestResponse ihrr : selectedMessages) { try { String selectedPOC = e.getActionCommand(); - IPoc poc = this.pocs.getPoc(selectedPOC); - byte[] pocContent = poc.getPoc(ihrr); - - PocCreatorTab pocCreatorTab = new PocCreatorTab(this.burpExtenderCallbacks, ihrr, this.pocs, pocContent); - pocCreatorTab.setSelectedItem(selectedPOC); - this.pocTabManager.addTab(String.valueOf(this.tabCount++), pocCreatorTab); + PocGenerator pg = this.pocs.getPoc(selectedPOC); + byte[] poc = pg.generate(Request.fromHTTPRequestResponse(ihrr, this.burpExtenderCallbacks.getHelpers())); + PocCreatorTab pct = new PocCreatorTab(this.burpExtenderCallbacks, ihrr, this.pocs, poc); + pct.setSelectedItem(selectedPOC); + this.pocTabManager.addTab(String.valueOf(this.tabCount++), pct); } catch (Exception ex) { JOptionPane.showMessageDialog(this.pocTabManager, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } diff --git a/src/main/java/burp/Util.java b/src/main/java/burp/Util.java deleted file mode 100644 index f6553a0..0000000 --- a/src/main/java/burp/Util.java +++ /dev/null @@ -1,75 +0,0 @@ -package burp; - -import java.util.LinkedList; -import java.util.List; -import java.util.SplittableRandom; -import java.util.stream.Collectors; -/** - * - * @author Joaquin R. Martinez - */ -public class Util { - - /** - * Escapes backslashes and doublequotes - * @param escape the string to escape - * @return the escaped string - */ - public static String escape(String escape){ - return escape.replace("\\", "\\\\").replace("\"", "\\\""); - } - - /** - * Generates a random string (for Multipart requests) - * @param lenght the char number of the random string - * @return the random string - */ - public static String generateRandomString(int lenght) { - SplittableRandom splittableRandom = new SplittableRandom(); - StringBuffer a = new StringBuffer(); - int nextInt, ext; - for (int i = 0; i < lenght; i++) { - nextInt = splittableRandom.nextInt(0, 2); - ext = 'a'; - if (nextInt == 1) { - ext = splittableRandom.nextInt('A', 'Z'); - } else { - ext = splittableRandom.nextInt('a', 'z'); - } - a.append((char) ext); - } - return a.toString(); - } - - /** - * Join all parameters with a "&" - * @param p the list of Parameters to join - * @return the joined parameters as a string - */ - public static String joinParameters(List p) { - return p.stream().map(Parameter::toString) - .collect(Collectors.joining("&")); - } - - /** - * Build a string to a list of Header objects - * @param headers the string to build - * @return a list of Header objects - */ - public static List
parseHeaders(List headers){ - List
a = new LinkedList<>(); - headers.stream().map(next -> Header.parse(next)).forEach(build -> { - a.add(build); - }); - return a; - } - - /** - * Tries to encode some problematic HTML when adding to a form value or name. - * @param encode the string to encode. - * @return escaped problematic html chars. - */ - public static String encodeHTML(String encode){ - return encode.replace("\"", """); - } -} diff --git a/src/main/java/burp/pocs/AjaxPoc.java b/src/main/java/burp/pocs/AjaxPoc.java index a54b2b1..cb649a0 100644 --- a/src/main/java/burp/pocs/AjaxPoc.java +++ b/src/main/java/burp/pocs/AjaxPoc.java @@ -1,82 +1,113 @@ package burp.pocs; -import burp.BurpExtender; -import burp.IExtensionHelpers; -import burp.IHttpRequestResponse; +import java.util.List; + import burp.IRequestInfo; -import burp.Parameter; -import burp.Util; +import burp.util.Header; +import burp.util.Parameter; +import burp.util.Request; +import burp.util.Util; /** * Ajax CSRF POCs * * @author Joaquin R. Martinez */ -public class AjaxPoc implements IPoc { - - private IExtensionHelpers helpers; - - public AjaxPoc(IExtensionHelpers helpers) { - this.helpers = helpers; +public class AjaxPoc implements PocGenerator { + + @Override + public byte[] generate(final Request request) { + String lineSeparator = System.lineSeparator(); + String scriptTag = createScriptTag(request, lineSeparator); + String formTag = createFormTag(lineSeparator); + return createHTMLPage(scriptTag + formTag, lineSeparator).getBytes(); } - @Override - public byte[] getPoc(final IHttpRequestResponse request) { - String lineSeparator = System.lineSeparator(); - StringBuilder pocString = new StringBuilder(); - pocString.append("").append(lineSeparator); - pocString.append("").append(lineSeparator).append(" ").append(lineSeparator); - pocString.append("").append(lineSeparator).append(" " + lineSeparator; + return script; + } + + private String createGETXHRRequest(String url, String lineSeparator) { + String getRequest = String.format(" xhr.open(\"GET\", \"%s\", true);%s", url, lineSeparator); + getRequest += " xhr.send();" + lineSeparator; + return getRequest; + } + + private String createNotGETXHRRequest(final Request request, String lineSeparator) { + String postRequest = ""; + postRequest += String.format(" xhr.open(\"%s\", \"%s\", true);%s", request.getMethod(), + request.getUrl().toString(), lineSeparator); + postRequest += addHeaders(request.getHeaders(), lineSeparator); + postRequest += " xhr.withCredentials = true;" + lineSeparator; + postRequest += " var body = " + createBody(request, lineSeparator) + lineSeparator; + postRequest += " var aBody = new Uint8Array(body.length);" + lineSeparator; + postRequest += " for (var i = 0; i < aBody.length; i++)" + lineSeparator; + postRequest += " aBody[i] = body.charCodeAt(i);" + lineSeparator; + postRequest += " xhr.send(new Blob([aBody]));" + lineSeparator; + return postRequest; + } - if ("GET".equals(method)) { - pocString.append(requestInfo.getUrl()).append("\", true);").append(lineSeparator); - pocString.append(" xhr.send();\n"); - } else { - pocString.append(requestInfo.getUrl().toString()).append("\", true);").append(lineSeparator); - String body = helpers.bytesToString(request.getRequest()).substring(requestInfo.getBodyOffset()); - body = Util.escape(body); - String accept = "*/*"; - String content = "text/plain"; - for (Parameter next : Util.parseHeaders(requestInfo.getHeaders())) { - if ("Accept".equalsIgnoreCase(next.getName())) { - accept = next.getValue(); - } - if ("Content-Type".equalsIgnoreCase(next.getName())) { - content = next.getValue(); - } - } - pocString.append(" xhr.setRequestHeader(\"Accept\", \"").append(accept).append("\");").append(lineSeparator); - pocString.append(" xhr.setRequestHeader(\"Content-Type\", \"").append(content).append("\");").append(lineSeparator); - pocString.append(" xhr.withCredentials = true;").append(lineSeparator).append(" var body = "); + private String addHeaders(final List
headers, String lineSeparator) { + String accept = "*/*"; + String content = "text/plain"; + for (Parameter next : headers) { + if ("Accept".equalsIgnoreCase(next.getName())) + accept = next.getValue(); + if ("Content-Type".equalsIgnoreCase(next.getName())) + content = next.getValue(); + } + + String pocString = String.format(" xhr.setRequestHeader(\"Accept\", \"%s\");", accept) + lineSeparator; + pocString += String.format(" xhr.setRequestHeader(\"Content-Type\", \"%s\");", content) + lineSeparator; + return pocString; + } + + private String createHTMLPage(String body, String lineSeparator) { + String html = "" + lineSeparator; + html += "" + lineSeparator; + html += " " + lineSeparator; + html += "" + lineSeparator; + html += body; + html += "" + lineSeparator; + html += ""; + return html; + } + + private String createBody(final Request request, final String lineSeparator) { + String body = Util.escape(request.getRequestBody()); + String formattedBody = String.format("\"%s\";%s", body, lineSeparator); + if (request.getContentType() == IRequestInfo.CONTENT_TYPE_MULTIPART) { + formattedBody = createMultipartBody(body, lineSeparator); + } + return formattedBody; + } + + private String createMultipartBody(final String body, final String lineSeparator) { + String formattedLines = ""; + String[] lines = body.split("\r\n"); + for (int i = 0; i < lines.length; i++) { + String endLine = (i == lines.length - 1) ? ";" : " +"; + formattedLines += String.format("\"%s\\r\\n\"%s%s", lines[i], endLine, lineSeparator); + } + return formattedLines; + } - if (requestInfo.getContentType() == IRequestInfo.CONTENT_TYPE_MULTIPART) { - String[] lines = body.split("\r\n"); - for (int i = 0; i < lines.length; i++) { - String line = lines[i]; - if (i == lines.length - 1) { - pocString.append("\"").append(line).append("\\r\\n\";").append(lineSeparator); - } else { - pocString.append("\"").append(line).append("\\r\\n\" +").append(lineSeparator); - } - } - } else { - pocString.append("\"").append(body).append("\";").append(lineSeparator); - } - pocString.append(" var aBody = new Uint8Array(body.length);").append(lineSeparator); - pocString.append(" for (var i = 0; i < aBody.length; i++)").append(lineSeparator); - pocString.append(" aBody[i] = body.charCodeAt(i); ").append(lineSeparator); - pocString.append(" xhr.send(new Blob([aBody]));").append(lineSeparator); - } - pocString.append(" }").append(lineSeparator).append(" \n
").append(lineSeparator); - pocString.append(" ").append(lineSeparator); - pocString.append("
").append(lineSeparator).append(" ").append(lineSeparator).append(""); - return pocString.toString().getBytes(); - } - } diff --git a/src/main/java/burp/pocs/HtmlPoc.java b/src/main/java/burp/pocs/HtmlPoc.java index 2ff13e7..2d45f3a 100644 --- a/src/main/java/burp/pocs/HtmlPoc.java +++ b/src/main/java/burp/pocs/HtmlPoc.java @@ -1,50 +1,52 @@ package burp.pocs; -import burp.BurpExtender; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IHttpRequestResponse; +import java.util.List; + import burp.IParameter; import burp.IRequestInfo; -import burp.Util; -import java.util.List; +import burp.util.Parameter; +import burp.util.Request; +import burp.util.Util; /** * HTML CSRF POCs * * @author Joaquin R. Martinez */ -public class HtmlPoc implements IPoc { +public class HtmlPoc implements PocGenerator { + + @Override + public byte[] generate(final Request request) { + String enctype = ""; + if (request.getContentType() == IRequestInfo.CONTENT_TYPE_MULTIPART) { + enctype = "enctype=\"multipart/form-data\""; + } + String lineSep = System.lineSeparator(); + String pocString = String.format("\t
%s", request.getMethod(), + request.getUrl().toString(), enctype, lineSep); + // params + List inputs = request.getParameters().stream().map(e -> createInput(e)).toList(); + pocString += String.join(lineSep, inputs) + lineSep; + pocString += "\t\t" + lineSep; + pocString += "\t" + lineSep; + return createHTMLPage(pocString, lineSep).getBytes(); + } + + private String createInput(IParameter parameter) { + String name = Util.encodeHTML(parameter.getName()); + String value = Util.encodeHTML(parameter.getValue()); + return String.format("\t\t", name, value); + } - private IExtensionHelpers helpers; - - public HtmlPoc(IExtensionHelpers helpers) { - this.helpers = helpers; + private String createHTMLPage(String body, String lineSeparator) { + String html = "" + lineSeparator; + html += "" + lineSeparator; + html += " " + lineSeparator; + html += "" + lineSeparator; + html += body; + html += "" + lineSeparator; + html += ""; + return html; } - - @Override - public byte[] getPoc(final IHttpRequestResponse request) { - String lineSep = System.lineSeparator(); - StringBuilder pocString = new StringBuilder(); - IRequestInfo requestInfo = helpers.analyzeRequest(request); - pocString.append("").append(lineSep); - pocString.append("").append(lineSep) - .append(" ").append(lineSep); - pocString.append("").append(lineSep); - pocString.append("\t
").append(lineSep); - // params - List parameters = requestInfo.getParameters(); - parameters.forEach((parameter) -> { - pocString.append("\t\t").append(lineSep); - }); - pocString.append("\t\t").append(lineSep); - pocString.append("\t").append(lineSep).append("").append(lineSep).append(""); - return pocString.toString().getBytes(); - } - } diff --git a/src/main/java/burp/pocs/IPoc.java b/src/main/java/burp/pocs/PocGenerator.java similarity index 73% rename from src/main/java/burp/pocs/IPoc.java rename to src/main/java/burp/pocs/PocGenerator.java index a700191..b437688 100644 --- a/src/main/java/burp/pocs/IPoc.java +++ b/src/main/java/burp/pocs/PocGenerator.java @@ -2,11 +2,12 @@ package burp.pocs; import burp.IHttpRequestResponse; +import burp.util.Request; /** * @author Joaquin R. Martinez */ -public interface IPoc { +public interface PocGenerator { /** * Returns the PoC code. @@ -14,6 +15,6 @@ public interface IPoc { * @return the PoC code. * @throws java.lang.Exception */ - public byte[] getPoc(final IHttpRequestResponse r) throws Exception; + public byte[] generate(final Request request); } diff --git a/src/main/java/burp/pocs/Pocs.java b/src/main/java/burp/pocs/Pocs.java index 2ebb101..5022e1f 100644 --- a/src/main/java/burp/pocs/Pocs.java +++ b/src/main/java/burp/pocs/Pocs.java @@ -6,8 +6,6 @@ import java.util.Iterator; import java.util.Map; -import burp.IExtensionHelpers; - /** * Contains all types of PoC's supported by this plugin. * @@ -15,32 +13,32 @@ */ public class Pocs { - private final Map pocs; + private final Map pocs; /** * Inaccesible constructor. */ - public Pocs(IExtensionHelpers helpers) { + public Pocs() { this.pocs = new HashMap<>(); - this.pocs.put("Ajax", new AjaxPoc(helpers)); - this.pocs.put("HTML", new HtmlPoc(helpers)); + this.pocs.put("Ajax", new AjaxPoc()); + this.pocs.put("HTML", new HtmlPoc()); // Add more kind of PoC's } /** - * Get the {@link IPoc} object by its key. + * Get the {@link PocGenerator} object by its key. * - * @param key the key of the {@link IPoc}. - * @return the {@link IPoc} object. + * @param key the key of the {@link PocGenerator}. + * @return the {@link PocGenerator} object. */ - public IPoc getPoc(String key) { + public PocGenerator getPoc(String key) { return pocs.get(key); } /** - * Get the {@link IPoc} as a {@link Enumeration}. + * Get the {@link PocGenerator} as a {@link Enumeration}. * - * @return an {@link Iterator} with the keys of all {@link IPoc} objects. + * @return an {@link Iterator} with the keys of all {@link PocGenerator} objects. */ public Iterator getPocKeys() { return this.pocs.keySet().iterator(); diff --git a/src/main/java/burp/tab/POCTypesComboBox.java b/src/main/java/burp/tab/POCTypesComboBox.java deleted file mode 100644 index 4355067..0000000 --- a/src/main/java/burp/tab/POCTypesComboBox.java +++ /dev/null @@ -1,45 +0,0 @@ -package burp.tab; - -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.util.Iterator; - -import javax.swing.JComboBox; -import javax.swing.JOptionPane; - -import burp.IHttpRequestResponse; -import burp.ITextEditor; -import burp.pocs.IPoc; -import burp.pocs.Pocs; - -public class POCTypesComboBox extends JComboBox implements ItemListener { - - private static final long serialVersionUID = 1L; - private IHttpRequestResponse request; - private ITextEditor textEditor; - private Pocs pocs; - - public POCTypesComboBox(ITextEditor textEditor, IHttpRequestResponse request, Pocs pocs) { - this.textEditor = textEditor; - this.request = request; - this.pocs = pocs; - Iterator pocKeys = pocs.getPocKeys(); - while (pocKeys.hasNext()) { - addItem(pocKeys.next()); - } - addItemListener(this); - } - - @Override - public void itemStateChanged(ItemEvent e) { - String selectedItem = getSelectedItem().toString(); - IPoc poc = this.pocs.getPoc(selectedItem); - try { - byte[] pocContent = poc.getPoc(this.request); - this.textEditor.setText(pocContent); - } catch (Exception ex) { - JOptionPane.showMessageDialog(this, ex, "Error", JOptionPane.ERROR_MESSAGE); - } - } - -} diff --git a/src/main/java/burp/tab/PocCreatorTab.java b/src/main/java/burp/tab/PocCreatorTab.java index 858e016..1976525 100644 --- a/src/main/java/burp/tab/PocCreatorTab.java +++ b/src/main/java/burp/tab/PocCreatorTab.java @@ -3,18 +3,23 @@ import java.awt.BorderLayout; import java.awt.FlowLayout; +import java.util.Iterator; +import javax.swing.JComboBox; import javax.swing.JLabel; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSplitPane; -import burp.BurpExtender; import burp.IBurpExtenderCallbacks; import burp.IExtensionHelpers; import burp.IHttpRequestResponse; import burp.IMessageEditor; import burp.ITextEditor; +import burp.pocs.PocGenerator; import burp.pocs.Pocs; import burp.tab.buttons.CopyPOCButton; import burp.tab.buttons.SavePOCButton; +import burp.util.MessageEditorController; +import burp.util.Request; /** * POC Creator tab @@ -26,27 +31,48 @@ public class PocCreatorTab extends JPanel { private static final long serialVersionUID = 1L; private final ITextEditor textEditor; private IMessageEditor messageEditor; - private POCTypesComboBox pocTypesCombo; + private JComboBox pocTypesCombo; /** * Creates pocString new tab for pocString poc * - * @param request the request to show on the left - * @param poc the poc code + * @param ihrr the request to show on the left + * @param currentPoc the poc code */ - public PocCreatorTab(IBurpExtenderCallbacks callbacks, IHttpRequestResponse request, Pocs pocs, byte[] poc) { + public PocCreatorTab(IBurpExtenderCallbacks callbacks, IHttpRequestResponse ihrr, Pocs pocs, byte[] currentPoc) { super(new BorderLayout(10, 10)); this.textEditor = callbacks.createTextEditor(); - this.pocTypesCombo = new POCTypesComboBox(textEditor, request, pocs); + IExtensionHelpers helpers = callbacks.getHelpers(); /* Making our message editor great with burp normal popup menu */ - MessageEditorController editorController = new MessageEditorController(callbacks.getHelpers(), request, messageEditor); + MessageEditorController editorController = new MessageEditorController(helpers, ihrr, messageEditor); this.messageEditor = callbacks.createMessageEditor(editorController, true); - + // POC types combo + this.pocTypesCombo = new JComboBox<>(); + Iterator pocKeys = pocs.getPocKeys(); + while (pocKeys.hasNext()) { + pocTypesCombo.addItem(pocKeys.next()); + } + + pocTypesCombo.addItemListener(e -> { + String selectedItem = pocTypesCombo.getSelectedItem().toString(); + PocGenerator generator = pocs.getPoc(selectedItem); + if (this.messageEditor.isMessageModified()) + ihrr.setRequest(this.messageEditor.getMessage()); + + byte[] pocContent = null; + try { + pocContent = generator.generate(Request.fromHTTPRequestResponse(ihrr, helpers)); + } catch (Exception ex) { + JOptionPane.showMessageDialog(this, ex.getMessage(), "", JOptionPane.WARNING_MESSAGE); + } + this.textEditor.setText(pocContent); + }); + this.add(BorderLayout.CENTER, createEditorSplitPane()); - this.add(BorderLayout.SOUTH, createButtonsPanel(callbacks.getHelpers())); - this.textEditor.setText(poc); - this.messageEditor.setMessage(request.getRequest(), true); + this.add(BorderLayout.SOUTH, createButtonsPanel(helpers)); + this.textEditor.setText(currentPoc); + this.messageEditor.setMessage(ihrr.getRequest(), true); callbacks.customizeUiComponent(PocCreatorTab.this);// burp lookandfeel } @@ -70,8 +96,8 @@ private JPanel createButtonsPanel(IExtensionHelpers helpers) { JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); buttonsPanel.add(new JLabel("PoC type: ")); buttonsPanel.add(pocTypesCombo); - buttonsPanel.add(new CopyPOCButton(textEditor,helpers)); - buttonsPanel.add(new SavePOCButton(textEditor,helpers)); + buttonsPanel.add(new CopyPOCButton(textEditor, helpers)); + buttonsPanel.add(new SavePOCButton(textEditor, helpers)); return buttonsPanel; } diff --git a/src/main/java/burp/Header.java b/src/main/java/burp/util/Header.java similarity index 90% rename from src/main/java/burp/Header.java rename to src/main/java/burp/util/Header.java index e7cee7f..e44f850 100644 --- a/src/main/java/burp/Header.java +++ b/src/main/java/burp/util/Header.java @@ -1,5 +1,5 @@ -package burp; +package burp.util; /** * @@ -13,7 +13,7 @@ public class Header extends Parameter { * @param value the header value */ public Header(String name, String value) { - super(name, value, Type.PARAM_HEADER); + super(name, value, Parameter.PARAM_HEADER); } /** diff --git a/src/main/java/burp/IHttpServiceImpl.java b/src/main/java/burp/util/IHttpServiceImpl.java similarity index 76% rename from src/main/java/burp/IHttpServiceImpl.java rename to src/main/java/burp/util/IHttpServiceImpl.java index 22e8bfb..c8844af 100644 --- a/src/main/java/burp/IHttpServiceImpl.java +++ b/src/main/java/burp/util/IHttpServiceImpl.java @@ -1,7 +1,10 @@ -package burp; +package burp.util; import java.net.URL; + +import burp.IHttpService; +import burp.IRequestInfo; /** * * @author Joaquin R. Martinez @@ -18,14 +21,6 @@ public IHttpServiceImpl(URL url) { this.url = url; } - /** - * Creates a {@link IHttpServiceImpl} using a {@link IRequestInfo} - * @param info {@link IRequestInfo} to use. - */ - public IHttpServiceImpl(IRequestInfo info) { - this(info.getUrl()); - } - /** * @return the host */ diff --git a/src/main/java/burp/tab/MessageEditorController.java b/src/main/java/burp/util/MessageEditorController.java similarity index 90% rename from src/main/java/burp/tab/MessageEditorController.java rename to src/main/java/burp/util/MessageEditorController.java index 3f66de5..7296d0e 100644 --- a/src/main/java/burp/tab/MessageEditorController.java +++ b/src/main/java/burp/util/MessageEditorController.java @@ -1,9 +1,8 @@ -package burp.tab; +package burp.util; import burp.IExtensionHelpers; import burp.IHttpRequestResponse; import burp.IHttpService; -import burp.IHttpServiceImpl; import burp.IMessageEditor; import burp.IMessageEditorController; import burp.IRequestInfo; @@ -23,7 +22,7 @@ public MessageEditorController(IExtensionHelpers helpers, IHttpRequestResponse r @Override public IHttpService getHttpService() { IRequestInfo analyzeRequest = this.helpers.analyzeRequest(this.request); - return new IHttpServiceImpl(analyzeRequest); + return new IHttpServiceImpl(analyzeRequest.getUrl()); } @Override diff --git a/src/main/java/burp/Parameter.java b/src/main/java/burp/util/Parameter.java similarity index 81% rename from src/main/java/burp/Parameter.java rename to src/main/java/burp/util/Parameter.java index 0772633..192d914 100644 --- a/src/main/java/burp/Parameter.java +++ b/src/main/java/burp/util/Parameter.java @@ -1,8 +1,9 @@ -package burp; +package burp.util; -import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import burp.IParameter; /** * Implementation of IParameter interface. @@ -13,7 +14,7 @@ public class Parameter implements IParameter { private String name; protected String value; - protected Type type; + protected byte type; /** Sets the name of this parameter. * @param name the name of the parameter. @@ -33,10 +34,11 @@ public void setValue(String value) { /** * Types of parameters. */ - enum Type { - PARAM_URL, PARAM_HEADER, PARAM_MULTIPART, - PARAM_FORM_URL_ENCODED, PARAM_UNKNOWN - } + public static final byte PARAM_HEADER = 20; + public static final byte PARAM_MULTIPART = 21; + public static final byte PARAM_FORM_URL_ENCODED = 22; + public static final byte PARAM_UNKNOWN = 23; + /** * Constructs a new parameter with its given name, value and type. @@ -44,7 +46,7 @@ enum Type { * @param value the value of the parameter. * @param type the type of the parameter. */ - public Parameter(String name, String value, Type type) { + public Parameter(String name, String value, byte type) { this.name = name.trim(); this.value = value.trim(); this.type = type; @@ -56,27 +58,18 @@ public Parameter(String name, String value, Type type) { public Parameter() { this.name = ""; this.value = ""; - this.type = Type.PARAM_URL; + this.type = PARAM_URL; } /** * Deprecated * Deprecated. Use {@link #getParameterType() } instead. - * @deprecated * @see #getParameterType() */ @Override public byte getType() { - return 0; - } - - /** - * Gets the parameter type. - * @return the type of the parameter. - */ - public Type getParameterType() { return this.type; } - + /** Gets the name of this parameter. * @return the name of the parameter. */ @@ -136,9 +129,7 @@ public int getValueEnd() { @Override public String toString() { StringBuilder a = new StringBuilder(); - if (null == type) - a.append(getName()).append("=").append(getValue()).toString(); - else switch (type) { + switch (type) { case PARAM_MULTIPART: a.append("Content-Disposition: form-data; name=\"") .append(this.getName()).append("\"\r\n") @@ -146,9 +137,7 @@ else switch (type) { break; case PARAM_FORM_URL_ENCODED: case PARAM_URL: - try { - a.append(getName()).append("=").append(URLEncoder.encode(getValue(), "UTF-8")); - } catch (UnsupportedEncodingException ex) {} + a.append(getName()).append("=").append(URLEncoder.encode(getValue(), StandardCharsets.UTF_8)); break; case PARAM_HEADER: a.append(getName()).append(": ").append(getValue()); diff --git a/src/main/java/burp/util/Request.java b/src/main/java/burp/util/Request.java new file mode 100644 index 0000000..86a14a8 --- /dev/null +++ b/src/main/java/burp/util/Request.java @@ -0,0 +1,73 @@ +package burp.util; + +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import burp.IExtensionHelpers; +import burp.IHttpRequestResponse; +import burp.IParameter; +import burp.IRequestInfo;; + +public class Request { + + private final String method; + private final URL url; + private final String requestBody; + private final List
headers; + private final byte contentType; + private final List parameters; + + public Request(String method, URL url, String requestBody, List
headers, byte contentType, + List parameters) { + super(); + this.method = method; + this.url = url; + this.requestBody = requestBody; + this.headers = headers; + this.contentType = contentType; + this.parameters = parameters; + } + + public String getMethod() { + return method; + } + + public URL getUrl() { + return url; + } + + public String getRequestBody() { + return requestBody; + } + + public List
getHeaders() { + return headers; + } + + public byte getContentType() { + return contentType; + } + + public List getParameters() { + return parameters; + } + + public static Request fromHTTPRequestResponse(IHttpRequestResponse hrr, IExtensionHelpers h) { + IRequestInfo requestInfo = h.analyzeRequest(hrr); + String body = h.bytesToString(hrr.getRequest()).substring(requestInfo.getBodyOffset()); + List
headers = requestInfo.getHeaders().stream().map(next -> Header.parse(next)).toList(); + URL url = requestInfo.getUrl(); + List parameters = requestInfo.getParameters().stream().filter(e -> isValidParameter(e)).toList(); + return new Request(requestInfo.getMethod(), url, body, headers, requestInfo.getContentType(), parameters); + } + + private static boolean isValidParameter(IParameter e) { + return e.getType() == IParameter.PARAM_BODY || e.getType() == IParameter.PARAM_URL + || e.getType() == IParameter.PARAM_MULTIPART_ATTR; + } + +} diff --git a/src/main/java/burp/util/Util.java b/src/main/java/burp/util/Util.java new file mode 100644 index 0000000..469cecc --- /dev/null +++ b/src/main/java/burp/util/Util.java @@ -0,0 +1,59 @@ +package burp.util; + +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.SplittableRandom; +import java.util.random.RandomGenerator; + +import burp.IExtensionHelpers; +import burp.IHttpRequestResponse; +import burp.IParameter; +import burp.IRequestInfo; + +/** + * + * @author Joaquin R. Martinez + */ +public class Util { + + /** + * Escapes backslashes and doublequotes + * + * @param escape the string to escape + * @return the escaped string + */ + public static String escape(String escape) { + return escape.replace("\\", "\\\\").replace("\"", "\\\""); + } + + /** + * Generates a random string (for Multipart requests) + * + * @param lenght the char number of the random string + * @return the random string + */ + public static String generateRandomString(int lenght) { + RandomGenerator random = new SplittableRandom(); + StringBuffer a = new StringBuffer(); + for (int i = 0; i < lenght; i++) { + int c = random.nextInt(0, 2) == 1 ? random.nextInt('A', 'Z') : random.nextInt('a', 'z'); + a.append((char) c); + } + return a.toString(); + } + + /** + * Tries to encode some problematic HTML when adding to a form value or name. + * + * @param encode the string to encode. + * @return escaped problematic html chars. + */ + public static String encodeHTML(String encode) { + return encode.replace("\"", """); + } + +}