diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 0a9e3cd..823e672 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -4,21 +4,30 @@ on: push: branches: - develop + paths: + - 'src/**' + - 'pom.xml' + pull_request: branches: - develop + paths: + - 'src/**' + - 'pom.xml' jobs: build: runs-on: ubuntu-latest - steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 + - name: Cache local Maven repository uses: actions/cache@v2 with: @@ -26,5 +35,12 @@ jobs: key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- + - name: Build with Maven run: mvn -B package --file pom.xml + + - name: Archive generated JAR file + uses: actions/upload-artifact@v2 + with: + name: cstc-develop-artifact + path: target/CSTC-* diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 7552e72..9bd26e1 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -4,21 +4,30 @@ on: push: branches: - master + paths: + - 'src/**' + - 'pom.xml' + pull_request: branches: - master + paths: + - 'src/**' + - 'pom.xml' jobs: build: runs-on: ubuntu-latest - steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 + - name: Cache local Maven repository uses: actions/cache@v2 with: @@ -26,5 +35,12 @@ jobs: key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- + - name: Build with Maven run: mvn -B package --file pom.xml + + - name: Archive generated JAR file + uses: actions/upload-artifact@v2 + with: + name: cstc-master-artifact + path: target/CSTC-* diff --git a/pom.xml b/pom.xml index 654af5b..89a61fd 100644 --- a/pom.xml +++ b/pom.xml @@ -1,88 +1,119 @@ + - 4.0.0 - de.usd.CSTC - CSTC - 1.2.1 - CSTC - CSTC - - UTF-8 - - - src - - - src - - **/*.java - - - - res - - **/*.java - - - - - - maven-compiler-plugin - 3.7.0 - - 1.8 - 1.8 - - - - maven-assembly-plugin - - - package - - single - - - - - - jar-with-dependencies - - - - - - - - com.jayway.jsonpath - json-path - 2.4.0 - - - net.portswigger.burp.extender - burp-extender-api - 1.7.22 - - - org.bouncycastle - bcprov-jdk15on - 1.59 - - - - com.fasterxml.jackson.core - jackson-core - 2.11.1 - - - - com.fasterxml.jackson.core - jackson-databind - 2.11.1 - - - org.apache.commons - commons-text - 1.8 - - + + 4.0.0 + de.usd.CSTC + CSTC + 1.3.0 + CSTC + CSTC + + + UTF-8 + + + + + + com.jayway.jsonpath + json-path + 2.7.0 + + + + net.portswigger.burp.extender + burp-extender-api + 2.3 + + + + org.bouncycastle + bcprov-jdk15on + 1.70 + + + + com.fasterxml.jackson.core + jackson-core + 2.14.2 + + + + com.fasterxml.jackson.core + jackson-databind + 2.14.2 + + + + org.apache.commons + commons-text + 1.10.0 + + + + junit + junit + 4.13.2 + test + + + + + + + src/main/java + + + + src/main/java + + **/*.java + + + + + res + + + + + + + maven-compiler-plugin + 3.11.0 + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0 + + false + true + + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + + + + + diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java deleted file mode 100644 index c5dbbe3..0000000 --- a/src/burp/BurpExtender.java +++ /dev/null @@ -1,114 +0,0 @@ -package burp; - -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.JMenuItem; - -import de.usd.cstchef.view.FormatTab; -import de.usd.cstchef.view.RecipePanel; -import de.usd.cstchef.view.View; - -public class BurpExtender implements IBurpExtender, ITab, IMessageEditorTabFactory, IHttpListener, IContextMenuFactory { - - private final String extensionName = "CSTC"; - private IBurpExtenderCallbacks callbacks; - private View view; - - @Override - public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) { - this.callbacks = callbacks; - Logger.getInstance().init(callbacks.getStdout(), callbacks.getStderr()); - BurpUtils.getInstance().init(callbacks); - - callbacks.setExtensionName(this.extensionName); - callbacks.addSuiteTab(this); - callbacks.registerHttpListener(this); - callbacks.registerContextMenuFactory(this); - callbacks.registerMessageEditorTabFactory(this); - } - - - @Override - public String getTabCaption() { - return this.extensionName; - } - - @Override - public Component getUiComponent() { - this.view = new View(); - return this.view; - } - - @Override - public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) { - if (messageIsRequest && view.getOutgoingRecipePanel().shouldProcess(toolFlag)) { - byte[] request = messageInfo.getRequest(); - byte[] modifiedRequest = view.getOutgoingRecipePanel().bake(request); - Logger.getInstance().log("modified request: \n" + new String(modifiedRequest)); - messageInfo.setRequest(modifiedRequest); - } else if (view.getIncomingRecipePanel().shouldProcess(toolFlag)) { - byte[] response = messageInfo.getResponse(); - byte[] modifiedResponse = view.getIncomingRecipePanel().bake(response); - messageInfo.setResponse(modifiedResponse); - Logger.getInstance().log("modified response: \n" + new String(modifiedResponse)); - } - } - - @Override - public List createMenuItems(IContextMenuInvocation invoc) { - - List menuItems = new ArrayList<>(); - JMenuItem incomingMenu = new JMenuItem("Send to CSTC (Incoming)"); - JMenuItem outgoingMenu = new JMenuItem("Send to CSTC (Outgoing)"); - JMenuItem incomingFormatMenu = new JMenuItem("Send to CSTC (Formating)"); - - menuItems.add(incomingMenu); - menuItems.add(outgoingMenu); - menuItems.add(incomingFormatMenu); - - incomingMenu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - IHttpRequestResponse[] msgs = invoc.getSelectedMessages(); - if (msgs != null && msgs.length > 0) { - view.getIncomingRecipePanel().setInput(msgs[0]); - } - } - }); - - outgoingMenu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - IHttpRequestResponse[] msgs = invoc.getSelectedMessages(); - if (msgs != null && msgs.length > 0) { - view.getOutgoingRecipePanel().setInput(msgs[0]); - } - - } - }); - - incomingFormatMenu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - IHttpRequestResponse[] msgs = invoc.getSelectedMessages(); - if (msgs != null && msgs.length > 0) { - view.getFormatRecipePanel().setInput(msgs[0]); - } - } - }); - - return menuItems; - } - - @Override - public IMessageEditorTab createNewInstance(IMessageEditorController controller, boolean editable) { - RecipePanel requestFormatPanel = this.view.getOutgoingRecipePanel(); - // TODO do we need the format panel or do we want to use the incoming recipe? - RecipePanel responseFormatPanel = this.view.getFormatRecipePanel(); - return new FormatTab(requestFormatPanel, responseFormatPanel, editable); - } -} diff --git a/src/burp/BurpUtils.java b/src/burp/BurpUtils.java deleted file mode 100644 index 20bc559..0000000 --- a/src/burp/BurpUtils.java +++ /dev/null @@ -1,38 +0,0 @@ -package burp; - -public class BurpUtils { - - private static BurpUtils instance; - private IBurpExtenderCallbacks callbacks; - - public static BurpUtils getInstance() { - if (BurpUtils.instance == null) { - BurpUtils.instance = new BurpUtils(); - } - return BurpUtils.instance; - } - - private BurpUtils() { - } - - public void init(IBurpExtenderCallbacks callbacks) { - this.callbacks = callbacks; - } - - public IBurpExtenderCallbacks getCallbacks() throws IllegalAccessError { - if (this.callbacks == null) { - throw new IllegalAccessError("Only works within burpsuite"); - } - return callbacks; - } - - public static boolean inBurp() { - try { - BurpUtils.getInstance().getCallbacks(); - return true; - } catch (IllegalAccessError e) { - return false; - } - } - -} diff --git a/src/burp/CstcMessageEditorController.java b/src/burp/CstcMessageEditorController.java deleted file mode 100644 index b25c775..0000000 --- a/src/burp/CstcMessageEditorController.java +++ /dev/null @@ -1,37 +0,0 @@ -package burp; - -public class CstcMessageEditorController implements IMessageEditorController { - - private IHttpService httpService = null; - private byte[] request = null; - private byte[] response = null; - - public void setHttpRequestResponse(IHttpRequestResponse requestResponse) { - this.httpService = requestResponse.getHttpService(); - this.request = requestResponse.getRequest(); - this.response = requestResponse.getResponse(); - } - - public void setRequest(byte[] request) { - this.request = request; - } - - public void setResponse(byte[] response) { - this.request = response; - } - - @Override - public IHttpService getHttpService() { - return httpService; - } - - @Override - public byte[] getRequest() { - return request; - } - - @Override - public byte[] getResponse() { - return response; - } -} diff --git a/src/burp/Logger.java b/src/burp/Logger.java deleted file mode 100644 index 465d70d..0000000 --- a/src/burp/Logger.java +++ /dev/null @@ -1,44 +0,0 @@ -package burp; - -import java.io.OutputStream; -import java.io.PrintWriter; - -public class Logger { - - private static Logger instance; - - private PrintWriter stdout; - private PrintWriter stderr; - - public static Logger getInstance() { - if (Logger.instance == null) { - Logger.instance = new Logger(); - } - return Logger.instance; - } - - private Logger() { - - } - - public void init(OutputStream stdOut, OutputStream stdErr) { - this.stdout = new PrintWriter(stdOut, true); - this.stderr = new PrintWriter(stdErr, true); - } - - public void log(String msg) { - if (this.stdout == null) { - System.out.println(msg); - } else { - this.stdout.println(msg); - } - } - - public void err(String msg) { - if (this.stderr == null) { - System.err.println(msg); - } else { - this.stderr.println(msg); - } - } -} diff --git a/src/de/usd/cstchef/VariableStore.java b/src/de/usd/cstchef/VariableStore.java deleted file mode 100644 index 5c6521c..0000000 --- a/src/de/usd/cstchef/VariableStore.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.usd.cstchef; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; - -public class VariableStore { - - private static VariableStore instance; - - private HashMap variables = new HashMap<>(); - private ReentrantLock lock = new ReentrantLock(); - - public static VariableStore getInstance() { - if (VariableStore.instance == null) { - VariableStore.instance = new VariableStore(); - } - return VariableStore.instance; - } - - private VariableStore() { - } - - public void lock() { - this.lock.lock(); - } - - public void unlock() { - this.lock.unlock(); - } - - public synchronized byte[] getVariable(String name) { - return this.variables.get(name); - } - - public synchronized void setVariable(String key, byte[] value) { - this.variables.put(key, value); - } - - public synchronized void removeVariable(String key) { - this.variables.remove(key); - } - - public synchronized HashMap getVariables() { - HashMap variablesCopy = new HashMap<>(); - - for (Map.Entry entry : this.variables.entrySet()) { - byte[] orig = entry.getValue(); - byte[] newContent = new byte[orig.length]; - System.arraycopy(orig, 0, newContent, 0, orig.length); - variablesCopy.put(entry.getKey(), newContent); - } - return variablesCopy; - } - -} diff --git a/src/de/usd/cstchef/operations/Operation.java b/src/de/usd/cstchef/operations/Operation.java deleted file mode 100644 index 31d43d6..0000000 --- a/src/de/usd/cstchef/operations/Operation.java +++ /dev/null @@ -1,492 +0,0 @@ -package de.usd.cstchef.operations; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.EOFException; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JFileChooser; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JPasswordField; -import javax.swing.JSpinner; -import javax.swing.JTextArea; -import javax.swing.JTextField; -import javax.swing.border.Border; -import javax.swing.border.CompoundBorder; -import javax.swing.border.MatteBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; - -import burp.Logger; -import de.usd.cstchef.view.ui.FormatTextField; -import de.usd.cstchef.view.ui.VariableTextArea; -import de.usd.cstchef.view.ui.VariableTextField; - -public abstract class Operation extends JPanel { - - private static Color defaultBgColor = new Color(223, 240, 216); - private static Color defaultFontColor = new Color(70, 136, 71); - private static Color disabledBgColor = new Color(223, 223, 223); - private static Color disabledFontColor = new Color(153, 153, 153); - private static Color breakBgColor = new Color(242, 222, 222); - private static Color breakFontColor = new Color(185, 74, 72); - private static Color errorBgColor = new Color(255, 121, 128); - private static Color errorFontColor = new Color(185, 74, 72); - - private static ImageIcon breakIcon = new ImageIcon(Operation.class.getResource("/stop.png")); - private static ImageIcon breakIconActive = new ImageIcon(Operation.class.getResource("/stop_active.png")); - private static ImageIcon disableIcon = new ImageIcon(Operation.class.getResource("/disable.png")); - private static ImageIcon removeIcon = new ImageIcon(Operation.class.getResource("/remove.png")); - private static ImageIcon helpIcon = new ImageIcon(Operation.class.getResource("/help.png")); - - private NotifyChangeListener notifyChangeListener; - - private boolean breakpoint = false; - private boolean disabled = false; - private boolean error = false; - - private ChangeListener changeListener; - private JTextArea errorArea; - private Box contentBox; - private Map uiElements; - - private int operationSkip = 0; - private int laneSkip = 0; - - public Operation() { - super(); - this.uiElements = new HashMap<>(); - - this.setLayout(new BorderLayout()); - this.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); - // set border - Border margin = BorderFactory.createEmptyBorder(10, 10, 10, 10); - MatteBorder lineBorder = new MatteBorder(0, 0, 1, 0, Color.BLACK); - CompoundBorder border = new CompoundBorder(lineBorder, margin); - this.setBorder(border); - - // add header - JPanel header = new JPanel(); - header.setBackground(new Color(0, 0, 0, 0)); // transparent - - BoxLayout layout = new BoxLayout(header, BoxLayout.X_AXIS); - header.setLayout(layout); - header.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); - OperationInfos opInfos = this.getClass().getAnnotation(OperationInfos.class); - - JLabel titleLbl = new JLabel(opInfos.name()); - Font f = titleLbl.getFont(); - titleLbl.setFont(f.deriveFont(f.getStyle() | Font.BOLD)); - - JButton disableBtn = createIconButton(Operation.disableIcon); - disableBtn.setToolTipText("Disable"); - JButton breakpointBtn = createIconButton(Operation.breakIcon); - breakpointBtn.setToolTipText("Breakpoint"); - JButton removeBtn = createIconButton(Operation.removeIcon); - removeBtn.setToolTipText("Remove"); - JButton helpBtn = createIconButton(Operation.helpIcon); - helpBtn.setToolTipText(opInfos.description()); - - disableBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - disabled = !isDisabled(); - refreshColors(); - validate(); - repaint(); - notifyChange(); - } - }); - - breakpointBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - breakpoint = !isBreakpoint(); - ImageIcon newIcon = isBreakpoint() ? Operation.breakIconActive : Operation.breakIcon; - breakpointBtn.setIcon(newIcon); - refreshColors(); - validate(); - repaint(); - notifyChange(); - } - }); - JPanel me = this; - removeBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Container parent = getParent(); - onRemove(); - parent.remove(me); - parent.validate(); - parent.repaint(); - notifyChange(); - } - }); - - header.add(titleLbl); - header.add(Box.createHorizontalStrut(6)); - header.add(helpBtn); - header.add(Box.createHorizontalGlue()); - header.add(disableBtn); - header.add(Box.createHorizontalStrut(3)); - header.add(breakpointBtn); - header.add(Box.createHorizontalStrut(3)); - header.add(removeBtn); - - this.add(header, BorderLayout.NORTH); - - errorArea = new JTextArea(); - errorArea.setEditable(false); - errorArea.setLineWrap(true); - errorArea.setWrapStyleWord(true); - errorArea.setBackground(new Color(0, 0, 0, 0)); - errorArea.setFont(f.deriveFont(f.getStyle() | Font.BOLD)); - errorArea.setFocusable(false); - errorArea.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); - - this.add(errorArea, BorderLayout.SOUTH); - - contentBox = Box.createVerticalBox(); - this.add(contentBox, BorderLayout.CENTER); - - this.createUI(); - this.refreshColors(); - } - - public Map getState() { - Map properties = new HashMap<>(); - for (String key : this.uiElements.keySet()) { - if( key.startsWith("noupdate") ) - properties.put(key, null); - else - properties.put(key, getUiValues(this.uiElements.get(key))); - } - - return properties; - } - - private Object getUiValues(Component comp) { - Object result = null; - if (comp instanceof JPasswordField) { - result = ""; - } else if (comp instanceof VariableTextArea) { - result = ((VariableTextArea) comp).getRawText(); - } else if (comp instanceof VariableTextField) { - result = ((VariableTextField) comp).getRawText(); - } else if (comp instanceof JTextField) { - result = ((JTextField) comp).getText(); - } else if (comp instanceof JSpinner) { - result = ((JSpinner) comp).getValue(); - } else if (comp instanceof JComboBox) { - result = ((JComboBox) comp).getSelectedItem(); - if( result != null ) - result = result.toString(); - } else if (comp instanceof JCheckBox) { - result = ((JCheckBox) comp).isSelected(); - } else if (comp instanceof FormatTextField) { - result = ((FormatTextField) comp).getValues(); - } else if (comp instanceof JFileChooser) { - result = ((JFileChooser) comp).getName(); - } - - return result; - } - - public void load(Map parameters) { - for (String key : this.uiElements.keySet()) { - Object value = parameters.get(key); - this.setUiValue(this.uiElements.get(key), value); - } - } - - private void setUiValue(Component comp, Object value) { - if (comp == null || value == null) { - return; - } - - if (comp instanceof JTextField) { - ((JTextField) comp).setText((String) value); - } else if (comp instanceof JSpinner) { - ((JSpinner) comp).setValue(value); - } else if (comp instanceof JComboBox) { - ((JComboBox) comp).setSelectedItem(value); - } else if (comp instanceof VariableTextArea) { - ((VariableTextArea) comp).setText((String) value); - } else if (comp instanceof JCheckBox) { - ((JCheckBox) comp).setSelected((boolean) value); - } else if (comp instanceof FormatTextField) { - ((FormatTextField) comp).setValues((Map) value); - } else if (comp instanceof JFileChooser) { - ((JFileChooser) comp).setName((String)value); - } - } - - private JButton createIconButton(ImageIcon icon) { - JButton btn = new JButton(); - btn.setBorder(BorderFactory.createEmptyBorder()); - btn.setIcon(icon); - btn.setContentAreaFilled(false); - btn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - btn.setAlignmentX(Component.RIGHT_ALIGNMENT); - - return btn; - } - - private void refreshColors() { - Color bgColor; - Color fontColor; - if (this.isDisabled()) { - bgColor = Operation.disabledBgColor; - fontColor = Operation.disabledFontColor; - } else if (this.isError()) { - bgColor = Operation.errorBgColor; - fontColor = Operation.errorFontColor; - } else if (this.isBreakpoint()) { - bgColor = Operation.breakBgColor; - fontColor = Operation.breakFontColor; - } else { - bgColor = Operation.defaultBgColor; - fontColor = Operation.defaultFontColor; - } - - this.setBackground(bgColor); - this.changeFontColor(this, fontColor); - } - - private void changeFontColor(Container container, Color color) { - for (Component comp : container.getComponents()) { - if (comp instanceof JLabel || comp.equals(errorArea)) { - comp.setForeground(color); - } else if (comp instanceof Container) { - changeFontColor((Container) comp, color); - } - } - } - - protected void addUIElement(String caption, Component comp) { - this.addUIElement(caption, comp, true, null); - } - - protected void addUIElement(String caption, Component comp, boolean notifyChange) { - this.addUIElement(caption, comp, notifyChange, null); - } - - protected void addUIElement(String caption, Component comp, String identifier) { - this.addUIElement(caption, comp, true, identifier); - } - - protected void addUIElement(String caption, Component comp, boolean notifyChange, String identifier) { - comp.setCursor(Cursor.getDefaultCursor()); - - Box box = Box.createHorizontalBox(); - box.setAlignmentX(Component.LEFT_ALIGNMENT); - if (comp instanceof JCheckBox) { - comp.setBackground(new Color(0, 0, 0, 0)); - } - JLabel lbl = new JLabel(caption); - box.add(lbl); - box.add(Box.createHorizontalStrut(10)); - box.add(comp); - this.contentBox.add(box); - this.contentBox.add(Box.createVerticalStrut(10)); - if( identifier == null ) - identifier = caption; - this.uiElements.put(identifier, comp); - - if (notifyChange) { - if (notifyChangeListener == null) { - notifyChangeListener = new NotifyChangeListener(); - } - - if (comp instanceof JTextField) { - ((JTextField) comp).getDocument().addDocumentListener(notifyChangeListener); - } else if (comp instanceof JSpinner) { - ((JSpinner) comp).addChangeListener(notifyChangeListener); - } else if (comp instanceof JComboBox) { - ((JComboBox) comp).addActionListener(notifyChangeListener); - } else if (comp instanceof VariableTextArea) { - ((VariableTextArea) comp).addDocumentListener(notifyChangeListener); - } else if (comp instanceof JCheckBox) { - ((JCheckBox) comp).addActionListener(notifyChangeListener); - } else if (comp instanceof FormatTextField) { - ((FormatTextField) comp).addDocumentListener(notifyChangeListener); - } else { - Logger.getInstance().err("could not add a default change listener for " + comp.getClass()); - } - } - } - - @Override - public Dimension getPreferredSize() { - Dimension dim = super.getPreferredSize(); - int width = this.getParent().getWidth(); - dim.setSize(width, dim.height); - return dim; - } - - public byte[] performOperation(byte[] input) { - try { - byte[] result = this.perform(input); - this.setErrorMessage(null); - return result; - } catch (EOFException e) { - this.setErrorMessage(new EOFException("End of file")); - return new byte[0]; - } catch (Throwable e) { - this.setErrorMessage(e); - return new byte[0]; - } - } - - public void setErrorMessage(Throwable e) { - boolean error = e != null; - - String msg = error ? e.getMessage() : ""; - String text; - if (msg == null) { - text = e.getClass().getName(); - } else { - text = error ? (msg.isEmpty() ? e.toString() : msg) : ""; - } - - this.errorArea.setText(text); - - this.setError(error); - this.refreshColors(); - this.validate(); - this.repaint(); - } - - public void removeChangeListener() { - this.changeListener = null; - } - - public void setChangeListener(ChangeListener listener) { - this.changeListener = listener; - } - - protected void notifyChange() { - if (this.changeListener != null) { - this.changeListener.stateChanged(new ChangeEvent(this)); - } - } - - public boolean isBreakpoint() { - return breakpoint; - } - - public void setBreakpoint(boolean breakpoint) { - this.breakpoint = breakpoint; - } - - public boolean isDisabled() { - return disabled; - } - - public void setDisabled(boolean disabled) { - this.disabled = disabled; - } - - public boolean isError() { - return error; - } - - public void setError(boolean error) { - this.error = error; - } - - public void setOperationSkip(int count) { - if( count < 0 ) - count = 0; - this.operationSkip = count; - } - - public int getOperationSkip() { - return this.operationSkip; - } - - public void setLaneSkip(int count) { - if( count < 0 ) - count = 0; - this.laneSkip = count; - } - - public int getLaneSkip() { - return this.laneSkip; - } - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.TYPE) - public @interface OperationInfos { - - public String name() - - default "Unnamed plugin!"; - - public String description() - - default "Change this description!"; - - public OperationCategory category() default OperationCategory.MISC; - } - - protected abstract byte[] perform(byte[] input) throws Exception; - - public void createUI() { - - } - - public void onRemove() { - - } - - private class NotifyChangeListener implements DocumentListener, ActionListener, ChangeListener { - - @Override - public void changedUpdate(DocumentEvent e) { - notifyChange(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - notifyChange(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - notifyChange(); - } - - @Override - public void actionPerformed(ActionEvent e) { - notifyChange(); - } - - @Override - public void stateChanged(ChangeEvent e) { - notifyChange(); - } - } -} diff --git a/src/de/usd/cstchef/operations/OperationCategory.java b/src/de/usd/cstchef/operations/OperationCategory.java deleted file mode 100644 index 10abe79..0000000 --- a/src/de/usd/cstchef/operations/OperationCategory.java +++ /dev/null @@ -1,32 +0,0 @@ -package de.usd.cstchef.operations; - -public enum OperationCategory { - ARITHMETIC("Arithmetic"), - BYTEOPERATION("Byte Operations"), - COMPRESSION("Compression"), - CONDITIONALS("Conditionals"), - DATAFORMAT("Data format"), - DATES("Date / Time"), - ENCRYPTION("Encryption / Encoding"), - EXTRACTORS("Extractors"), - HASHING("Hashing"), - MISC("Misc"), - NETWORKING("Networking"), - SETTER("Setter"), - SIGNATURE("Signature"), - STRING("String"), - UTILS("Utils"); -// LANGUAGE("Language"), -// FLOWCONTROL("Flow control"); - - private final String text; - - OperationCategory(final String text) { - this.text = text; - } - - @Override - public String toString() { - return text; - } -} diff --git a/src/de/usd/cstchef/operations/arithmetic/ArithmeticDelimiterOperation.java b/src/de/usd/cstchef/operations/arithmetic/ArithmeticDelimiterOperation.java deleted file mode 100644 index 830ad73..0000000 --- a/src/de/usd/cstchef/operations/arithmetic/ArithmeticDelimiterOperation.java +++ /dev/null @@ -1,65 +0,0 @@ -package de.usd.cstchef.operations.arithmetic; - -import java.util.Set; - -import javax.swing.JCheckBox; -import javax.swing.JComboBox; - -import de.usd.cstchef.Utils; -import de.usd.cstchef.operations.Operation; - -public abstract class ArithmeticDelimiterOperation extends Operation { - - private JComboBox delimiterBox; - private JCheckBox floatCheckBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - String delimiterKey = (String) this.delimiterBox.getSelectedItem(); - String delimiter = Utils.delimiters.get(delimiterKey); - String[] lines = new String(input).split(delimiter); - if (lines.length < 2) { - return input; - } - - double[] numbers = new double[lines.length]; - - double result = Utils.parseNumber(lines[0].trim()); - numbers[0] = result; - double val; - for (int i = 1; i < lines.length; i++) { - val = Utils.parseNumber(lines[i].trim()); - numbers[i] = val; - result = this.calculate(result, val); - } - - result = onFinish(result, numbers); - String str = ""; - if (floatCheckBox.isSelected()) { - str = String.valueOf(result); - } - else { - str = String.valueOf(Math.round(result)); - } - return str.getBytes(); - } - - protected double onFinish(double result, double[] lines) { - return result; - } - - protected abstract double calculate(double a, double b); - - @Override - public void createUI() { - Set delimSet = Utils.delimiters.keySet(); - String[] delimiters = delimSet.toArray(new String[delimSet.size()]); - - this.delimiterBox = new JComboBox(delimiters); - this.addUIElement("Delimiter", this.delimiterBox); - - this.floatCheckBox = new JCheckBox(); - this.addUIElement("Point Number", this.floatCheckBox); - } - -} diff --git a/src/de/usd/cstchef/operations/arithmetic/ArithmeticOperation.java b/src/de/usd/cstchef/operations/arithmetic/ArithmeticOperation.java deleted file mode 100644 index 02b11ff..0000000 --- a/src/de/usd/cstchef/operations/arithmetic/ArithmeticOperation.java +++ /dev/null @@ -1,55 +0,0 @@ -package de.usd.cstchef.operations.arithmetic; - -import javax.swing.JCheckBox; -import javax.swing.JTextField; - -import de.usd.cstchef.operations.Operation; - -public abstract class ArithmeticOperation extends Operation { - - private JTextField numberInput; - private JCheckBox floatCheckBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String result = ""; - try { - - String i = new String(input); - - //A little trick - if (i.isEmpty()) { - i = "0"; - } - - Double input_number = Double.valueOf(i); - Double static_number = Double.valueOf(numberInput.getText()); - Double result_number = calculate(input_number, static_number); - - - if (this.floatCheckBox.isSelected()) { - result = String.valueOf(result_number); - } else { - result = String.valueOf(Math.round(result_number)); - } - - } catch( Exception e ) { - throw new IllegalArgumentException("Input is not a number."); - } - - return result.getBytes(); - } - - protected abstract double calculate(double input_number, double static_number); - - @Override - public void createUI() { - this.numberInput = new JTextField("1"); - this.addUIElement("Number", this.numberInput); - - this.floatCheckBox = new JCheckBox(); - this.addUIElement("Point Number", this.floatCheckBox); - } - -} diff --git a/src/de/usd/cstchef/operations/arithmetic/Divide.java b/src/de/usd/cstchef/operations/arithmetic/Divide.java deleted file mode 100644 index 5c2a9d3..0000000 --- a/src/de/usd/cstchef/operations/arithmetic/Divide.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.usd.cstchef.operations.arithmetic; - -import javax.swing.JCheckBox; - -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "Single - Divide", category = OperationCategory.ARITHMETIC, description = "Divide input by the given number") -public class Divide extends ArithmeticOperation { - - private JCheckBox reverse; - - @Override - protected double calculate(double input_number, double static_number) { - - if( reverse.isSelected() ) { - - if( input_number == 0 ) - input_number = 1; - - return static_number / input_number; - - } else { - - if( static_number == 0 ) - static_number = 1; - - return input_number / static_number; - - } - } - - @Override - public void createUI() { - super.createUI(); - - this.reverse = new JCheckBox(); - this.addUIElement("Reverse", this.reverse); - } -} diff --git a/src/de/usd/cstchef/operations/arithmetic/Median.java b/src/de/usd/cstchef/operations/arithmetic/Median.java deleted file mode 100644 index dad3f38..0000000 --- a/src/de/usd/cstchef/operations/arithmetic/Median.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.usd.cstchef.operations.arithmetic; - -import java.util.Arrays; - -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; - -@OperationInfos(name = "List - Median", category = OperationCategory.ARITHMETIC, description = "Computes the median of a list of numbers.") -public class Median extends ArithmeticDelimiterOperation { - - @Override - protected double calculate(double a, double b) { - // we dont need this here - return a; - } - - @Override - protected double onFinish(double intermediateResult, double[] lines) { - Arrays.sort(lines); - double result; - - if (lines.length % 2 == 0) { - int mid = lines.length / 2; - result = (lines[mid] + lines[mid - 1]) / 2; - } else { - result = lines[(int) (Math.floor(lines.length / 2))]; - } - return result; - } - -} diff --git a/src/de/usd/cstchef/operations/byteoperation/ByteKeyOperation.java b/src/de/usd/cstchef/operations/byteoperation/ByteKeyOperation.java deleted file mode 100644 index c75063a..0000000 --- a/src/de/usd/cstchef/operations/byteoperation/ByteKeyOperation.java +++ /dev/null @@ -1,37 +0,0 @@ -package de.usd.cstchef.operations.byteoperation; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.view.ui.FormatTextField; - -public abstract class ByteKeyOperation extends Operation { - - private FormatTextField inputTxt; - - public void createUI() { - this.inputTxt = new FormatTextField(); - this.addUIElement("Key", inputTxt); - } - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] result = new byte[input.length]; - byte[] key = this.inputTxt.getText(); - - if (key.length == 0) { - return input; - } - - int keyCounter = 0; - for (int i = 0; i < input.length; i++) { - byte var = key[keyCounter]; - keyCounter = (keyCounter + 1) % key.length; - result[i] = calculate(input[i], var); - } - - return result; - } - - protected abstract byte calculate(byte input, byte var); - -} diff --git a/src/de/usd/cstchef/operations/conditional/ConditionalOperation.java b/src/de/usd/cstchef/operations/conditional/ConditionalOperation.java deleted file mode 100644 index a928361..0000000 --- a/src/de/usd/cstchef/operations/conditional/ConditionalOperation.java +++ /dev/null @@ -1,52 +0,0 @@ -package de.usd.cstchef.operations.conditional; - -import javax.swing.JTextField; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.view.ui.VariableTextField; - -public abstract class ConditionalOperation extends Operation { - - protected VariableTextField expr; - private JTextField operationSkipField; - private JTextField laneSkipField; - - public void setOperationSkip() { - - try { - int operationSkip = Integer.valueOf(operationSkipField.getText()); - this.setOperationSkip(operationSkip); - } catch( Exception e ) { - throw new IllegalArgumentException("Input is not a number."); - } - } - - public void setLaneSkip() { - - try { - int laneSkip = Integer.valueOf(laneSkipField.getText()); - this.setLaneSkip(laneSkip); - } catch( Exception e ) { - throw new IllegalArgumentException("Input is not a number."); - } - } - - public void resetSkips() { - this.setOperationSkip(0); - this.setLaneSkip(0); - } - - @Override - public void createUI() { - this.expr = new VariableTextField(); - this.addUIElement("Expr", this.expr); - - this.operationSkipField = new JTextField("0"); - this.addUIElement("Skip Operations", this.operationSkipField); - - this.laneSkipField = new JTextField("0"); - this.addUIElement("Skip Lanes", this.laneSkipField); - - } - -} diff --git a/src/de/usd/cstchef/operations/conditional/NumberCompare.java b/src/de/usd/cstchef/operations/conditional/NumberCompare.java deleted file mode 100644 index f336d85..0000000 --- a/src/de/usd/cstchef/operations/conditional/NumberCompare.java +++ /dev/null @@ -1,73 +0,0 @@ -package de.usd.cstchef.operations.conditional; - -import javax.swing.JComboBox; - -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "Number Compare", category = OperationCategory.CONDITIONALS, description = "Skip if evaluates to true") -public class NumberCompare extends ConditionalOperation { - - private JComboBox operationBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - Double inputNumber; - Double userNumber; - - try { - String tmp = new String(input); - inputNumber = Double.valueOf(tmp); - userNumber = Double.valueOf(this.expr.getText()); - } catch( Exception e ) { - throw new IllegalArgumentException("Input is not a number."); - } - - boolean condition = false; - switch ((String)this.operationBox.getSelectedItem()) { - case "equal": - if( inputNumber.compareTo(userNumber) == 0 ) - condition = true; - break; - case "not equal": - if( inputNumber.compareTo(userNumber) != 0 ) - condition = true; - break; - case "greater": - if( inputNumber < userNumber ) - condition = true; - break; - case "lower": - if( inputNumber > userNumber ) - condition = true; - break; - case "greater equal": - if( inputNumber <= userNumber ) - condition = true; - break; - case "lower equal": - if( inputNumber >= userNumber ) - condition = true; - break; - } - - if( condition ) { - this.setOperationSkip(); - this.setLaneSkip(); - } else { - this.resetSkips(); - } - - return input; - } - - @Override - public void createUI() { - super.createUI(); - this.operationBox = new JComboBox<>(new String[] {"equal", "not equal", "lower", "greater", "lower equal", "greater equal"}); - this.operationBox.setSelectedItem("equal"); - this.addUIElement("Lineseperator", this.operationBox); - } - -} diff --git a/src/de/usd/cstchef/operations/conditional/RegexMatch.java b/src/de/usd/cstchef/operations/conditional/RegexMatch.java deleted file mode 100644 index 2f156af..0000000 --- a/src/de/usd/cstchef/operations/conditional/RegexMatch.java +++ /dev/null @@ -1,51 +0,0 @@ -package de.usd.cstchef.operations.conditional; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.swing.JCheckBox; - -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "Regex Match", category = OperationCategory.CONDITIONALS, description = "Skip if regex matches") -public class RegexMatch extends ConditionalOperation { - - private JCheckBox invert; - private JCheckBox find; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - Pattern p = Pattern.compile(this.expr.getText()); - Matcher m = p.matcher(new String(input)); - - boolean condition = false; - if( find.isSelected() ) { - condition = m.find(); - } else { - condition = m.matches(); - } - - if( condition ^ invert.isSelected() ) { - this.setOperationSkip(); - this.setLaneSkip(); - } else { - this.resetSkips(); - } - - return input; - } - - @Override - public void createUI() { - super.createUI(); - - this.invert = new JCheckBox(); - this.addUIElement("Invert Match", this.invert); - - this.find = new JCheckBox(); - this.addUIElement("Find anywhere", this.find); - } - -} diff --git a/src/de/usd/cstchef/operations/conditional/StringContains.java b/src/de/usd/cstchef/operations/conditional/StringContains.java deleted file mode 100644 index d29ee8a..0000000 --- a/src/de/usd/cstchef/operations/conditional/StringContains.java +++ /dev/null @@ -1,45 +0,0 @@ -package de.usd.cstchef.operations.conditional; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "String Contains", category = OperationCategory.CONDITIONALS, description = "Skip if input contains") -public class StringContains extends ConditionalOperation { - - private JCheckBox invert; - private JCheckBox caseSensitive; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = cbs.getHelpers(); - int start = helpers.indexOf(input, this.expr.getBytes(), caseSensitive.isSelected(), 0, input.length); - - if( (start >= 0) ^ invert.isSelected() ) { - this.setOperationSkip(); - this.setLaneSkip(); - } else { - this.resetSkips(); - } - - return input; - } - - @Override - public void createUI() { - super.createUI(); - - this.invert = new JCheckBox(); - this.addUIElement("Invert Match", this.invert); - - this.caseSensitive = new JCheckBox(); - this.addUIElement("Case Sensitive", this.caseSensitive); - } - -} diff --git a/src/de/usd/cstchef/operations/conditional/StringMatch.java b/src/de/usd/cstchef/operations/conditional/StringMatch.java deleted file mode 100644 index 56cfbf0..0000000 --- a/src/de/usd/cstchef/operations/conditional/StringMatch.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.usd.cstchef.operations.conditional; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "String Match", category = OperationCategory.CONDITIONALS, description = "Skip if input matches") -public class StringMatch extends ConditionalOperation { - - private JCheckBox invert; - private JCheckBox caseSensitive; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] search = this.expr.getBytes(); - if( search.length != input.length ) { - if( invert.isSelected() ) { - this.setOperationSkip(); - this.setLaneSkip(); - } else { - this.resetSkips(); - } - return input; - } - - IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = cbs.getHelpers(); - int start = helpers.indexOf(input, search, caseSensitive.isSelected(), 0, input.length); - - if( (start >= 0) ^ invert.isSelected() ) { - this.setOperationSkip(); - this.setLaneSkip(); - } else { - this.resetSkips(); - } - - return input; - } - - @Override - public void createUI() { - super.createUI(); - - this.invert = new JCheckBox(); - this.addUIElement("Invert Match", this.invert); - - this.caseSensitive = new JCheckBox(); - this.addUIElement("Case Sensitive", this.caseSensitive); - } - -} diff --git a/src/de/usd/cstchef/operations/dataformat/FromHex.java b/src/de/usd/cstchef/operations/dataformat/FromHex.java deleted file mode 100644 index 3ba4659..0000000 --- a/src/de/usd/cstchef/operations/dataformat/FromHex.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.usd.cstchef.operations.dataformat; - -import java.util.Set; - -import javax.swing.JComboBox; -import org.bouncycastle.util.encoders.Hex; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.dataformat.ToHex.Delimiter; -import de.usd.cstchef.operations.Operation.OperationInfos; - -@OperationInfos(name = "From Hex", category = OperationCategory.DATAFORMAT, description = "From hex") -public class FromHex extends Operation { - - private JComboBox delimiterBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - String selectedKey = (String) this.delimiterBox.getSelectedItem(); - Delimiter delimiter = ToHex.delimiters.get(selectedKey); - - if (delimiter.value.length == 0) { // No delimiter - return Hex.decode(input); - } - - String delimiterStr = new String(delimiter.value); - String inputStr = new String(input); - inputStr = inputStr.replace(delimiterStr, ""); - - return Hex.decode(inputStr); - } - - @Override - public void createUI() { - Set choices = ToHex.delimiters.keySet(); - delimiterBox = new JComboBox(choices.toArray(new String[choices.size()])); - delimiterBox.setSelectedIndex(0); - - this.addUIElement("Delimiter", delimiterBox); - } - -} diff --git a/src/de/usd/cstchef/operations/dataformat/HtmlEncode.java b/src/de/usd/cstchef/operations/dataformat/HtmlEncode.java deleted file mode 100644 index 051a9a2..0000000 --- a/src/de/usd/cstchef/operations/dataformat/HtmlEncode.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.usd.cstchef.operations.dataformat; - -import java.io.ByteArrayOutputStream; - -import javax.swing.JCheckBox; - -import org.apache.commons.text.StringEscapeUtils; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTML Encode", category = OperationCategory.DATAFORMAT, description = "HTML Encode") -public class HtmlEncode extends Operation { - - private JCheckBox checkbox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] result = null; - if( checkbox.isSelected() ) { - - byte[] delimiter = "&#".getBytes(); - byte[] closer = ";".getBytes(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - out.write(delimiter); - for (int i = 0; i < input.length - 1; i++) { - out.write(String.valueOf(Byte.toUnsignedInt(input[i])).getBytes()); - out.write(closer); - out.write(delimiter); - } - - out.write(String.valueOf(Byte.toUnsignedInt(input[input.length - 1])).getBytes()); - out.write(closer); - result = out.toByteArray(); - - } else { - String tmp = new String(input); - tmp = StringEscapeUtils.escapeHtml4(tmp); - result = tmp.getBytes(); - } - - return result; - } - - @Override - public void createUI() { - this.checkbox = new JCheckBox("Encode all"); - this.checkbox.setSelected(false); - this.addUIElement(null, this.checkbox, "checkbox1"); - } -} diff --git a/src/de/usd/cstchef/operations/dataformat/ToHex.java b/src/de/usd/cstchef/operations/dataformat/ToHex.java deleted file mode 100644 index 4a3737f..0000000 --- a/src/de/usd/cstchef/operations/dataformat/ToHex.java +++ /dev/null @@ -1,92 +0,0 @@ -package de.usd.cstchef.operations.dataformat; - -import java.io.ByteArrayOutputStream; -import java.util.HashMap; -import java.util.Set; - -import javax.swing.JComboBox; -import org.bouncycastle.util.encoders.Hex; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; - -@OperationInfos(name = "To Hex", category = OperationCategory.DATAFORMAT, description = "To hex") -public class ToHex extends Operation { - - static HashMap delimiters = new HashMap() { - { - put("None", new Delimiter("")); - put("Space", new Delimiter(" ")); - put("Comma", new Delimiter(",")); - put("Colon", new Delimiter(":")); - put("Semi-colon", new Delimiter(";")); - put("Colon", new Delimiter(":")); - put("Line feed", new Delimiter("\n")); - put("CRLF", new Delimiter("\r\n")); - put("0x", new Delimiter("0x", true)); - put("\\x", new Delimiter("\\x", true)); - } - }; - - private JComboBox delimiterBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - String selectedKey = (String) this.delimiterBox.getSelectedItem(); - Delimiter delimiter = ToHex.delimiters.get(selectedKey); - - if (delimiter.value.length == 0) { // No delimiter - return Hex.encode(input); - } - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - if (input.length > 0 && delimiter.writeAtStart) { - out.write(delimiter.value); - } - - for (int i = 0; i < input.length - 1; i++) { - out.write(Hex.encode(new byte[] { input[i] })); - out.write(delimiter.value); - } - - if (input.length > 0) { - out.write(Hex.encode(new byte[] { input[input.length - 1] })); // wow - if (delimiter.writeAtEnd) { - out.write(delimiter.value); - } - } - - return out.toByteArray(); - } - - @Override - public void createUI() { - Set choices = ToHex.delimiters.keySet(); - delimiterBox = new JComboBox(choices.toArray(new String[choices.size()])); - delimiterBox.setSelectedIndex(0); - - this.addUIElement("Delimiter", delimiterBox); - } - - public static class Delimiter { - public byte[] value; - public boolean writeAtStart; - public boolean writeAtEnd; - - public Delimiter(String value) { - this(value, false, false); - } - - public Delimiter(String value, boolean writeAtStart) { - this(value, writeAtStart, false); - } - - public Delimiter(String value, boolean writeAtStart, boolean writeAtEnd) { - this.value = value.getBytes(); - this.writeAtStart = writeAtStart; - this.writeAtEnd = writeAtEnd; - } - } -} diff --git a/src/de/usd/cstchef/operations/dataformat/UrlEncode.java b/src/de/usd/cstchef/operations/dataformat/UrlEncode.java deleted file mode 100644 index 813f670..0000000 --- a/src/de/usd/cstchef/operations/dataformat/UrlEncode.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.usd.cstchef.operations.dataformat; - -import java.io.ByteArrayOutputStream; - -import javax.swing.JCheckBox; - -import org.bouncycastle.util.encoders.Hex; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; - -@OperationInfos(name = "Url Encode", category = OperationCategory.DATAFORMAT, description = "Url encode") -public class UrlEncode extends Operation { - - private JCheckBox checkbox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = cbs.getHelpers(); - - byte[] result = null; - if( checkbox.isSelected() ) { - - byte[] delimiter = "%".getBytes(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(delimiter); - - for (int i = 0; i < input.length - 1; i++) { - out.write(Hex.encode(new byte[] { input[i] })); - out.write(delimiter); - } - - out.write(Hex.encode(new byte[] { input[input.length - 1] })); - result = out.toByteArray(); - - } else { - result = helpers.urlEncode(input); - } - - return result; - } - - @Override - public void createUI() { - this.checkbox = new JCheckBox("Encode all"); - this.checkbox.setSelected(false); - this.addUIElement(null, this.checkbox, "checkbox1"); - } -} diff --git a/src/de/usd/cstchef/operations/datetime/UnixTimestamp.java b/src/de/usd/cstchef/operations/datetime/UnixTimestamp.java deleted file mode 100644 index a1a6085..0000000 --- a/src/de/usd/cstchef/operations/datetime/UnixTimestamp.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.usd.cstchef.operations.datetime; - -import javax.swing.JCheckBox; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "Unix Timestamp", category = OperationCategory.DATES, description = "Returnes the current unix timestamp.") -public class UnixTimestamp extends Operation { - - private JCheckBox milliBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - long timestamp = 0; - if (milliBox.isSelected()) { - timestamp = System.currentTimeMillis(); - } - else { - timestamp = System.currentTimeMillis() / 1000L; - } - return String.valueOf(timestamp).getBytes(); - } - - public void createUI() { - this.milliBox = new JCheckBox(); - this.addUIElement("Milliseconds", this.milliBox); - } - -} diff --git a/src/de/usd/cstchef/operations/encryption/CipherUtils.java b/src/de/usd/cstchef/operations/encryption/CipherUtils.java deleted file mode 100644 index 117c138..0000000 --- a/src/de/usd/cstchef/operations/encryption/CipherUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -package de.usd.cstchef.operations.encryption; - -import java.security.Provider; -import java.security.Security; -import java.util.HashMap; - -public class CipherUtils { - - private static CipherUtils instance; - - private HashMap algos; - - private CipherUtils() { - algos = new HashMap<>(); - - getCipherInfos(); - } - - private void getCipherInfos() { - for (Provider provider : Security.getProviders()) { - for (String key : provider.stringPropertyNames()) { - if (key.startsWith("Cipher")) { - String[] parts = key.split(" "); - if (parts.length < 2) { - continue; - } - String cipherName = parts[0].substring(7); - String type = parts[1]; - - CipherInfo info = algos.getOrDefault(cipherName, new CipherInfo()); - String property = provider.getProperty(key); - - if (type.equals("SupportedModes")) { - String[] modes = property.split("\\|"); - info.setModes(modes); - } else if (type.equals("SupportedPaddings")) { - String[] paddings = property.split("\\|"); - info.setPaddings(paddings); - } - this.algos.put(cipherName, info); - } - } - } - } - - public static CipherUtils getInstance() { - if (instance == null) { - instance = new CipherUtils(); - } - return instance; - } - - public CipherInfo getCipherInfo(String algorithm) { - return this.algos.getOrDefault(algorithm, new CipherInfo()); - } - - public class CipherInfo { - - private String[] modes; - private String[] paddings; - - - public CipherInfo() { - this.modes = new String[0]; - this.paddings = new String[0]; - } - - public CipherInfo(String[] modes, String[] paddings) { - this.modes = modes; - this.paddings = paddings; - } - - public String[] getModes() { - return modes; - } - - public void setModes(String[] modes) { - this.modes = modes; - } - - public String[] getPaddings() { - return paddings; - } - - public void setPaddings(String[] paddings) { - this.paddings = paddings; - } - - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append("Modes: "); - for (String mode : this.modes) { - buf.append(mode); - buf.append("|"); - } - buf.append(", Paddings: "); - for (String padding : this.paddings) { - buf.append(padding); - buf.append("|"); - } - - return buf.toString(); - } - - } -} diff --git a/src/de/usd/cstchef/operations/encryption/CryptOperation.java b/src/de/usd/cstchef/operations/encryption/CryptOperation.java deleted file mode 100644 index a0ca5f2..0000000 --- a/src/de/usd/cstchef/operations/encryption/CryptOperation.java +++ /dev/null @@ -1,89 +0,0 @@ -package de.usd.cstchef.operations.encryption; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.swing.JComboBox; - -import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.encoders.Base64; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.encryption.CipherUtils.CipherInfo; -import de.usd.cstchef.view.ui.FormatTextField; - -public abstract class CryptOperation extends Operation { - - private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" }; - - protected String algorithm; - protected FormatTextField ivTxt; - protected FormatTextField keyTxt; - - protected JComboBox cipherMode; - protected JComboBox inputMode; - protected JComboBox outputMode; - protected JComboBox paddings; - - public CryptOperation(String alogrithm) { - super(); - this.algorithm = alogrithm; - this.createMyUI(); - } - - protected byte[] crypt(byte[] input, int cipherMode, String algorithm, String mode, String padding) - throws Exception { - byte[] key = keyTxt.getText(); - byte[] iv = ivTxt.getText(); - - SecretKeySpec secretKeySpec = new SecretKeySpec(key, algorithm); - IvParameterSpec ivSpec = new IvParameterSpec(iv); - Cipher cipher = Cipher.getInstance(String.format("%s/%s/%s", algorithm, mode, padding)); - - if( mode.equals("ECB") ) { - cipher.init(cipherMode, secretKeySpec); - } else { - cipher.init(cipherMode, secretKeySpec, ivSpec); - } - - String selectedInputMode = (String)inputMode.getSelectedItem(); - String selectedOutputMode = (String)outputMode.getSelectedItem(); - - if( selectedInputMode.equals("Hex") ) - input = Hex.decode(input); - if( selectedInputMode.equals("Base64") ) - input = Base64.decode(input); - - byte[] encrypted = cipher.doFinal(input); - - if( selectedOutputMode.equals("Hex") ) - encrypted = Hex.encode(encrypted); - if( selectedOutputMode.equals("Base64") ) - encrypted = Base64.encode(encrypted); - - return encrypted; - } - - public void createMyUI() { - this.ivTxt = new FormatTextField(); - this.addUIElement("IV", this.ivTxt); - - this.keyTxt = new FormatTextField(); - this.addUIElement("Key", this.keyTxt); - CipherUtils utils = CipherUtils.getInstance(); - - CipherInfo info = utils.getCipherInfo(this.algorithm); - this.cipherMode = new JComboBox<>(info.getModes()); - this.addUIElement("Mode", this.cipherMode); - - this.paddings = new JComboBox<>(info.getPaddings()); - this.addUIElement("Padding", this.paddings); - - this.inputMode = new JComboBox<>(inOutModes); - this.addUIElement("Input", this.inputMode); - - this.outputMode = new JComboBox<>(inOutModes); - this.addUIElement("Output", this.outputMode); - } - -} diff --git a/src/de/usd/cstchef/operations/encryption/DecryptionOperation.java b/src/de/usd/cstchef/operations/encryption/DecryptionOperation.java deleted file mode 100644 index 9d7b7b6..0000000 --- a/src/de/usd/cstchef/operations/encryption/DecryptionOperation.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.usd.cstchef.operations.encryption; - -import javax.crypto.Cipher; - -public abstract class DecryptionOperation extends CryptOperation { - - public DecryptionOperation(String alogrithm) { - super(alogrithm); - } - - @Override - protected byte[] perform(byte[] input) throws Exception { - return this.crypt(input, Cipher.DECRYPT_MODE, this.algorithm, (String) this.cipherMode.getSelectedItem(), - (String) this.paddings.getSelectedItem()); - } - -} diff --git a/src/de/usd/cstchef/operations/encryption/EncryptionOperation.java b/src/de/usd/cstchef/operations/encryption/EncryptionOperation.java deleted file mode 100644 index 65e90ed..0000000 --- a/src/de/usd/cstchef/operations/encryption/EncryptionOperation.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.usd.cstchef.operations.encryption; - -import javax.crypto.Cipher; - -public abstract class EncryptionOperation extends CryptOperation { - - public EncryptionOperation(String alogrithm) { - super(alogrithm); - } - - @Override - protected byte[] perform(byte[] input) throws Exception { - return this.crypt(input, Cipher.ENCRYPT_MODE, this.algorithm, (String) this.cipherMode.getSelectedItem(), - (String) this.paddings.getSelectedItem()); - } - -} diff --git a/src/de/usd/cstchef/operations/encryption/RsaDecryption.java b/src/de/usd/cstchef/operations/encryption/RsaDecryption.java deleted file mode 100644 index 908a3e0..0000000 --- a/src/de/usd/cstchef/operations/encryption/RsaDecryption.java +++ /dev/null @@ -1,75 +0,0 @@ -package de.usd.cstchef.operations.encryption; - -import javax.crypto.Cipher; -import javax.swing.JComboBox; - -import org.bouncycastle.util.encoders.Base64; -import org.bouncycastle.util.encoders.Hex; - -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.encryption.CipherUtils.CipherInfo; -import de.usd.cstchef.operations.signature.KeystoreOperation; - -@OperationInfos(name = "RSA Decryption", category = OperationCategory.ENCRYPTION, description = "Decrypt input using a private key") -public class RsaDecryption extends KeystoreOperation { - - private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" }; - - protected String algorithm = "RSA"; - protected String cipherMode = "ECB"; - - protected JComboBox inputMode; - protected JComboBox outputMode; - protected JComboBox paddings; - - public RsaDecryption() { - super(); - this.createMyUI(); - } - - protected byte[] perform(byte[] input) throws Exception { - - if( ! this.keyAvailable.isSelected() ) - throw new IllegalArgumentException("No private key available."); - - String padding = (String)paddings.getSelectedItem(); - Cipher cipher = Cipher.getInstance(String.format("%s/%s/%s", algorithm, cipherMode, padding)); - cipher.init(Cipher.DECRYPT_MODE, this.selectedEntry.getPrivateKey()); - - String selectedInputMode = (String)inputMode.getSelectedItem(); - String selectedOutputMode = (String)outputMode.getSelectedItem(); - - if( selectedInputMode.equals("Hex") ) - input = Hex.decode(input); - if( selectedInputMode.equals("Base64") ) - input = Base64.decode(input); - - byte[] encrypted = cipher.doFinal(input); - - if( selectedOutputMode.equals("Hex") ) - encrypted = Hex.encode(encrypted); - if( selectedOutputMode.equals("Base64") ) - encrypted = Base64.encode(encrypted); - - return encrypted; - } - - public void createMyUI() { - - super.createMyUI(); - - CipherUtils utils = CipherUtils.getInstance(); - CipherInfo info = utils.getCipherInfo(this.algorithm); - - this.paddings = new JComboBox<>(info.getPaddings()); - this.addUIElement("Padding", this.paddings); - - this.inputMode = new JComboBox<>(inOutModes); - this.addUIElement("Input", this.inputMode); - - this.outputMode = new JComboBox<>(inOutModes); - this.addUIElement("Output", this.outputMode); - } - -} diff --git a/src/de/usd/cstchef/operations/encryption/RsaEncryption.java b/src/de/usd/cstchef/operations/encryption/RsaEncryption.java deleted file mode 100644 index edcde37..0000000 --- a/src/de/usd/cstchef/operations/encryption/RsaEncryption.java +++ /dev/null @@ -1,75 +0,0 @@ -package de.usd.cstchef.operations.encryption; - -import javax.crypto.Cipher; -import javax.swing.JComboBox; - -import org.bouncycastle.util.encoders.Base64; -import org.bouncycastle.util.encoders.Hex; - -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.encryption.CipherUtils.CipherInfo; -import de.usd.cstchef.operations.signature.KeystoreOperation; - -@OperationInfos(name = "RSA Encryption", category = OperationCategory.ENCRYPTION, description = "Encrypt input using a certificate") -public class RsaEncryption extends KeystoreOperation { - - private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" }; - - protected String algorithm = "RSA"; - protected String cipherMode = "ECB"; - - protected JComboBox inputMode; - protected JComboBox outputMode; - protected JComboBox paddings; - - public RsaEncryption() { - super(); - this.createMyUI(); - } - - protected byte[] perform(byte[] input) throws Exception { - - if( ! this.certAvailable.isSelected() ) - throw new IllegalArgumentException("No certificate available."); - - String padding = (String)paddings.getSelectedItem(); - Cipher cipher = Cipher.getInstance(String.format("%s/%s/%s", algorithm, cipherMode, padding)); - cipher.init(Cipher.ENCRYPT_MODE, this.cert.getPublicKey()); - - String selectedInputMode = (String)inputMode.getSelectedItem(); - String selectedOutputMode = (String)outputMode.getSelectedItem(); - - if( selectedInputMode.equals("Hex") ) - input = Hex.decode(input); - if( selectedInputMode.equals("Base64") ) - input = Base64.decode(input); - - byte[] encrypted = cipher.doFinal(input); - - if( selectedOutputMode.equals("Hex") ) - encrypted = Hex.encode(encrypted); - if( selectedOutputMode.equals("Base64") ) - encrypted = Base64.encode(encrypted); - - return encrypted; - } - - public void createMyUI() { - - super.createMyUI(); - - CipherUtils utils = CipherUtils.getInstance(); - CipherInfo info = utils.getCipherInfo(this.algorithm); - - this.paddings = new JComboBox<>(info.getPaddings()); - this.addUIElement("Padding", this.paddings); - - this.inputMode = new JComboBox<>(inOutModes); - this.addUIElement("Input", this.inputMode); - - this.outputMode = new JComboBox<>(inOutModes); - this.addUIElement("Output", this.outputMode); - } - -} diff --git a/src/de/usd/cstchef/operations/extractors/HttpBodyExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpBodyExtractor.java deleted file mode 100644 index 3f8c907..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpBodyExtractor.java +++ /dev/null @@ -1,28 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import java.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IRequestInfo; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; - -@OperationInfos(name = "HTTP Body", category = OperationCategory.EXTRACTORS, description = "Extracts the body of a HTTP request.") -public class HttpBodyExtractor extends Operation { - - @Override - protected byte[] perform(byte[] input) throws Exception { - try { - IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); - IRequestInfo requestInfo = cbs.getHelpers().analyzeRequest(input); - int bodyOffset = requestInfo.getBodyOffset(); - - byte[] body = Arrays.copyOfRange(input, bodyOffset, input.length); - return body; - } catch (Exception e) { - throw new IllegalArgumentException("Provided input is not a valid http request."); - } - } -} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/extractors/HttpCookieExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpCookieExtractor.java deleted file mode 100644 index a1616d8..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpCookieExtractor.java +++ /dev/null @@ -1,63 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import org.bouncycastle.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IResponseInfo; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "HTTP Cookie", category = OperationCategory.EXTRACTORS, description = "Extracts a cookie from a HTTP request.") -public class HttpCookieExtractor extends Operation { - - private VariableTextField cookieNameField; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] cookieName = cookieNameField.getBytes(); - if( cookieName.length == 0 ) - return input; - - byte[] cookieSearch = new byte[cookieName.length + 1]; - System.arraycopy(cookieName, 0, cookieSearch, 0, cookieName.length); - System.arraycopy("=".getBytes(), 0, cookieSearch, cookieName.length, 1); - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - IResponseInfo resp = helpers.analyzeResponse(input); - boolean isRequest = (resp.getStatusCode() == 0); - - String cookieHeader = "\r\nSet-Cookie: "; - if(isRequest) - cookieHeader = "\r\nCookie: "; - - try { - - int offset = helpers.indexOf(input, cookieHeader.getBytes(), false, 0, length); - int line_end = helpers.indexOf(input, "\r\n".getBytes(), false, offset + 2, length); - int start = helpers.indexOf(input, cookieSearch, true, offset, line_end); - int end = helpers.indexOf(input, ";".getBytes(), true, start, line_end); - - if( end < 0 ) - end = line_end; - - return Arrays.copyOfRange(input, start + cookieName.length + 1, end); - - } catch( IllegalArgumentException e ) { - throw new IllegalArgumentException("Cookie not found."); - } - } - - @Override - public void createUI() { - this.cookieNameField = new VariableTextField(); - this.addUIElement("Name", this.cookieNameField); - } -} diff --git a/src/de/usd/cstchef/operations/extractors/HttpGetExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpGetExtractor.java deleted file mode 100644 index 5a4762b..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpGetExtractor.java +++ /dev/null @@ -1,49 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import java.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IParameter; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "HTTP GET Param", category = OperationCategory.EXTRACTORS, description = "Extracts a GET Parameter of a HTTP request.") -public class HttpGetExtractor extends Operation { - - protected VariableTextField parameter; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String parameterName = parameter.getText(); - if( parameterName.equals("") ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - IParameter param = helpers.getRequestParameter(input, parameterName); - if( param == null) - throw new IllegalArgumentException("Parameter name not found."); - if( param.getType() != IParameter.PARAM_URL ) - throw new IllegalArgumentException("Parameter type is not GET."); - - int start = param.getValueStart(); - int end = param.getValueEnd(); - - byte[] result = Arrays.copyOfRange(input, start, end); - return result; - - } - - @Override - public void createUI() { - this.parameter = new VariableTextField(); - this.addUIElement("Parameter", this.parameter); - } - -} diff --git a/src/de/usd/cstchef/operations/extractors/HttpHeaderExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpHeaderExtractor.java deleted file mode 100644 index 1783046..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpHeaderExtractor.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import org.bouncycastle.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "HTTP Header", category = OperationCategory.EXTRACTORS, description = "Extracts a header of a HTTP request.") -public class HttpHeaderExtractor extends Operation { - - private VariableTextField headerNameField; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] headerName = headerNameField.getBytes(); - if( headerName.length == 0 ) - return input; - - byte[] headerSearch = new byte[headerName.length + 4]; - System.arraycopy("\r\n".getBytes(), 0, headerSearch, 0, 2); - System.arraycopy(headerName, 0, headerSearch, 2, headerName.length); - System.arraycopy(": ".getBytes(), 0, headerSearch, headerName.length + 2, 2); - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - int offset = helpers.indexOf(input, headerSearch, true, 0, length); - - if( offset < 0 ) - throw new IllegalArgumentException("Header not found."); - - int valueStart = helpers.indexOf(input, " ".getBytes(), false, offset, length); - if( valueStart < 0 ) - throw new IllegalArgumentException("Invalid Header format."); - int valueEnd = helpers.indexOf(input, "\r\n".getBytes(), false, valueStart, length); - if( valueEnd < 0 ) - throw new IllegalArgumentException("Invalid Header format."); - - byte[] result = Arrays.copyOfRange(input, valueStart + 1, valueEnd); - return result; - } - - @Override - public void createUI() { - this.headerNameField = new VariableTextField(); - this.addUIElement("Name", this.headerNameField); - } - -} diff --git a/src/de/usd/cstchef/operations/extractors/HttpJsonExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpJsonExtractor.java deleted file mode 100644 index ac3acaf..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpJsonExtractor.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import java.util.Arrays; - -import javax.swing.JTextField; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IParameter; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP JSON", category = OperationCategory.EXTRACTORS, description = "Get a JSON value from HTTP message.") -public class HttpJsonExtractor extends Operation { - - private JTextField fieldTxt; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String keyName = fieldTxt.getText(); - if( keyName.equals("") ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - IParameter param = helpers.getRequestParameter(input, keyName); - if( param == null) - throw new IllegalArgumentException("Key not found."); - if( param.getType() != IParameter.PARAM_JSON ) - throw new IllegalArgumentException("Parameter type is not JSON"); - - int start = param.getValueStart(); - int end = param.getValueEnd(); - - byte[] result = Arrays.copyOfRange(input, start, end); - return result; - } - - @Override - public void createUI() { - this.fieldTxt = new JTextField(); - this.addUIElement("Field", this.fieldTxt); - } -} diff --git a/src/de/usd/cstchef/operations/extractors/HttpMethodExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpMethodExtractor.java deleted file mode 100644 index 6b21d4b..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpMethodExtractor.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import org.bouncycastle.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP Method", category = OperationCategory.EXTRACTORS, description = "Extracts the method of a HTTP request.") -public class HttpMethodExtractor extends Operation { - - @Override - protected byte[] perform(byte[] input) throws Exception { - try { - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - int methodEnd = helpers.indexOf(input, " ".getBytes(), false, 0, length); - byte[] result = Arrays.copyOfRange(input, 0, methodEnd); - - return result; - - } catch (Exception e) { - throw new IllegalArgumentException("Provided input is not a valid http request."); - } - } -} diff --git a/src/de/usd/cstchef/operations/extractors/HttpPostExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpPostExtractor.java deleted file mode 100644 index 7a0f171..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpPostExtractor.java +++ /dev/null @@ -1,47 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import java.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IParameter; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "HTTP POST Param", category = OperationCategory.EXTRACTORS, description = "Extracts a POST parameter of a HTTP request.") -public class HttpPostExtractor extends Operation { - - protected VariableTextField parameter; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String parameterName = parameter.getText(); - if( parameterName.equals("") ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - IParameter param = helpers.getRequestParameter(input, parameterName); - if( param == null) - throw new IllegalArgumentException("Parameter name not found."); - if( param.getType() != IParameter.PARAM_BODY ) - throw new IllegalArgumentException("Parameter type is not POST"); - - int start = param.getValueStart(); - int end = param.getValueEnd(); - - byte[] result = Arrays.copyOfRange(input, start, end); - return result; - } - - @Override - public void createUI() { - this.parameter = new VariableTextField(); - this.addUIElement("Parameter", this.parameter); - } -} diff --git a/src/de/usd/cstchef/operations/extractors/HttpUriExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpUriExtractor.java deleted file mode 100644 index e07a6f0..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpUriExtractor.java +++ /dev/null @@ -1,50 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import java.util.Arrays; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP URI", category = OperationCategory.EXTRACTORS, description = "Extracts the URI of a HTTP request.") -public class HttpUriExtractor extends Operation { - - private JCheckBox checkbox; - - @Override - public void createUI() { - this.checkbox = new JCheckBox("With parameters"); - this.checkbox.setSelected(true); - this.addUIElement(null, this.checkbox, "checkbox1"); - } - - @Override - protected byte[] perform(byte[] input) throws Exception { - try { - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - int firstMark = helpers.indexOf(input, " ".getBytes(), false, 0, length); - int lineMark = helpers.indexOf(input, " ".getBytes(), false, firstMark + 1, length); - - int secondMark = helpers.indexOf(input, "?".getBytes(), false, firstMark + 1, length); - - if( this.checkbox.isSelected() || secondMark < 0 || secondMark >= lineMark) { - secondMark = lineMark; - } - - byte[] result = Arrays.copyOfRange(input, firstMark + 1, secondMark); - return result; - - } catch (Exception e) { - throw new IllegalArgumentException("Provided input is not a valid http request."); - } - } -} diff --git a/src/de/usd/cstchef/operations/extractors/HttpXmlExtractor.java b/src/de/usd/cstchef/operations/extractors/HttpXmlExtractor.java deleted file mode 100644 index f14ef5e..0000000 --- a/src/de/usd/cstchef/operations/extractors/HttpXmlExtractor.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import java.util.Arrays; - -import javax.swing.JTextField; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IParameter; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP XML", category = OperationCategory.EXTRACTORS, description = "Extract XML value from HTTP message.") -public class HttpXmlExtractor extends Operation { - - private JTextField fieldTxt; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String keyName = fieldTxt.getText(); - if( keyName.equals("") ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - IParameter param = helpers.getRequestParameter(input, keyName); - if( param == null) - throw new IllegalArgumentException("Key not found."); - if( param.getType() != IParameter.PARAM_XML ) - throw new IllegalArgumentException("Parameter type is not XML"); - - int start = param.getValueStart(); - int end = param.getValueEnd(); - - byte[] result = Arrays.copyOfRange(input, start, end); - return result; - } - - @Override - public void createUI() { - this.fieldTxt = new JTextField(); - this.addUIElement("Field", this.fieldTxt); - } -} diff --git a/src/de/usd/cstchef/operations/extractors/JsonExtractor.java b/src/de/usd/cstchef/operations/extractors/JsonExtractor.java deleted file mode 100644 index 86b6534..0000000 --- a/src/de/usd/cstchef/operations/extractors/JsonExtractor.java +++ /dev/null @@ -1,59 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import javax.swing.JTextField; - -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.spi.json.JsonProvider; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "JSON", category = OperationCategory.EXTRACTORS, description = "Extracts values of json objects.") -public class JsonExtractor extends Operation { - - private static JsonProvider provider; - - //TODO should this be a VariableTextField? - private JTextField fieldTxt; - - public JsonExtractor() { - super(); - if (JsonExtractor.provider == null) { - JsonExtractor.provider = Configuration.defaultConfiguration().jsonProvider(); - } - } - - @Override - protected byte[] perform(byte[] input) throws Exception { - - if( fieldTxt.getText().equals("") ) - return input; - - Object document = provider.parse(new String(input)); - Object result = JsonPath.read(document, fieldTxt.getText()); - - if( result == null ) - result = "null"; - - Class resultClass = result.getClass(); - - if( resultClass == String.class ) { - return ((String)result).getBytes(); - } else if( resultClass == Integer.class || resultClass == Float.class || resultClass == Double.class ) { - return String.valueOf(result).getBytes(); - } else if( resultClass == Boolean.class ) { - return String.valueOf(result).getBytes(); - } - - throw new IllegalArgumentException("JSON data of unknown type."); - } - - @Override - public void createUI() { - this.fieldTxt = new JTextField(); - this.addUIElement("Field", this.fieldTxt); - } - -} diff --git a/src/de/usd/cstchef/operations/extractors/LineExtractor.java b/src/de/usd/cstchef/operations/extractors/LineExtractor.java deleted file mode 100644 index badd030..0000000 --- a/src/de/usd/cstchef/operations/extractors/LineExtractor.java +++ /dev/null @@ -1,82 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import javax.swing.JComboBox; - -import org.bouncycastle.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "Line Extractor", category = OperationCategory.EXTRACTORS, description = "Extracts the specified line number.") -public class LineExtractor extends Operation { - - private VariableTextField lineNumberField; - private JComboBox formatBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - int lineNumber = 0; - try { - String number = lineNumberField.getText(); - lineNumber = Integer.valueOf(number); - } catch(Exception e) { - return input; - } - - if( lineNumber <= 0 ) - return input; - - byte[] lineEndings = "\r\n".getBytes(); - switch ((String) this.formatBox.getSelectedItem()) { - case "\\r\\n": - lineEndings = "\r\n".getBytes(); - break; - case "\\r": - lineEndings = "\r".getBytes(); - break; - case "\\n": - lineEndings = "\n".getBytes(); - break; - } - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - int start = 0; - int offset = 0; - int counter = 0; - while( counter < lineNumber - 1 ) { - offset = helpers.indexOf(input, lineEndings, false, start, length); - if( offset >= 0 ) { - start = offset + lineEndings.length; - counter++; - } else { - break; - } - } - - int end = helpers.indexOf(input, lineEndings, false, start, length); - if( end < 0 ) - end = length; - - byte[] result = Arrays.copyOfRange(input, start, end); - return result; - } - - @Override - public void createUI() { - this.lineNumberField = new VariableTextField(); - this.addUIElement("Name", this.lineNumberField); - this.formatBox = new JComboBox<>(new String[] {"\\r\\n", "\\r", "\\n"}); - this.formatBox.setSelectedItem("\\r\\n"); - this.addUIElement("Lineseperator", this.formatBox); - } - -} diff --git a/src/de/usd/cstchef/operations/extractors/RegexExtractor.java b/src/de/usd/cstchef/operations/extractors/RegexExtractor.java deleted file mode 100644 index 1f16cbd..0000000 --- a/src/de/usd/cstchef/operations/extractors/RegexExtractor.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.usd.cstchef.operations.extractors; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.swing.JComboBox; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "Regex", category = OperationCategory.EXTRACTORS, description = "Extracts using a regex.") -public class RegexExtractor extends Operation { - - private static String LIST_MATCHES = "List matches"; - private static String LIST_GROUPS = "List capture groups"; - - private VariableTextField regexTxt; - private JComboBox outputBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - Pattern p = Pattern.compile(this.regexTxt.getText()); - Matcher m = p.matcher(new String(input)); - String outputType = (String) this.outputBox.getSelectedItem(); - - StringBuffer buf = new StringBuffer(); - - while (m.find()) { - if (outputType.equals(LIST_MATCHES)) { - buf.append(m.group()).append("\n"); - } else { - for (int i = 1; i <= m.groupCount(); i++) { - buf.append(m.group(i)).append("\n"); - } - } - } - - if( buf.length() > 0 ) - buf.setLength(buf.length() - 1); - - return buf.toString().getBytes(); - } - - @Override - public void createUI() { - this.regexTxt = new VariableTextField(); - this.addUIElement("Regex", this.regexTxt); - - this.outputBox = new JComboBox<>(new String[] { LIST_MATCHES, LIST_GROUPS }); - this.addUIElement("Output format", this.outputBox); - } -} diff --git a/src/de/usd/cstchef/operations/hashing/HashOperation.java b/src/de/usd/cstchef/operations/hashing/HashOperation.java deleted file mode 100644 index 718e4ad..0000000 --- a/src/de/usd/cstchef/operations/hashing/HashOperation.java +++ /dev/null @@ -1,47 +0,0 @@ -package de.usd.cstchef.operations.hashing; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import javax.swing.JComboBox; - -import org.bouncycastle.util.encoders.Hex; - -import de.usd.cstchef.operations.Operation; - -public abstract class HashOperation extends Operation { - - private JComboBox sizeBox; - private String algorithm; - - public HashOperation(String alogrithm) { - super(); - this.algorithm = alogrithm; - } - - public HashOperation(String alogrithm, String... sizes) { - super(); - this.algorithm = alogrithm; - createMyUI(sizes); - } - - @Override - protected byte[] perform(byte[] input) throws Exception { - return this.hash(input); - } - - protected byte[] hash(byte[] input) throws NoSuchAlgorithmException { - String algo = this.algorithm + (this.sizeBox != null ? (String) sizeBox.getSelectedItem() : ""); - - MessageDigest digest = MessageDigest.getInstance(algo); - byte[] hash = digest.digest(input); - return Hex.encode(hash); - } - - public void createMyUI(String[] sizes) { - sizeBox = new JComboBox(sizes); - sizeBox.setSelectedIndex(0); - this.addUIElement("Size", sizeBox); - } - -} diff --git a/src/de/usd/cstchef/operations/hashing/Hmac.java b/src/de/usd/cstchef/operations/hashing/Hmac.java deleted file mode 100644 index 764c4d0..0000000 --- a/src/de/usd/cstchef/operations/hashing/Hmac.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.usd.cstchef.operations.hashing; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.swing.JComboBox; -import org.bouncycastle.util.encoders.Hex; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "HMAC", category = OperationCategory.HASHING, description = "Creates an HMAC with the chosen hashing function.") -public class Hmac extends Operation { - - private VariableTextField keyTxt; - private JComboBox hashAlgoBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - byte[] key = this.keyTxt.getText().getBytes(); - String algo = "Hmac" + (String) hashAlgoBox.getSelectedItem(); - SecretKeySpec signingKey = new SecretKeySpec(key, algo); - Mac mac = Mac.getInstance(algo); - mac.init(signingKey); - return Hex.encode(mac.doFinal(input)); - } - - @Override - public void createUI() { - String[] algorithms = { "MD5", "SHA1", "SHA256", "SHA224", "SHA384", "SHA512", "GOST3411" }; - this.hashAlgoBox = new JComboBox<>(algorithms); - this.addUIElement("Hashing function", this.hashAlgoBox); - - this.keyTxt = new VariableTextField(); - this.addUIElement("Key", this.keyTxt); - } - -} diff --git a/src/de/usd/cstchef/operations/misc/ReadFile.java b/src/de/usd/cstchef/operations/misc/ReadFile.java deleted file mode 100644 index 302b9c6..0000000 --- a/src/de/usd/cstchef/operations/misc/ReadFile.java +++ /dev/null @@ -1,52 +0,0 @@ -package de.usd.cstchef.operations.misc; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.FileInputStream; -import javax.swing.JButton; -import javax.swing.JFileChooser; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "Read File", category = OperationCategory.MISC, description = "Reads data from a file.") -public class ReadFile extends Operation implements ActionListener { - - private final JFileChooser fileChooser = new JFileChooser(); - private VariableTextField fileNameTxt; - - @Override - protected byte[] perform(byte[] input) throws Exception { - String path = fileNameTxt.getText(); - - File file = new File(path); - FileInputStream fis = new FileInputStream(file); - byte[] data = new byte[(int) file.length()]; - fis.read(data); - fis.close(); - - return data; - } - - public void createUI() { - this.fileNameTxt = new VariableTextField(); - this.addUIElement("Filename", this.fileNameTxt); - - JButton chooseFileButton = new JButton("Select file"); - chooseFileButton.addActionListener(this); - this.addUIElement(null, chooseFileButton, false, "button1"); - } - - @Override - public void actionPerformed(ActionEvent e) { - int returnVal = fileChooser.showOpenDialog(this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fileChooser.getSelectedFile(); - this.fileNameTxt.setText(file.getAbsolutePath()); - } - } - -} diff --git a/src/de/usd/cstchef/operations/misc/WriteFile.java b/src/de/usd/cstchef/operations/misc/WriteFile.java deleted file mode 100644 index 8ca2990..0000000 --- a/src/de/usd/cstchef/operations/misc/WriteFile.java +++ /dev/null @@ -1,78 +0,0 @@ -package de.usd.cstchef.operations.misc; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -import javax.swing.JButton; -import javax.swing.JFileChooser; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "Write File", category = OperationCategory.MISC, description = "Appends data to the end of a file.") -public class WriteFile extends Operation implements ActionListener { - - private final JFileChooser fileChooser = new JFileChooser(); - private VariableTextField fileNameTxt; - private String lastPath = ""; - private FileOutputStream out; - - @Override - protected byte[] perform(byte[] input) throws Exception { - String path = fileNameTxt.getText(); - - if (!lastPath.equals(path)) { - if (out != null) { - out.close(); - out = null; - } - if (!path.isEmpty()) { - out = new FileOutputStream(path); - } - lastPath = path; - } - - if (out != null) { - out.write(input); - out.write('\n'); - } - - return input; - } - - public void createUI() { - this.fileNameTxt = new VariableTextField(); - this.fileNameTxt.setEditable(false); - this.addUIElement("Filename", this.fileNameTxt); - - JButton chooseFileButton = new JButton("Select file"); - chooseFileButton.addActionListener(this); - this.addUIElement(null, chooseFileButton, false, "button1"); - } - - - @Override - public void actionPerformed(ActionEvent e) { - int returnVal = fileChooser.showOpenDialog(this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fileChooser.getSelectedFile(); - this.fileNameTxt.setText(file.getAbsolutePath()); - } - } - - @Override - public void onRemove() { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - } - } - } - -} diff --git a/src/de/usd/cstchef/operations/networking/HTTPRequest.java b/src/de/usd/cstchef/operations/networking/HTTPRequest.java deleted file mode 100644 index 030a8b4..0000000 --- a/src/de/usd/cstchef/operations/networking/HTTPRequest.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.usd.cstchef.operations.networking; - -import javax.swing.JCheckBox; -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IHttpRequestResponse; -import burp.IHttpService; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "HTTP Request", category = OperationCategory.NETWORKING, description = "Makes an http reqeust and returns the response.") -public class HTTPRequest extends Operation { - - private VariableTextField hostTxt; - private VariableTextField portTxt; - private JCheckBox sslEnabledBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helper = callbacks.getHelpers(); - String protocol = sslEnabledBox.isSelected() ? "https" : "http"; - IHttpService service = helper.buildHttpService(hostTxt.getText(), Integer.valueOf(portTxt.getText()), protocol); - IHttpRequestResponse response = callbacks.makeHttpRequest(service, input); - return response.getResponse(); - } - - @Override - public void createUI() { - this.hostTxt = new VariableTextField(); - this.addUIElement("Host", this.hostTxt); - - this.portTxt = new VariableTextField(); - this.addUIElement("Port", this.portTxt); - - this.sslEnabledBox = new JCheckBox(); - this.addUIElement("SSL", this.sslEnabledBox); - } - -} diff --git a/src/de/usd/cstchef/operations/setter/HttpGetSetter.java b/src/de/usd/cstchef/operations/setter/HttpGetSetter.java deleted file mode 100644 index 14cfb9b..0000000 --- a/src/de/usd/cstchef/operations/setter/HttpGetSetter.java +++ /dev/null @@ -1,66 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IParameter; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP GET Param", category = OperationCategory.SETTER, description = "Sets a GET parameter to the specified value.") -public class HttpGetSetter extends SetterOperation { - - private JCheckBox addIfNotPresent; - private JCheckBox urlEncode; - private JCheckBox urlEncodeAll; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String parameterName = getWhere(); - if( parameterName.equals("") ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - byte[] newValue = getWhatBytes(); - - if( urlEncodeAll.isSelected() || urlEncode.isSelected() ) - newValue = urlEncode(newValue, urlEncodeAll.isSelected(), helpers); - - IParameter param = getParameter(input, parameterName, IParameter.PARAM_URL, helpers); - - if( param == null ) { - - if( !addIfNotPresent.isSelected() ) - return input; - - param = helpers.buildParameter(parameterName, "dummy", IParameter.PARAM_URL); - input = helpers.addParameter(input, param); - param = getParameter(input, parameterName, IParameter.PARAM_URL, helpers); - } - - byte[] newRequest = replaceParam(input, param, newValue); - return newRequest; - } - - @Override - public void createUI() { - super.createUI(); - - this.urlEncode = new JCheckBox("URL encode"); - this.urlEncode.setSelected(false); - this.addUIElement(null, this.urlEncode, "checkbox1"); - - this.urlEncodeAll = new JCheckBox("URL encode all"); - this.urlEncodeAll.setSelected(false); - this.addUIElement(null, this.urlEncodeAll, "checkbox2"); - - this.addIfNotPresent = new JCheckBox("Add if not present"); - this.addIfNotPresent.setSelected(true); - this.addUIElement(null, this.addIfNotPresent, "checkbox3"); - } -} diff --git a/src/de/usd/cstchef/operations/setter/HttpHeaderSetter.java b/src/de/usd/cstchef/operations/setter/HttpHeaderSetter.java deleted file mode 100644 index 3653471..0000000 --- a/src/de/usd/cstchef/operations/setter/HttpHeaderSetter.java +++ /dev/null @@ -1,66 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IRequestInfo; -import de.usd.cstchef.Utils; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP Header", category = OperationCategory.SETTER, description = "Set a HTTP header to the specified value.") -public class HttpHeaderSetter extends SetterOperation { - - private JCheckBox addIfNotPresent; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] newValue = getWhatBytes(); - byte[] headerName = getWhereBytes(); - if( headerName.length == 0 ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - byte[] headerSearch = new byte[headerName.length + 2]; - System.arraycopy(headerName, 0, headerSearch, 0, headerName.length); - System.arraycopy(": ".getBytes(), 0, headerSearch, headerName.length, 2); - - try { - - int offset = helpers.indexOf(input, headerSearch, false, 0, length); - int start = helpers.indexOf(input, ": ".getBytes(), false, offset, length) + 2; - int end = helpers.indexOf(input, "\r\n".getBytes(), false, start, length); - return Utils.insertAtOffset(input, start, end, newValue); - - } catch( IllegalArgumentException e ) { - - if( !addIfNotPresent.isSelected() ) - return input; - - IRequestInfo info = helpers.analyzeRequest(input); - int bodyOffset = info.getBodyOffset() - 2; - - byte[] value = new byte[headerSearch.length + newValue.length + 2]; - System.arraycopy(headerSearch, 0, value, 0, headerSearch.length); - System.arraycopy(newValue, 0, value, headerName.length + 2, newValue.length); - System.arraycopy("\r\n".getBytes(), 0, value, headerName.length + 2 + newValue.length, 2); - return Utils.insertAtOffset(input, bodyOffset, bodyOffset, value); - - } - } - - @Override - public void createUI() { - super.createUI(); - this.addIfNotPresent = new JCheckBox("Add if not present"); - this.addIfNotPresent.setSelected(true); - this.addUIElement(null, this.addIfNotPresent, "checkbox1"); - } - -} diff --git a/src/de/usd/cstchef/operations/setter/HttpJsonSetter.java b/src/de/usd/cstchef/operations/setter/HttpJsonSetter.java deleted file mode 100644 index 2ff016b..0000000 --- a/src/de/usd/cstchef/operations/setter/HttpJsonSetter.java +++ /dev/null @@ -1,33 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IParameter; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP JSON", category = OperationCategory.SETTER, description = "Set a JSON parameter to the specified value.") -public class HttpJsonSetter extends SetterOperation { - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String parameterName = getWhere(); - if( parameterName.equals("") ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - byte[] newValue = getWhatBytes(); - IParameter param = getParameter(input, parameterName, IParameter.PARAM_JSON, helpers); - - if( param == null ) - return input; - - byte[] newRequest = replaceParam(input, param, newValue); - return newRequest; - } - -} diff --git a/src/de/usd/cstchef/operations/setter/HttpPostSetter.java b/src/de/usd/cstchef/operations/setter/HttpPostSetter.java deleted file mode 100644 index c2b38af..0000000 --- a/src/de/usd/cstchef/operations/setter/HttpPostSetter.java +++ /dev/null @@ -1,71 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IParameter; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP POST Param", category = OperationCategory.SETTER, description = "Set a POST parameter to the specified value.") -public class HttpPostSetter extends SetterOperation { - - private JCheckBox addIfNotPresent; - private JCheckBox urlEncode; - private JCheckBox urlEncodeAll; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String parameterName = getWhere(); - if( parameterName.equals("") ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - byte[] newValue = getWhatBytes(); - - if( urlEncodeAll.isSelected() || urlEncode.isSelected() ) - newValue = urlEncode(newValue, urlEncodeAll.isSelected(), helpers); - - IParameter param = getParameter(input, parameterName, IParameter.PARAM_BODY, helpers); - - if( param == null ) { - - if( !addIfNotPresent.isSelected() ) - return input; - - param = helpers.buildParameter(parameterName, "dummy", IParameter.PARAM_BODY); - input = helpers.addParameter(input, param); - param = getParameter(input, parameterName, IParameter.PARAM_BODY, helpers); - if( param == null ) - // This case occurs when the HTTP request is a JSON or XML request. Burp does not - // support adding parameters to these and therefore the request should stay unmodified. - throw new IllegalArgumentException("Failure while adding the parameter. Operation cannot be used on XML or JSON."); - } - - byte[] newRequest = replaceParam(input, param, newValue); - return newRequest; - } - - @Override - public void createUI() { - super.createUI(); - - this.urlEncode = new JCheckBox("URL encode"); - this.urlEncode.setSelected(false); - this.addUIElement(null, this.urlEncode, "checkbox1"); - - this.urlEncodeAll = new JCheckBox("URL encode all"); - this.urlEncodeAll.setSelected(false); - this.addUIElement(null, this.urlEncodeAll, "checkbox2"); - - this.addIfNotPresent = new JCheckBox("Add if not present"); - this.addIfNotPresent.setSelected(true); - this.addUIElement(null, this.addIfNotPresent, "checkbox3"); - } - -} diff --git a/src/de/usd/cstchef/operations/setter/HttpSetBody.java b/src/de/usd/cstchef/operations/setter/HttpSetBody.java deleted file mode 100644 index c4ba5ce..0000000 --- a/src/de/usd/cstchef/operations/setter/HttpSetBody.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import java.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IRequestInfo; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.FormatTextField; - -@OperationInfos(name = "HTTP Body", category = OperationCategory.SETTER, description = "Set the HTTP body to the specified value.") -public class HttpSetBody extends Operation { - - private FormatTextField replacementTxt; - - @Override - protected byte[] perform(byte[] input) throws Exception { - IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); - IRequestInfo requestInfo = cbs.getHelpers().analyzeRequest(input); - int bodyOffset = requestInfo.getBodyOffset(); - - byte[] noBody = Arrays.copyOfRange(input, 0, bodyOffset); - byte[] newBody = replacementTxt.getText(); - byte[] newRequest = new byte[noBody.length + newBody.length]; - System.arraycopy(noBody, 0, newRequest, 0, noBody.length); - System.arraycopy(newBody, 0, newRequest, noBody.length, newBody.length); - - return newRequest; - } - - @Override - public void createUI() { - this.replacementTxt = new FormatTextField(); - this.addUIElement("Body", this.replacementTxt); - } - -} diff --git a/src/de/usd/cstchef/operations/setter/HttpSetCookie.java b/src/de/usd/cstchef/operations/setter/HttpSetCookie.java deleted file mode 100644 index d11d80d..0000000 --- a/src/de/usd/cstchef/operations/setter/HttpSetCookie.java +++ /dev/null @@ -1,92 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IResponseInfo; -import de.usd.cstchef.Utils; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP Cookie", category = OperationCategory.SETTER, description = "Set a HTTP cookie to the specified value.") -public class HttpSetCookie extends SetterOperation { - - private JCheckBox addIfNotPresent; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] newValue = getWhatBytes(); - byte[] cookieName = getWhereBytes(); - if( cookieName.length == 0 ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - byte[] cookieSearch = new byte[cookieName.length + 1]; - System.arraycopy(cookieName, 0, cookieSearch, 0, cookieName.length); - System.arraycopy("=".getBytes(), 0, cookieSearch, cookieName.length, 1); - - IResponseInfo resp = helpers.analyzeResponse(input); - boolean isRequest = (resp.getStatusCode() == 0); - - String cookieHeader = "\r\nSet-Cookie: "; - if(isRequest) - cookieHeader = "\r\nCookie: "; - - int offset = -1; - int cookieHeaderLength = cookieHeader.length(); - - try { - - offset = helpers.indexOf(input, cookieHeader.getBytes(), false, 0, length); - int line_end = helpers.indexOf(input, "\r\n".getBytes(), false, offset + 2, length); - int start = helpers.indexOf(input, cookieSearch, true, offset, line_end); - int end = helpers.indexOf(input, ";".getBytes(), true, start, line_end); - - if( end < 0 ) - end = line_end; - - return Utils.insertAtOffset(input, start + cookieSearch.length, end, newValue); - - } catch( IllegalArgumentException e ) { - - if( !addIfNotPresent.isSelected() ) - return input; - - if( (offset > 0) && isRequest ) { - - byte[] value = new byte[cookieName.length + newValue.length + 3]; - System.arraycopy(cookieName, 0, value, 0, cookieName.length); - System.arraycopy("=".getBytes(), 0, value, cookieName.length, 1); - System.arraycopy(newValue, 0, value, cookieName.length + 1, newValue.length); - System.arraycopy("; ".getBytes(), 0, value, cookieName.length + 1 + newValue.length, 2); - return Utils.insertAtOffset(input, offset + cookieHeaderLength, offset + cookieHeaderLength, value); - - } else { - - int bodyOffset = resp.getBodyOffset() - 4; - byte[] value = new byte[cookieName.length + newValue.length + cookieHeaderLength + 2]; - System.arraycopy(cookieHeader.getBytes(), 0, value, 0, cookieHeaderLength); - System.arraycopy(cookieName, 0, value, cookieHeaderLength, cookieName.length); - System.arraycopy("=".getBytes(), 0, value, cookieHeaderLength + cookieName.length, 1); - System.arraycopy(newValue, 0, value, cookieHeaderLength + cookieName.length + 1, newValue.length); - System.arraycopy(";".getBytes(), 0, value, cookieHeaderLength + cookieName.length + 1 + newValue.length, 1); - return Utils.insertAtOffset(input, bodyOffset, bodyOffset, value); - } - } - } - - @Override - public void createUI() { - super.createUI(); - this.addIfNotPresent = new JCheckBox("Add if not present"); - this.addIfNotPresent.setSelected(true); - this.addUIElement(null, this.addIfNotPresent, "checkbox1"); - } - -} diff --git a/src/de/usd/cstchef/operations/setter/HttpSetUri.java b/src/de/usd/cstchef/operations/setter/HttpSetUri.java deleted file mode 100644 index ad55dc1..0000000 --- a/src/de/usd/cstchef/operations/setter/HttpSetUri.java +++ /dev/null @@ -1,64 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import java.util.Arrays; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "HTTP URI", category = OperationCategory.SETTER, description = "Sets the specified variable as the uri.") -public class HttpSetUri extends Operation { - - private VariableTextField uriTxt; - private JCheckBox checkbox; - - @Override - public void createUI() { - this.uriTxt = new VariableTextField(); - this.addUIElement("Uri", this.uriTxt); - - this.checkbox = new JCheckBox("Keep parameters"); - this.checkbox.setSelected(false); - this.addUIElement(null, this.checkbox, "checkbox1"); - } - - - @Override - protected byte[] perform(byte[] input) throws Exception { - try { - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - int firstMark = helpers.indexOf(input, " ".getBytes(), false, 0, length); - int lineMark = helpers.indexOf(input, " ".getBytes(), false, firstMark + 1, length); - - int secondMark = helpers.indexOf(input, "?".getBytes(), false, firstMark + 1, length); - - if( !this.checkbox.isSelected() || secondMark < 0 || secondMark >= lineMark ) { - secondMark = lineMark; - } - - byte[] method = Arrays.copyOfRange(input, 0, firstMark + 1); - byte[] newUri = this.uriTxt.getBytes(); - byte[] rest = Arrays.copyOfRange(input, secondMark, length); - - byte[] newRequest = new byte[method.length + newUri.length + rest.length]; - System.arraycopy(method, 0, newRequest, 0, method.length); - System.arraycopy(newUri, 0, newRequest, method.length, newUri.length); - System.arraycopy(rest, 0, newRequest, method.length + newUri.length, rest.length); - - return newRequest; - - } catch (Exception e) { - throw new IllegalArgumentException("Provided input is not a valid http request."); - } - } - -} diff --git a/src/de/usd/cstchef/operations/setter/HttpXmlSetter.java b/src/de/usd/cstchef/operations/setter/HttpXmlSetter.java deleted file mode 100644 index b783db9..0000000 --- a/src/de/usd/cstchef/operations/setter/HttpXmlSetter.java +++ /dev/null @@ -1,33 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IParameter; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "HTTP XML", category = OperationCategory.SETTER, description = "Set a XML parameter to the specified value.") -public class HttpXmlSetter extends SetterOperation { - - @Override - protected byte[] perform(byte[] input) throws Exception { - - String parameterName = getWhere(); - if( parameterName.equals("") ) - return input; - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - byte[] newValue = getWhatBytes(); - IParameter param = getParameter(input, parameterName, IParameter.PARAM_XML, helpers); - - if( param == null ) - return input; - - byte[] newRequest = replaceParam(input, param, newValue); - return newRequest; - } - -} diff --git a/src/de/usd/cstchef/operations/setter/JsonSetter.java b/src/de/usd/cstchef/operations/setter/JsonSetter.java deleted file mode 100644 index 99447f1..0000000 --- a/src/de/usd/cstchef/operations/setter/JsonSetter.java +++ /dev/null @@ -1,91 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import java.awt.Color; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; - -import javax.swing.JCheckBox; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; - -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "JSON", category = OperationCategory.SETTER, description = "Set value of json object.") -public class JsonSetter extends SetterOperation implements ActionListener { - - private JCheckBox addIfNotPresent; - private VariableTextField path; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - if( getWhere().equals("") ) - return input; - - DocumentContext document = JsonPath.parse(new String(input)); - - try { - document.read(getWhere()); - } catch( Exception e ) { - - if( !addIfNotPresent.isSelected() ) - throw new IllegalArgumentException("Key not found."); - - String insertPath = this.path.getText(); - if( insertPath.equals("Insert-Path") || insertPath.equals("") ) - insertPath = "$"; - - document = document.put(insertPath, getWhere(), getWhat()); - return document.jsonString().getBytes(); - } - - document.set(getWhere(), getWhat()); - return document.jsonString().getBytes(); - } - - @Override - public void createUI() { - super.createUI(); - this.addIfNotPresent = new JCheckBox("Add if not present"); - this.addIfNotPresent.setSelected(true); - this.addIfNotPresent.addActionListener(this); - this.addUIElement(null, this.addIfNotPresent, "checkbox1"); - - this.path = new VariableTextField(); - this.path.setText("Insert-Path"); - this.path.setForeground(Color.GRAY); - this.path.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - if (path.getText().equals("Insertion Path")) { - path.setText(""); - path.setForeground(null); - } - } - @Override - public void focusLost(FocusEvent e) { - if (path.getText().isEmpty()) { - path.setForeground(Color.GRAY); - path.setText("Insertion Path"); - } - } - }); - this.addUIElement(null, this.path, "textbox1"); - } - - @Override - public void actionPerformed(ActionEvent arg0) { - if( arg0.getSource() == this.addIfNotPresent ) { - if( this.addIfNotPresent.isSelected() ) { - this.path.setEditable(true); - } else { - this.path.setEditable(false); - } - } - } -} diff --git a/src/de/usd/cstchef/operations/setter/LineSetter.java b/src/de/usd/cstchef/operations/setter/LineSetter.java deleted file mode 100644 index ebff621..0000000 --- a/src/de/usd/cstchef/operations/setter/LineSetter.java +++ /dev/null @@ -1,92 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import java.util.Arrays; - -import javax.swing.JCheckBox; -import javax.swing.JComboBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.Utils; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "Line Setter", category = OperationCategory.SETTER, description = "Sets a line to the specified value.") -public class LineSetter extends SetterOperation { - - private JCheckBox append; - private JComboBox formatBox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - int lineNumber; - try { - String number = getWhere(); - lineNumber = Integer.valueOf(number); - } catch( Exception e ) { - return input; - } - - if( lineNumber <= 0 ) - return input; - - byte[] newValue = getWhatBytes(); - byte[] lineEndings = "\r\n".getBytes(); - switch ((String) this.formatBox.getSelectedItem()) { - case "\\r\\n": - lineEndings = "\r\n".getBytes(); - break; - case "\\r": - lineEndings = "\r".getBytes(); - break; - case "\\n": - lineEndings = "\n".getBytes(); - break; - } - - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - int length = input.length; - - int start = 0; - int offset = 0; - int counter = 0; - while( counter < lineNumber - 1 ) { - offset = helpers.indexOf(input, lineEndings, false, start, length); - if( offset >= 0 ) { - start = offset + lineEndings.length; - counter++; - } else { - break; - } - } - - int end = helpers.indexOf(input, lineEndings, false, start, length); - if( end < 0 ) - end = length; - - if( append.isSelected() ) { - byte[] value = new byte[newValue.length + lineEndings.length]; - System.arraycopy(lineEndings, 0, value, 0, lineEndings.length); - System.arraycopy(newValue, 0, value, lineEndings.length, newValue.length); - return Utils.insertAtOffset(input, end, end, value); - } else { - return Utils.insertAtOffset(input, start, end, newValue); - } - } - - @Override - public void createUI() { - super.createUI(); - this.append = new JCheckBox("Insert below"); - this.append.setSelected(false); - this.addUIElement(null, this.append, "checkbox1"); - - this.formatBox = new JComboBox<>(new String[] {"\\r\\n", "\\r", "\\n"}); - this.formatBox.setSelectedItem("\\r\\n"); - this.addUIElement("Lineseperator", this.formatBox); - } - -} diff --git a/src/de/usd/cstchef/operations/setter/SetterOperation.java b/src/de/usd/cstchef/operations/setter/SetterOperation.java deleted file mode 100644 index b3be909..0000000 --- a/src/de/usd/cstchef/operations/setter/SetterOperation.java +++ /dev/null @@ -1,104 +0,0 @@ -package de.usd.cstchef.operations.setter; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import org.bouncycastle.util.encoders.Hex; - -import burp.IExtensionHelpers; -import burp.IParameter; -import burp.IRequestInfo; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.view.ui.VariableTextField; - -public abstract class SetterOperation extends Operation { - - private VariableTextField whereToSet; - private VariableTextField whatToSet; - - @Override - public void createUI() { - this.whereToSet = new VariableTextField(); - this.whatToSet = new VariableTextField(); - this.addUIElement("Key", this.whereToSet); - this.addUIElement("Value", this.whatToSet); - } - - protected String getWhere() { - return whereToSet.getText(); - } - - protected byte[] getWhereBytes() { - return whereToSet.getBytes(); - } - - protected String getWhat() { - return whatToSet.getText(); - } - - protected byte[] getWhatBytes() { - return whatToSet.getBytes(); - } - - // This is required because Burps getRequestParameter returns always the first occurrence of the parameter name. - // If you have e.g. a cookie with the same name as the POST parameter, you have no chance of getting the POST - // parameter using getRequestParameter (at least I do not know how). - protected IParameter getParameter(byte[] request, String paramName, byte type, IExtensionHelpers helpers) { - - IRequestInfo info = helpers.analyzeRequest(request); - List parameters = info.getParameters(); - IParameter param = null; - - for(IParameter p:parameters) { - if( p.getName().equals(paramName) ) - if( p.getType() == type ) { - param = p; - break; - } - } - return param; - } - - protected byte[] urlEncode(byte[] input, boolean all, IExtensionHelpers helpers) throws IOException { - - byte[] newValue = input; - - if( all ) { - byte[] delimiter = "%".getBytes(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(delimiter); - - for (int i = 0; i < newValue.length - 1; i++) { - out.write(Hex.encode(new byte[] { newValue[i] })); - out.write(delimiter); - } - - out.write(Hex.encode(new byte[] { newValue[newValue.length - 1] })); - newValue = out.toByteArray(); - - } else { - newValue = helpers.urlEncode(input); - } - - return newValue; - } - - protected byte[] replaceParam(byte[] request, IParameter param, byte[] newValue) { - - int length = request.length; - int start = param.getValueStart(); - int end = param.getValueEnd(); - - byte[] prefix = Arrays.copyOfRange(request, 0, start); - byte[] rest = Arrays.copyOfRange(request, end, length); - - byte[] newRequest = new byte[prefix.length + newValue.length + rest.length]; - System.arraycopy(prefix, 0, newRequest, 0, prefix.length); - System.arraycopy(newValue, 0, newRequest, prefix.length, newValue.length); - System.arraycopy(rest, 0, newRequest, prefix.length + newValue.length, rest.length); - - return newRequest; - } -} diff --git a/src/de/usd/cstchef/operations/signature/RsaSignature.java b/src/de/usd/cstchef/operations/signature/RsaSignature.java deleted file mode 100644 index b02b463..0000000 --- a/src/de/usd/cstchef/operations/signature/RsaSignature.java +++ /dev/null @@ -1,69 +0,0 @@ -package de.usd.cstchef.operations.signature; - -import java.security.Signature; - -import javax.swing.JComboBox; - -import org.bouncycastle.util.encoders.Base64; -import org.bouncycastle.util.encoders.Hex; - -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "RSA Signature", category = OperationCategory.SIGNATURE, description = "Create an RSA signature") -public class RsaSignature extends KeystoreOperation { - - private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" }; - - protected JComboBox algos; - protected JComboBox inputMode; - protected JComboBox outputMode; - - public RsaSignature() { - super(); - this.createMyUI(); - } - - protected byte[] perform(byte[] input) throws Exception { - - if( !this.keyAvailable.isSelected() ) - throw new IllegalArgumentException("No private key available."); - - String algo = (String)algos.getSelectedItem(); - Signature signature = Signature.getInstance(algo); - - String selectedInputMode = (String)inputMode.getSelectedItem(); - String selectedOutputMode = (String)outputMode.getSelectedItem(); - - if( selectedInputMode.equals("Hex") ) - input = Hex.decode(input); - if( selectedInputMode.equals("Base64") ) - input = Base64.decode(input); - - signature.initSign(this.selectedEntry.getPrivateKey()); - signature.update(input); - byte[] result = signature.sign(); - - if( selectedOutputMode.equals("Hex") ) - result = Hex.encode(result); - if( selectedOutputMode.equals("Base64") ) - result = Base64.encode(result); - - return result; - } - - public void createMyUI() { - - super.createMyUI(); - SignatureUtils utils = SignatureUtils.getInstance(); - - this.algos = new JComboBox<>(utils.getRsaAlgos()); - this.addUIElement("Padding", this.algos); - - this.inputMode = new JComboBox<>(inOutModes); - this.addUIElement("Input", this.inputMode); - - this.outputMode = new JComboBox<>(inOutModes); - this.addUIElement("Output", this.outputMode); - } -} diff --git a/src/de/usd/cstchef/operations/signature/SignatureUtils.java b/src/de/usd/cstchef/operations/signature/SignatureUtils.java deleted file mode 100644 index 04be967..0000000 --- a/src/de/usd/cstchef/operations/signature/SignatureUtils.java +++ /dev/null @@ -1,42 +0,0 @@ -package de.usd.cstchef.operations.signature; - -import java.security.Provider; -import java.security.Provider.Service; -import java.security.Security; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -public class SignatureUtils { - - private static SignatureUtils instance; - - private List algos; - - private SignatureUtils() { - algos = new ArrayList();; - getSignatureInfos(); - } - - private void getSignatureInfos() { - for (Provider provider : Security.getProviders()) - for (Service service : provider.getServices()) - if (service.getType().equals("Signature")) - algos.add(service.getAlgorithm()); - } - - public static SignatureUtils getInstance() { - if (instance == null) { - instance = new SignatureUtils(); - } - return instance; - } - - public String[] getAlgos() { - return algos.toArray(new String[0]); - } - public String[] getRsaAlgos() { - List rsaAlgos = algos.stream().filter(p -> p.contains("RSA")).collect(Collectors.toList()); - return rsaAlgos.toArray(new String[0]); - } -} diff --git a/src/de/usd/cstchef/operations/string/Prefix.java b/src/de/usd/cstchef/operations/string/Prefix.java deleted file mode 100644 index 374a8a8..0000000 --- a/src/de/usd/cstchef/operations/string/Prefix.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.usd.cstchef.operations.string; - -import java.io.ByteArrayOutputStream; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.FormatTextField; - -@OperationInfos(name = "Prefix", category = OperationCategory.STRING, description = "Adds a prefix.") -public class Prefix extends Operation { - - private FormatTextField prefixTxt; - - @Override - protected byte[] perform(byte[] input) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(prefixTxt.getText()); - out.write(input); - - return out.toByteArray(); - } - - @Override - public void createUI() { - this.prefixTxt = new FormatTextField(); - this.addUIElement("Prefix", this.prefixTxt); - } - -} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/string/Replace.java b/src/de/usd/cstchef/operations/string/Replace.java deleted file mode 100644 index 1dc86b6..0000000 --- a/src/de/usd/cstchef/operations/string/Replace.java +++ /dev/null @@ -1,64 +0,0 @@ -package de.usd.cstchef.operations.string; - -import javax.swing.JCheckBox; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.VariableTextArea; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "Replace", category = OperationCategory.STRING, description = "Uses a regular expression to replace all occurences. Has side effect on binary content due to String Encoding.") -public class Replace extends Operation { - - private JCheckBox checkbox; - private VariableTextField exptTxt; - private VariableTextArea replacementTxt; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] result = null; - if( checkbox.isSelected() ) { - String inputStr = new String(input); - result = inputStr.replaceAll(exptTxt.getText(), replacementTxt.getText()).getBytes(); - } else { - IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = cbs.getHelpers(); - - int start = helpers.indexOf(input, exptTxt.getBytes(), true, 0, input.length); - - if(start < 0) - return input; - - byte[] replaced = exptTxt.getBytes(); - byte[] replacement = replacementTxt.getBytes(); - - byte[] newRequest = new byte[input.length + replacement.length - replaced.length]; - System.arraycopy(input, 0, newRequest, 0, start); - System.arraycopy(replacement, 0, newRequest, start, replacement.length); - System.arraycopy(input, start + replaced.length, newRequest, start + replacement.length, input.length - replaced.length - start); - - result = newRequest; - } - - return result; - } - - @Override - public void createUI() { - this.exptTxt = new VariableTextField(); - this.addUIElement("Expr", this.exptTxt); - - this.checkbox = new JCheckBox("Regex"); - this.checkbox.setSelected(false); - this.addUIElement(null, this.checkbox, "checkbox1"); - - this.replacementTxt = new VariableTextArea(); - this.addUIElement("Value", this.replacementTxt); - } - -} diff --git a/src/de/usd/cstchef/operations/string/SplitAndSelect.java b/src/de/usd/cstchef/operations/string/SplitAndSelect.java deleted file mode 100644 index 5d8e19b..0000000 --- a/src/de/usd/cstchef/operations/string/SplitAndSelect.java +++ /dev/null @@ -1,67 +0,0 @@ -package de.usd.cstchef.operations.string; - -import org.bouncycastle.util.Arrays; - -import burp.BurpUtils; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.VariableTextField; - -@OperationInfos(name = "Split and Select", category = OperationCategory.STRING, description = "Split input and select one item.") -public class SplitAndSelect extends Operation { - - private VariableTextField item; - private VariableTextField delim; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] delimmiter = delim.getBytes(); - - int itemNumber = 0; - try { - String itemValue = item.getText(); - itemNumber = Integer.valueOf(itemValue); - } catch(Exception e) { - return input; - } - - if( itemNumber < 0 ) - return input; - - IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = cbs.getHelpers(); - int length = input.length; - - int start = 0; - int offset = 0; - int counter = 0; - while( counter < itemNumber ) { - offset = helpers.indexOf(input, delimmiter, false, start, length); - if( offset >= 0 ) { - start = offset + delimmiter.length; - counter++; - } else { - break; - } - } - - int end = helpers.indexOf(input, delimmiter, false, start, length); - if( end < 0 ) - end = length; - - byte[] result = Arrays.copyOfRange(input, start, end); - return result; - } - - @Override - public void createUI() { - this.delim = new VariableTextField(); - this.addUIElement("Delimmiter", this.delim); - this.item = new VariableTextField(); - this.addUIElement("Item number", this.item); - } -} diff --git a/src/de/usd/cstchef/operations/string/Substring.java b/src/de/usd/cstchef/operations/string/Substring.java deleted file mode 100644 index 3a984d0..0000000 --- a/src/de/usd/cstchef/operations/string/Substring.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.usd.cstchef.operations.string; - -import javax.swing.JSpinner; - -import org.bouncycastle.util.Arrays; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; - -@OperationInfos(name = "Substring", category = OperationCategory.STRING, description = "Extracts a substring.") -public class Substring extends Operation { - - private JSpinner startSpinner; - private JSpinner endSpinner; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - int start = (int) startSpinner.getValue(); - int end = (int) endSpinner.getValue(); - - if( start < 0 ) - start = input.length + start; - if( end < 0 ) - end = input.length + end; - if( end > input.length ) - end = input.length + 1; - - byte[] slice = Arrays.copyOfRange(input, start, end); - return slice; - } - - @Override - public void createUI() { - this.startSpinner = new JSpinner(); - this.addUIElement("Start", this.startSpinner); - - this.endSpinner = new JSpinner(); - this.addUIElement("End", this.endSpinner); - } - -} diff --git a/src/de/usd/cstchef/operations/string/Suffix.java b/src/de/usd/cstchef/operations/string/Suffix.java deleted file mode 100644 index cf85b74..0000000 --- a/src/de/usd/cstchef/operations/string/Suffix.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.usd.cstchef.operations.string; - -import java.io.ByteArrayOutputStream; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.view.ui.FormatTextField; - -@OperationInfos(name = "Suffix", category = OperationCategory.STRING, description = "Adds a suffix.") -public class Suffix extends Operation { - - private FormatTextField suffixTxt; - - @Override - protected byte[] perform(byte[] input) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(input); - out.write(suffixTxt.getText()); - - return out.toByteArray(); - } - - @Override - public void createUI() { - this.suffixTxt = new FormatTextField (); - this.addUIElement("Suffix", this.suffixTxt); - } - -} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/utils/GetVariable.java b/src/de/usd/cstchef/operations/utils/GetVariable.java deleted file mode 100644 index e6041c7..0000000 --- a/src/de/usd/cstchef/operations/utils/GetVariable.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.usd.cstchef.operations.utils; - -import javax.swing.JTextField; - -import de.usd.cstchef.VariableStore; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; - -@OperationInfos(name = "Get Variable", category = OperationCategory.UTILS, description = "Retrives a stored variable.") -public class GetVariable extends Operation { - - private JTextField varNameTxt; - private JTextField defaultTxt; - - @Override - protected byte[] perform(byte[] input) throws Exception { - String varName = this.varNameTxt.getText().trim(); - byte[] var = VariableStore.getInstance().getVariable(varName); - return var == null ? this.defaultTxt.getText().getBytes() : var; - } - - public void createUI() { - this.varNameTxt = new JTextField(); - this.addUIElement("Variable name", this.varNameTxt); - - this.defaultTxt = new JTextField(); - this.addUIElement("Default value", this.defaultTxt); - } - -} diff --git a/src/de/usd/cstchef/operations/utils/RandomNumber.java b/src/de/usd/cstchef/operations/utils/RandomNumber.java deleted file mode 100644 index 57cca74..0000000 --- a/src/de/usd/cstchef/operations/utils/RandomNumber.java +++ /dev/null @@ -1,35 +0,0 @@ -package de.usd.cstchef.operations.utils; - -import java.security.SecureRandom; - -import javax.swing.JTextField; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; - -@OperationInfos(name = "Random Number", category = OperationCategory.UTILS, description = "Generate a random number.") -public class RandomNumber extends Operation { - - private JTextField maximum; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - SecureRandom secRand = new SecureRandom(); - try { - int bound = Integer.valueOf(this.maximum.getText()) + 1; - int random = Math.abs(secRand.nextInt(bound)); - return String.valueOf(random).getBytes(); - } catch( Exception e ) { - int random = Math.abs(secRand.nextInt()); - return String.valueOf(random).getBytes(); - } - } - - public void createUI() { - this.maximum = new JTextField(); - this.addUIElement("Maximum Number", this.maximum); - } - -} diff --git a/src/de/usd/cstchef/operations/utils/SetIfEmpty.java b/src/de/usd/cstchef/operations/utils/SetIfEmpty.java deleted file mode 100644 index d1e0581..0000000 --- a/src/de/usd/cstchef/operations/utils/SetIfEmpty.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.usd.cstchef.operations.utils; - -import javax.swing.JCheckBox; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.view.ui.FormatTextField; - -@OperationInfos(name = "Set if Empty", category = OperationCategory.UTILS, description = "Sets a value if the input is empty.") -public class SetIfEmpty extends Operation { - - private FormatTextField value; - private JCheckBox checkbox; - - @Override - protected byte[] perform(byte[] input) throws Exception { - - byte[] valueToSet = value.getText(); - if( input.length == 0 ) { - return valueToSet; - } - - if( !checkbox.isSelected() ) - return input; - - int i = 0; - while( i < input.length ) { - if( input[i] != 32 ) { - return input; - } - i++; - } - - return valueToSet; - } - - public void createUI() { - this.value = new FormatTextField(); - this.addUIElement("Value to set", this.value); - - this.checkbox = new JCheckBox("Space is empty"); - this.checkbox.setSelected(false); - this.addUIElement(null, this.checkbox, "checkbox1"); - } -} diff --git a/src/de/usd/cstchef/operations/utils/StoreVariable.java b/src/de/usd/cstchef/operations/utils/StoreVariable.java deleted file mode 100644 index a23fc83..0000000 --- a/src/de/usd/cstchef/operations/utils/StoreVariable.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.usd.cstchef.operations.utils; - -import javax.swing.JTextField; - -import de.usd.cstchef.VariableStore; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; - -@OperationInfos(name = "Store Variable", category = OperationCategory.UTILS, description = "Stores variables to be retrieved later.") -public class StoreVariable extends Operation { - - private JTextField varNameTxt; - private String oldVarName; - - @Override - protected byte[] perform(byte[] input) throws Exception { - String newVarName = this.varNameTxt.getText().trim(); - VariableStore store = VariableStore.getInstance(); - // remove old variable from hashmap - if (!newVarName.equals(oldVarName)) { - store.removeVariable(this.oldVarName); - this.oldVarName = newVarName; - } - - if (!newVarName.isEmpty()) { - store.setVariable(newVarName, input); - } - - return input; - } - - public void createUI() { - this.varNameTxt = new JTextField(); - this.addUIElement("Variable name", this.varNameTxt); - } - - @Override - public void onRemove() { - VariableStore.getInstance().removeVariable(this.oldVarName); - } - -} diff --git a/src/de/usd/cstchef/view/AddOperationMouseAdapter.java b/src/de/usd/cstchef/view/AddOperationMouseAdapter.java deleted file mode 100644 index 38efaf8..0000000 --- a/src/de/usd/cstchef/view/AddOperationMouseAdapter.java +++ /dev/null @@ -1,32 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.Container; -import javax.swing.JTree; -import javax.swing.tree.TreePath; - -import de.usd.cstchef.operations.Operation; - -public class AddOperationMouseAdapter extends OperationMouseAdapter { - - - public AddOperationMouseAdapter(JTree source, Container target) { - super(source, target); - } - - @Override - protected Operation getDraggedOperation(int x, int y) { - TreePath draggedPath = ((JTree) this.source).getClosestPathForLocation(x, y); - if (draggedPath != null) { - Object node = draggedPath.getLastPathComponent(); - if (node.getClass().equals(OperationTreeNode.class)) { - Class cls = ((OperationTreeNode) node).getOperationClass(); - try { - return cls.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - } - } - } - return null; - } - -} diff --git a/src/de/usd/cstchef/view/BurpEditorWrapper.java b/src/de/usd/cstchef/view/BurpEditorWrapper.java deleted file mode 100644 index 4d6af6c..0000000 --- a/src/de/usd/cstchef/view/BurpEditorWrapper.java +++ /dev/null @@ -1,100 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.Component; -import java.util.Arrays; - -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; - -import burp.BurpUtils; -import burp.IMessageEditor; -import burp.IMessageEditorController; - -public class BurpEditorWrapper implements IMessageEditor, DocumentListener { - - private JTextArea fallbackArea; - private IMessageEditor burpEditor; - public boolean fallbackMode; - boolean isModified; - byte[] lastContent; - - public BurpEditorWrapper(IMessageEditorController controller, boolean editable) { - if (BurpUtils.inBurp()) { - this.burpEditor = BurpUtils.getInstance().getCallbacks().createMessageEditor(controller, editable); - fallbackMode = false; - } else { - this.fallbackArea = new JTextArea(); - this.fallbackArea.getDocument().addDocumentListener(this); - fallbackMode = true; - } - } - - @Override - public Component getComponent() { - if (fallbackMode) { - JScrollPane inputScrollPane = new JScrollPane(fallbackArea); - return inputScrollPane; - } - return burpEditor.getComponent(); - } - - @Override - public byte[] getMessage() { - byte[] result; - result = fallbackMode ? fallbackArea.getText().getBytes() : burpEditor.getMessage(); - return result == null ? new byte[0] : result; - } - - @Override - public byte[] getSelectedData() { - return null; - } - - @Override - public int[] getSelectionBounds() { - return null; - } - - @Override - public boolean isMessageModified() { - if (fallbackMode) { - boolean state = this.isModified; - this.isModified = false; - return state; - } - // TODO: a little hack here - if (!Arrays.equals(lastContent, getMessage())) { - lastContent = getMessage(); - return true; - } - return false; - } - - @Override - public void setMessage(byte[] arg0, boolean arg1) { - if (fallbackMode) { - fallbackArea.setText(new String(arg0)); - } else { - this.lastContent = arg0; - burpEditor.setMessage(arg0, arg1); //TODO fix second parameter - } - } - - @Override - public void changedUpdate(DocumentEvent e) { - this.isModified = true; - } - - @Override - public void insertUpdate(DocumentEvent e) { - this.isModified = true; - } - - @Override - public void removeUpdate(DocumentEvent e) { - this.isModified = true; - } - -} diff --git a/src/de/usd/cstchef/view/FormatTab.java b/src/de/usd/cstchef/view/FormatTab.java deleted file mode 100644 index 8fe2978..0000000 --- a/src/de/usd/cstchef/view/FormatTab.java +++ /dev/null @@ -1,70 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.Component; - -import burp.BurpUtils; -import burp.IMessageEditorTab; -import burp.ITextEditor; -import burp.Logger; - -public class FormatTab implements IMessageEditorTab { - private ITextEditor txtInput; - private boolean editable; - private RecipePanel responseFormatRecipePanel; - private RecipePanel requestFormatRecipePanel; - private byte[] currentMessage; - - public FormatTab(RecipePanel requestFormatRecipePanel, RecipePanel responseFormatRecipePanel, boolean editable) { - this.editable = editable; - this.responseFormatRecipePanel = responseFormatRecipePanel; - this.requestFormatRecipePanel = requestFormatRecipePanel; - txtInput = BurpUtils.getInstance().getCallbacks().createTextEditor(); - txtInput.setEditable(editable); - } - - @Override - public String getTabCaption() { - return "CSTC"; - } - - @Override - public Component getUiComponent() { - return txtInput.getComponent(); - } - - @Override - public boolean isEnabled(byte[] content, boolean isRequest) { - return true; - } - - @Override - public void setMessage(byte[] content, boolean isRequest) { - currentMessage = content; - - if (content == null) { - txtInput.setText("Nothing here".getBytes()); - txtInput.setEditable(false); - return; - } - RecipePanel recipe = isRequest ? this.requestFormatRecipePanel : this.responseFormatRecipePanel; - Logger.getInstance().log("baking new stuff"); - byte[] result = recipe.bake(content); - this.txtInput.setText(result); - } - - @Override - public byte[] getMessage() { - return currentMessage; - } - - @Override - public boolean isModified() { - return txtInput.isTextModified(); - } - - @Override - public byte[] getSelectedData() { - return txtInput.getSelectedText(); - } - -} \ No newline at end of file diff --git a/src/de/usd/cstchef/view/LayoutPanel.java b/src/de/usd/cstchef/view/LayoutPanel.java deleted file mode 100644 index ad5892c..0000000 --- a/src/de/usd/cstchef/view/LayoutPanel.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Font; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.UIManager; - -public class LayoutPanel extends JPanel { - - private Box headerBox; - - public LayoutPanel() { - this("No tile"); - } - - public LayoutPanel(String title) { - super(); - this.setLayout(new BorderLayout(0, 0)); - - this.headerBox = Box.createHorizontalBox(); - this.headerBox.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - this.headerBox.setOpaque(true); - this.headerBox.setBackground(UIManager.getColor("Panel.background")); - - JLabel titleLbl = new JLabel(title); - titleLbl.setAlignmentX(Component.LEFT_ALIGNMENT); - - Font f = titleLbl.getFont(); - titleLbl.setFont(f.deriveFont(f.getStyle() | Font.BOLD)); - - this.headerBox.add(titleLbl); - this.headerBox.add(Box.createHorizontalGlue()); - - this.add(headerBox, BorderLayout.PAGE_START); - } - - public void addActionComponent(JComponent comp) { - comp.setAlignmentX(Component.RIGHT_ALIGNMENT); - this.headerBox.add(comp); - this.headerBox.add(Box.createHorizontalStrut(10)); - } -} diff --git a/src/de/usd/cstchef/view/MoveOperationMouseAdapter.java b/src/de/usd/cstchef/view/MoveOperationMouseAdapter.java deleted file mode 100644 index 25587f6..0000000 --- a/src/de/usd/cstchef/view/MoveOperationMouseAdapter.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.Component; -import java.awt.Container; - -import de.usd.cstchef.operations.Operation; - -public class MoveOperationMouseAdapter extends OperationMouseAdapter { - - public MoveOperationMouseAdapter(RecipeStepPanel source, Container target) { - super(source.getOperationsPanel(), target); - } - - @Override - protected Operation getDraggedOperation(int x, int y) { - Component comp = this.source.getComponentAt(x, y); - comp.getParent().remove(comp); - - return comp instanceof Operation ? (Operation) comp : null; - } - -} diff --git a/src/de/usd/cstchef/view/OperationMouseAdapter.java b/src/de/usd/cstchef/view/OperationMouseAdapter.java deleted file mode 100644 index fef166f..0000000 --- a/src/de/usd/cstchef/view/OperationMouseAdapter.java +++ /dev/null @@ -1,241 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.dnd.DragSource; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.Objects; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JWindow; -import javax.swing.SwingUtilities; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; - -/* - * Based on: - * https://stackoverflow.com/questions/27245283/java-drag-and-drop-to-change-the-order-of-panels - */ -public abstract class OperationMouseAdapter extends MouseAdapter { - - private static final Rectangle R1 = new Rectangle(); - private static final Rectangle R2 = new Rectangle(); - - private static Rectangle prevRect; - - private final JWindow window = new JWindow(); - private Container panelPreview; - private JLabel windowPreviewLbl; - private JLabel panelPreviewLbl; - - private Point startPt; - private Point dragOffset; - private final int gestureMotionThreshold = DragSource.getDragThreshold(); - - protected Container source; - protected Container target; - private RecipeStepPanel currentTargetPanel; - - private Operation draggedOperation; - - public OperationMouseAdapter(Container source, Container target) { - super(); - this.source = source; - this.target = target; - window.setSize(300, 35); - window.setLocationRelativeTo(null); - window.setBackground(new Color(0, true)); - window.setVisible(false); - - Container windowPreview = createPreview("My Preview"); - windowPreviewLbl = (JLabel) windowPreview.getComponent(0); - window.add(windowPreview); - panelPreview = createPreview("My Preview"); - panelPreviewLbl = (JLabel) panelPreview.getComponent(0); - - dragOffset = new Point(window.getWidth() / 3, window.getHeight() / 2); - } - - private Container createPreview(String title) { - Box previewBox = Box.createHorizontalBox(); - previewBox.setOpaque(true); - previewBox.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - previewBox.setBackground(new Color(127, 237, 247, 255)); - - JLabel previewLbl = new JLabel(title); - previewLbl.setForeground(new Color(58, 135, 173)); - - previewBox.add(previewLbl); - return previewBox; - } - - private void startDragging(Point pt) { - OperationInfos opInfos = this.draggedOperation.getClass().getAnnotation(OperationInfos.class); - if (opInfos == null) { - return; - } - - String name = opInfos.name(); - windowPreviewLbl.setText(name); - panelPreviewLbl.setText(name); - - updateWindowLocation(pt, this.source); - window.setVisible(true); - } - - private void updateWindowLocation(Point pt, Container parent) { - Point p = new Point(pt.x - dragOffset.x, pt.y - dragOffset.y); - SwingUtilities.convertPointToScreen(p, parent); - window.setLocation(p); - } - - private int getTargetIndex(Rectangle r, Point pt, int i, boolean previewIndexSmaller) { - int ht2 = (int) (0.5 + r.height * 0.5); - R1.setBounds(r.x, r.y, r.width, ht2); - R2.setBounds(r.x, r.y + ht2, r.width, ht2); - if (R1.contains(pt)) { - prevRect = R1; - return previewIndexSmaller ? i - 1 : i - 1 > 0 ? i : 0; - } else if (R2.contains(pt)) { - prevRect = R2; - return i; - } - return -1; - } - - private void addComponent(RecipeStepPanel line, Component comp, int idx) { - line.removeComponent(comp); - line.addComponent(comp, idx); - } - - @Override - public void mousePressed(MouseEvent e) { - this.startPt = e.getPoint(); - } - - protected abstract Operation getDraggedOperation(int x, int y); - - @Override - public void mouseDragged(MouseEvent e) { - Point pt = e.getPoint(); - JComponent parent = (JComponent) e.getComponent(); - - // not yet dragging and motion > threshold - if (this.draggedOperation == null && startPt != null) { - double a = Math.pow(pt.x - startPt.x, 2); - double b = Math.pow(pt.y - startPt.y, 2); - if (Math.sqrt(a + b) > gestureMotionThreshold) { - this.draggedOperation = this.getDraggedOperation(startPt.x, startPt.y); - if (this.draggedOperation != null) { - startDragging(pt); - } - } - return; - } - - // dragging, but no component was created - if (!window.isVisible() || draggedOperation == null) { - return; - } - - pt = SwingUtilities.convertPoint(parent, e.getPoint(), this.target); - updateWindowLocation(pt, this.target); - - Component targetLine = this.target.getComponentAt(pt); - - // changed the target, remove the old preview - if (currentTargetPanel != null) { - if (targetLine == null || !targetLine.equals(currentTargetPanel)) { - this.currentTargetPanel.removeComponent(panelPreview); - this.currentTargetPanel = null; - } - } - - // we have no valid target - if (targetLine == null || !(targetLine instanceof RecipeStepPanel)) { - return; - } - - RecipeStepPanel targetPanel = (RecipeStepPanel) this.target.getComponentAt(pt); - this.currentTargetPanel = targetPanel; - - JPanel operationsPanel = currentTargetPanel.getOperationsPanel(); - pt = SwingUtilities.convertPoint(this.target, pt, operationsPanel); - - if (prevRect != null && prevRect.contains(pt)) { - return; - } - - boolean gotPreview = false; - for (int i = 0; i < operationsPanel.getComponentCount(); i++) { - Component comp = operationsPanel.getComponent(i); - Rectangle r = comp.getBounds(); - // inside our gap, do nothing - if (Objects.equals(comp, panelPreview)) { - if (r.contains(pt)) { - return; - } else { - gotPreview = true; - continue; - } - } - - int tgt; - if (!(comp instanceof Operation)) { //this is the dummy panel - int count = operationsPanel.getComponentCount(); - tgt = count > 1 ? operationsPanel.getComponentCount() - 2 : 0; - } else { - tgt = getTargetIndex(r, pt, i, gotPreview); - } - - if (tgt >= 0) { - addComponent(currentTargetPanel, panelPreview, tgt); - return; - } - } - } - - @Override - public void mouseReleased(MouseEvent e) { - startPt = null; - - // no dragging - if (!window.isVisible() || draggedOperation == null) { - return; - } - int addIndex = -1; - - // get the index of the preview element - if (currentTargetPanel != null) { - JPanel operationsPanel = this.currentTargetPanel.getOperationsPanel(); - for (int i = 0; i < operationsPanel.getComponentCount(); i++) { - Component comp = operationsPanel.getComponent(i); - if (comp.equals(this.panelPreview)) { - addIndex = i; - break; - } - } - // remove preview from panel - currentTargetPanel.removeComponent(this.panelPreview); - } - - if (addIndex != -1) { - currentTargetPanel.addComponent(this.draggedOperation, addIndex); - } - - this.draggedOperation = null; - prevRect = null; - this.startPt = null; - this.window.setVisible(false); - this.currentTargetPanel = null; - } -} diff --git a/src/de/usd/cstchef/view/OperationTreeNode.java b/src/de/usd/cstchef/view/OperationTreeNode.java deleted file mode 100644 index 2c9ae47..0000000 --- a/src/de/usd/cstchef/view/OperationTreeNode.java +++ /dev/null @@ -1,35 +0,0 @@ -package de.usd.cstchef.view; - -import javax.swing.tree.DefaultMutableTreeNode; - -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.Operation.OperationInfos; - -public class OperationTreeNode extends DefaultMutableTreeNode { - - private String name; - private String toolTipText; - private Class operationClass; - - public OperationTreeNode(Class operationClass) { - super(); - OperationInfos infos = operationClass.getAnnotation(OperationInfos.class); - this.name = infos.name(); - this.toolTipText = infos.description(); - - this.operationClass = operationClass; - } - - public String getToolTipText() { - return this.toolTipText; - } - - public Class getOperationClass() { - return operationClass; - } - - @Override - public String toString() { - return this.name; - } -} diff --git a/src/de/usd/cstchef/view/OperationsTree.java b/src/de/usd/cstchef/view/OperationsTree.java deleted file mode 100644 index 05ef9e6..0000000 --- a/src/de/usd/cstchef/view/OperationsTree.java +++ /dev/null @@ -1,160 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.event.MouseEvent; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; - -import javax.swing.ImageIcon; -import javax.swing.JTree; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.MutableTreeNode; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; - -import burp.Logger; -import de.usd.cstchef.Utils; -import de.usd.cstchef.operations.Operation; -import de.usd.cstchef.operations.OperationCategory; -import de.usd.cstchef.operations.Operation.OperationInfos; - -public class OperationsTree extends JTree { - - private DefaultTreeModel model; - private static ImageIcon nodeIcon = new ImageIcon(Operation.class.getResource("/operation.png")); - private static ImageIcon openIcon = new ImageIcon(Operation.class.getResource("/folder_open.png")); - private static ImageIcon closedIcon = new ImageIcon(Operation.class.getResource("/folder_closed.png")); - - public OperationsTree() { - super(); - - this.model = (DefaultTreeModel) this.getModel(); - this.model.setRoot(this.createTree()); - this.setToolTipText(""); - DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) this.getCellRenderer(); - renderer.setLeafIcon(nodeIcon); - renderer.setClosedIcon(closedIcon); - renderer.setOpenIcon(openIcon); - } - - @Override - public String getToolTipText(MouseEvent evt) { - if (getRowForLocation(evt.getX(), evt.getY()) == -1) { - return null; - } - - TreePath curPath = getPathForLocation(evt.getX(), evt.getY()); - Object node = curPath.getLastPathComponent(); - - if (node.getClass().equals(OperationTreeNode.class)) { - return ((OperationTreeNode) node).getToolTipText(); - } else if (node.getClass().equals(DefaultMutableTreeNode.class)) { - return null; - } - - return ""; - } - - public void search(String text) { - DefaultMutableTreeNode root = this.createTree(); - this.model.setRoot(root); - - if (text.trim().equals("")) { - return; - } - - ArrayList nodesToRemove = new ArrayList<>(); - Enumeration e = root.breadthFirstEnumeration(); - while (e.hasMoreElements()) { - DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) e.nextElement(); - if (!nextNode.toString().toLowerCase().contains(text.toLowerCase())) { - if (nextNode.getChildCount() == 0) { - nodesToRemove.add(nextNode); - } - } - } - - for (DefaultMutableTreeNode node : nodesToRemove) { - this.removeNode(node); - } - - nodesToRemove.clear(); - for (int i = 0; i < root.getChildCount(); i++) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i); - if (node.getChildCount() == 0) { - nodesToRemove.add(node); - } - } - - for (DefaultMutableTreeNode node : nodesToRemove) { - this.removeNode(node); - } - - this.expandAll(new TreePath(root)); - } - - private void removeNode(TreeNode selNode) { - if (selNode == null) { - return; - } - - MutableTreeNode parent = (MutableTreeNode) (selNode.getParent()); - if (parent == null) { - return; - } - - if (selNode.getChildCount() == 0) { - this.model.removeNodeFromParent((MutableTreeNode) selNode); - } - } - - private DefaultMutableTreeNode createTree() { - DefaultMutableTreeNode root = new DefaultMutableTreeNode(); - - // add all categories - HashMap categoryNodes = new HashMap<>(); - for (OperationCategory category : OperationCategory.values()) { - DefaultMutableTreeNode categoryNode = new DefaultMutableTreeNode(category.toString()); - root.add(categoryNode); - categoryNodes.put(category, categoryNode); - } - - // TODO add operations to categories - reflections do not work in burp :( - Class[] operations = Utils.getOperations(); - for (Class operation : operations) { - OperationInfos operationInfos = operation.getAnnotation(OperationInfos.class); - if (operationInfos == null) { - if (!Modifier.isAbstract(operation.getModifiers())) { - Logger.getInstance().err("Found a operation without annotaion: " + operation); - } - continue; - } - - OperationCategory category = operationInfos.category(); - DefaultMutableTreeNode parent = categoryNodes.get(category); - - OperationTreeNode newOperationNode = new OperationTreeNode(operation); - parent.add(newOperationNode); - } - - return root; - } - - private void expandAll(TreePath path) { - TreeNode node = (TreeNode) path.getLastPathComponent(); - - if (node.getChildCount() >= 0) { - Enumeration enumeration = node.children(); - while (enumeration.hasMoreElements()) { - TreeNode n = (TreeNode) enumeration.nextElement(); - TreePath p = path.pathByAddingChild(n); - - expandAll(p); - } - } - this.expandPath(path); - } -} diff --git a/src/de/usd/cstchef/view/PopupVariableMenu.java b/src/de/usd/cstchef/view/PopupVariableMenu.java deleted file mode 100644 index 697cb33..0000000 --- a/src/de/usd/cstchef/view/PopupVariableMenu.java +++ /dev/null @@ -1,65 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.HashMap; -import java.util.SortedMap; -import java.util.TreeMap; - -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; -import javax.swing.text.JTextComponent; - -public class PopupVariableMenu extends JPopupMenu implements ActionListener, PopupMenuListener { - - private JTextComponent parent; - private static SortedMap variableMap; - - public PopupVariableMenu(JTextComponent parent) { - super(); - this.parent = parent; - this.addPopupMenuListener(this); - - } - - public void refreshMenu() { - this.removeAll(); - - for (String key : variableMap.keySet()) { - JMenuItem item = new JMenuItem(key); - item.addActionListener(this); - this.add(item); - } - } - - public static void refresh(HashMap variables) { - if (variables == null) { - variableMap = new TreeMap(); - } else { - variableMap = new TreeMap(variables); - } - } - - @Override - public void actionPerformed(ActionEvent arg0) { - parent.setText(parent.getText() + "$" + arg0.getActionCommand()); - } - - @Override - public void popupMenuCanceled(PopupMenuEvent arg0) { - // not needed - } - - @Override - public void popupMenuWillBecomeInvisible(PopupMenuEvent arg0) { - // not needed - } - - @Override - public void popupMenuWillBecomeVisible(PopupMenuEvent arg0) { - this.refreshMenu(); - } - -} diff --git a/src/de/usd/cstchef/view/RecipePanel.java b/src/de/usd/cstchef/view/RecipePanel.java deleted file mode 100644 index 3350676..0000000 --- a/src/de/usd/cstchef/view/RecipePanel.java +++ /dev/null @@ -1,544 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; - -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; -import javax.swing.ToolTipManager; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import burp.BurpUtils; -import burp.CstcMessageEditorController; -import burp.IBurpExtenderCallbacks; -import burp.IExtensionHelpers; -import burp.IHttpRequestResponse; -import burp.IParameter; -import burp.IRequestInfo; -import burp.Logger; -import de.usd.cstchef.VariableStore; -import de.usd.cstchef.operations.Operation; - -public class RecipePanel extends JPanel implements ChangeListener { - - private static Logger logger = Logger.getInstance(); - - private int operationSteps = 10; - private boolean autoBake = true; - private boolean isRequest = true; - private int bakeThreshold = 400; - private String recipeName; - private int filterMask; - - private BurpEditorWrapper inputText; - private BurpEditorWrapper outputText; - - private JPanel operationLines; - private RequestFilterDialog requestFilterDialog; - - private CstcMessageEditorController controllerOrig; - private CstcMessageEditorController controllerMod; - - private Timer bakeTimer; - - public RecipePanel(String recipeName, boolean isRequest) { - - this.recipeName = recipeName; - this.isRequest = isRequest; - - ToolTipManager tooltipManager = ToolTipManager.sharedInstance(); - tooltipManager.setInitialDelay(0); - this.setLayout(new GridLayout(0, 1)); - - JSplitPane inOut = new JSplitPane(JSplitPane.VERTICAL_SPLIT); - - controllerOrig = new CstcMessageEditorController(); - controllerMod = new CstcMessageEditorController(); - - // create input panel - JPanel inputPanel = new LayoutPanel("Input"); - inputText = new BurpEditorWrapper(controllerOrig, true); - inputPanel.add(inputText.getComponent()); - - // create output panel - JPanel outputPanel = new LayoutPanel("Output"); - outputText = new BurpEditorWrapper(controllerMod, false); - outputPanel.add(outputText.getComponent()); - - JPanel searchTreePanel = new JPanel(); - searchTreePanel.setLayout(new BorderLayout()); - JTextField searchText = new JTextField(); - searchTreePanel.add(searchText, BorderLayout.PAGE_START); - - OperationsTree operationsTree = new OperationsTree(); - operationsTree.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - operationsTree.setRootVisible(false); - searchTreePanel.add(new JScrollPane(operationsTree)); - searchText.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void removeUpdate(DocumentEvent e) { - operationsTree.search(searchText.getText()); - } - - @Override - public void insertUpdate(DocumentEvent e) { - operationsTree.search(searchText.getText()); - } - - @Override - public void changedUpdate(DocumentEvent e) { - operationsTree.search(searchText.getText()); - } - }); - - // create operations panel - JPanel operationsPanel = new LayoutPanel("Operations"); - operationsPanel.add(searchTreePanel); - operationsPanel.setBackground(Color.WHITE); - inOut.setTopComponent(inputPanel); - inOut.setBottomComponent(outputPanel); - inOut.setResizeWeight(0.5); - - // create active operations (middle) panel - LayoutPanel activeOperationsPanel = new LayoutPanel("Recipe"); - - // add action items - JButton filters = new JButton("Filter"); - this.requestFilterDialog = new RequestFilterDialog(); - activeOperationsPanel.addActionComponent(filters); - filters.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - int result = JOptionPane.showConfirmDialog(null, requestFilterDialog, "Request Filter", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); - if (result == JOptionPane.OK_OPTION) { - filterMask = requestFilterDialog.getFilterMask(); - } - } - }); - - JButton bakeButton = new JButton("Bake"); - activeOperationsPanel.addActionComponent(bakeButton); - bakeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - bake(false); - } - }); - - JButton saveButton = new JButton("Save"); - activeOperationsPanel.addActionComponent(saveButton); - saveButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - try { - JFileChooser fc = new JFileChooser(); - int returnVal = fc.showSaveDialog(RecipePanel.this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); - save(file); - } - } catch (IOException e) { - JOptionPane.showMessageDialog(null, "The file could not be saved."); - } - } - }); - - JButton loadButton = new JButton("Load"); - activeOperationsPanel.addActionComponent(loadButton); - loadButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - try { - JFileChooser fc = new JFileChooser(); - int returnVal = fc.showOpenDialog(RecipePanel.this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); - String jsonState = new String(Files.readAllBytes(Paths.get(file.getPath()))); - restoreState(jsonState); - } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException e) { - JOptionPane.showMessageDialog(null, "The provided file could not be loaded."); - } - } - }); - - JCheckBox bakeCheckBox = new JCheckBox("Auto bake"); - bakeCheckBox.setSelected(this.autoBake); - activeOperationsPanel.addActionComponent(bakeCheckBox); - bakeCheckBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ae) { - autoBake = bakeCheckBox.isSelected(); - bake(false); - } - }); - - JButton variablesButton = new JButton("Variables"); - activeOperationsPanel.addActionComponent(variablesButton); - variablesButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - VariablesWindow vw = VariablesWindow.getInstance(); - vw.refresh(VariableStore.getInstance().getVariables()); - vw.setVisible(true); - } - }); - - operationLines = new JPanel(); - operationLines.setLayout(new GridBagLayout()); - - // add dummy panel - GridBagConstraints gbc = new GridBagConstraints(); - gbc.gridheight = GridBagConstraints.REMAINDER; - gbc.weightx = 1; - gbc.weighty = 1; - JPanel dummyPanel = new JPanel(); - dummyPanel.setBackground(Color.YELLOW); - - GridBagConstraints co = new GridBagConstraints(); - co.gridheight = GridBagConstraints.REMAINDER; - co.weighty = 1; - co.fill = GridBagConstraints.VERTICAL; - - operationLines.add(dummyPanel, gbc); // this is the magic!11!! - - for (int i = operationSteps; i > 0; i--) { - RecipeStepPanel opPanel = new RecipeStepPanel(String.valueOf(i), this); - operationLines.add(opPanel, co, 0); - - JPanel panel = opPanel.getOperationsPanel(); - MoveOperationMouseAdapter moma = new MoveOperationMouseAdapter(opPanel, operationLines); - panel.addMouseListener(moma ); - panel.addMouseMotionListener(moma ); - } - - JScrollPane activeOperationsScrollPane = new JScrollPane(operationLines, JScrollPane.VERTICAL_SCROLLBAR_NEVER, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - activeOperationsPanel.add(activeOperationsScrollPane); - - JSplitPane opsInOut = new JSplitPane(); - opsInOut.setResizeWeight(0.5); - - opsInOut.setLeftComponent(activeOperationsPanel); - opsInOut.setRightComponent(inOut); - - JSplitPane opSplit = new JSplitPane(); - opSplit.setRightComponent(opsInOut); - opSplit.setLeftComponent(operationsPanel); - opSplit.setResizeWeight(0.1); - - this.add(opSplit); - - AddOperationMouseAdapter dma = new AddOperationMouseAdapter(operationsTree, operationLines); - operationsTree.addMouseListener(dma); - operationsTree.addMouseMotionListener(dma); - - loadRecipeFromBurp(); - startAutoBakeTimer(); - } - - private void loadRecipeFromBurp() { - logger.log("[" + this.recipeName + "] Autoloading..."); - boolean inBurp = BurpUtils.inBurp(); - //Check if we run inside a burp - if (inBurp) { - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - String jsonState = callbacks.loadExtensionSetting("cstc_" + this.recipeName); - if (jsonState != null && jsonState != "") { - try { - logger.log("[" + this.recipeName + "] Restoring state."); - //We remove the setting and set it again to be safe in an error case - callbacks.saveExtensionSetting("cstc_" + this.recipeName, ""); - restoreState(jsonState); - callbacks.saveExtensionSetting("cstc_" + this.recipeName, jsonState); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException e) { - Logger.getInstance().err("There was an error restoring the state of RecipePanel " + this.recipeName); - } - } - } - else { - logger.log("[" + this.recipeName + "] Autoloading aborted. Not running inside Burp."); - } - } - - private void autoSaveToBurp() { - boolean inBurp = BurpUtils.inBurp(); - //Check if we run inside a burp - if (inBurp) { - try { - String jsonState = getStateAsJSON(); - BurpUtils.getInstance().getCallbacks().saveExtensionSetting("cstc_" + this.recipeName, jsonState); - } catch (IOException e) { - Logger.getInstance().err("There was an error persisting the current state of the recipe panel."); - } - } - } - - public void setInput(IHttpRequestResponse requestResponse) { - if( isRequest ) - this.inputText.setMessage(requestResponse.getRequest(), true); - else { - byte[] responseBytes = requestResponse.getResponse(); - if( responseBytes == null ) - responseBytes = "Your request has no server response yet :(".getBytes(); - this.inputText.setMessage(responseBytes, false); - } - - this.controllerOrig.setHttpRequestResponse(requestResponse); - this.controllerMod.setHttpRequestResponse(requestResponse); - - this.bake(false); - } - - private void restoreState(String jsonState) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { - // TODO do we want to remove all existing operations before loading here? - ObjectMapper mapper = new ObjectMapper(); - JsonNode stepNodes = mapper.readTree(jsonState); - if (!stepNodes.isArray()) { - throw new IOException("wrong data format"); - } - - for (int step = 0; step < stepNodes.size(); step++) { - JsonNode operationNodes = stepNodes.get(step); - if (!operationNodes.isArray()) { - throw new IOException("wrong data format"); - } - - for (int i = 0; i < operationNodes.size(); i++) { - JsonNode operationNode = operationNodes.get(i); - String operation = operationNode.get("operation").asText(); - Map parameters = mapper.convertValue(operationNode.get("parameters"), Map.class); - Class cls = (Class) Class.forName(operation); - // check if it is an operation - Operation op = cls.newInstance(); - op.load(parameters); - RecipeStepPanel panel = (RecipeStepPanel) this.operationLines.getComponent(step); - panel.addComponent(op, i); - } - } - } - - private String getStateAsJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - ArrayNode stepsNode = mapper.createArrayNode(); - - for (int step = 0; step < this.operationSteps; step++) { - ArrayNode operationsNode = mapper.createArrayNode(); - - RecipeStepPanel stepPanel = (RecipeStepPanel) this.operationLines.getComponent(step); - List operations = stepPanel.getOperations(); - for (Operation op : operations) { - ObjectNode operationNode = mapper.createObjectNode(); - operationNode.put("operation", op.getClass().getName()); - operationsNode.add(operationNode); - operationNode.putPOJO("parameters", op.getState()); - } - stepsNode.add(operationsNode); - } - return mapper.writeValueAsString(stepsNode); - } - - private void save(File file) throws IOException { - FileWriter fw = new FileWriter(file); - fw.write(getStateAsJSON()); - fw.close(); - } - - private byte[] doBake(byte[] input) { - if (input == null || input.length == 0) { - return new byte[0]; - } - byte[] result = input.clone(); - byte[] intermediateResult = input; - boolean outputChanged; - VariableStore store = VariableStore.getInstance(); - out: for (int j = 0; j < this.operationLines.getComponentCount(); j++) { - - Component operationLine = this.operationLines.getComponent(j); - if (!(operationLine instanceof RecipeStepPanel)) { - continue; - } - - String stepVariableName = String.format("%s_step%d", this.recipeName, (j + 1)); - store.removeVariable(stepVariableName); - - intermediateResult = input; - outputChanged = false; - - List operationList = ((RecipeStepPanel)operationLine).getOperations(); - for(int i = 0; i < operationList.size(); i++) { - - Operation op = operationList.get(i); - if (op.isDisabled()) { - continue; - } - - intermediateResult = op.performOperation(intermediateResult); - outputChanged = true; - - if (op.isBreakpoint()) { - result = intermediateResult; - store.setVariable(stepVariableName, intermediateResult); - break out; - } - - i += op.getOperationSkip(); - j += op.getLaneSkip(); - } - - if (outputChanged) { - result = intermediateResult; - store.setVariable(stepVariableName, intermediateResult); - } - } - - if (BurpUtils.inBurp()) { - IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); - - IRequestInfo info; - try { - info = helpers.analyzeRequest(result); - } catch( IllegalArgumentException e ) { - // In this case there is no valid HTTP request and no Content-Length update is requried. - return result; - } - - List headers = info.getHeaders(); - int offset = info.getBodyOffset(); - - if( result.length == offset ) { - // In this case there is no body and we do not need to update the content length header. - return result; - } - - for(String header : headers) { - if(header.startsWith("Content-Length:")) { - // To update the content-length header, we just add a dummy parameter and remove it right away. - // Burps extension helpers will care about updating the length without any string transformations. - IParameter dummy = helpers.buildParameter("dummy", "dummy", IParameter.PARAM_BODY); - result = helpers.addParameter(result, dummy); - result = helpers.removeParameter(result, dummy); - break; - } - } - return result; - - } else { - return result; - } - } - - private void bake(boolean spamProtection) { - if (this.bakeTimer != null) { - this.bakeTimer.cancel(); - } - this.bakeTimer = new Timer(this.recipeName); - TimerTask tt = new TimerTask() { - @Override - public void run() { - byte[] result = doBake(inputText.getMessage()); - HashMap variables = VariableStore.getInstance().getVariables(); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if( isRequest) { - outputText.setMessage(result, true); - controllerMod.setRequest(result); - } else { - outputText.setMessage(result, false); - controllerMod.setResponse(result); - } - VariablesWindow vw = VariablesWindow.getInstance(); - if (vw.isVisible()) { - vw.refresh(variables); - } - PopupVariableMenu.refresh(variables); - } - }); - autoSaveToBurp(); - } - }; - int threshold = spamProtection ? this.bakeThreshold : 0; - this.bakeTimer.schedule(tt, threshold); - } - - public byte[] bake(byte[] input) { - VariableStore store = VariableStore.getInstance(); - try { - store.lock(); - return this.doBake(input); - } finally { - store.unlock(); - } - } - - private void startAutoBakeTimer() { - TimerTask repeatedTask = new TimerTask() { - public void run() { - if (inputText.isMessageModified()) { - logger.log("autobaking"); - autoBake(); - } - } - }; - Timer timer = new Timer("Timer"); - long delay = 1000L; - long period = 1000L; - timer.scheduleAtFixedRate(repeatedTask, delay, period); - } - - private void autoBake() { - if (!this.autoBake) { - return; - } - VariableStore store = VariableStore.getInstance(); - try { - store.lock(); - this.bake(true); - } finally { - store.unlock(); - } - } - - @Override - public void stateChanged(ChangeEvent e) { - this.autoBake(); - } - - public boolean shouldProcess(int tool) { - return (this.filterMask & tool) != 0; - } -} diff --git a/src/de/usd/cstchef/view/RecipeStepPanel.java b/src/de/usd/cstchef/view/RecipeStepPanel.java deleted file mode 100644 index 1b714f5..0000000 --- a/src/de/usd/cstchef/view/RecipeStepPanel.java +++ /dev/null @@ -1,114 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextField; -import javax.swing.border.Border; -import javax.swing.border.CompoundBorder; -import javax.swing.border.MatteBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import de.usd.cstchef.operations.*; - -public class RecipeStepPanel extends JPanel { - - private JPanel operationsLine; - private GridBagConstraints addContraints; - private ChangeListener changeListener; - - public RecipeStepPanel(String title, ChangeListener changelistener) { - this.changeListener = changelistener; - this.setLayout(new BorderLayout()); - this.setPreferredSize(new Dimension(300, 0)); - - // header - Box headerBox = Box.createHorizontalBox(); - // add borders - Border margin = BorderFactory.createEmptyBorder(10, 10, 10, 10); - MatteBorder lineBorder = new MatteBorder(0, 0, 2, 0, Color.DARK_GRAY); - CompoundBorder border = new CompoundBorder(lineBorder, margin); - headerBox.setBorder(border); - - JTextField contentTextField = new JTextField(); - contentTextField.setBorder(null); - contentTextField.setBackground(new Color(0, 0, 0, 0)); - contentTextField.setText(title); - headerBox.add(contentTextField); - - this.add(headerBox, BorderLayout.NORTH); - - // body - operationsLine = new JPanel(new GridBagLayout()); - - GridBagConstraints gbc = new GridBagConstraints(); - gbc.gridwidth = GridBagConstraints.REMAINDER; - gbc.gridheight = GridBagConstraints.REMAINDER; - gbc.weightx = 1; - gbc.weighty = 1; - gbc.fill = GridBagConstraints.BOTH; - - JPanel dummyPanel = new JPanel(); - operationsLine.add(dummyPanel, gbc); - - this.addContraints = new GridBagConstraints(); - this.addContraints.gridwidth = GridBagConstraints.REMAINDER; - this.addContraints.weightx = 1; - this.addContraints.fill = GridBagConstraints.HORIZONTAL; - - JScrollPane scrollPane = new JScrollPane(operationsLine); - scrollPane.setBorder(new MatteBorder(0, 2, 0, 0, Color.DARK_GRAY)); - scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - scrollPane.getVerticalScrollBar().setUnitIncrement(16); - - this.add(scrollPane, BorderLayout.CENTER); - } - - public void addComponent(Component comp, int index) { - operationsLine.add(comp, addContraints, index); - operationsLine.revalidate(); - operationsLine.repaint(); - if (comp instanceof Operation) { - ((Operation) comp).setChangeListener(this.changeListener); - this.changeListener.stateChanged(new ChangeEvent(this)); - } - } - - public void removeComponent(Component comp) { - operationsLine.remove(comp); - operationsLine.revalidate(); - operationsLine.repaint(); - this.changeListener.stateChanged(new ChangeEvent(this)); - } - - public JPanel getOperationsPanel() { - return this.operationsLine; - } - - public List getOperations() { - List result = new ArrayList<>(); - - for (int i = 0; i < this.operationsLine.getComponentCount(); i++) { - Component op = this.operationsLine.getComponent(i); - if (!(op instanceof Operation)) { - continue; - } - - result.add((Operation) op); - } - return result; - } - -} diff --git a/src/de/usd/cstchef/view/RequestFilterDialog.java b/src/de/usd/cstchef/view/RequestFilterDialog.java deleted file mode 100644 index 176791a..0000000 --- a/src/de/usd/cstchef/view/RequestFilterDialog.java +++ /dev/null @@ -1,81 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.LinkedHashMap; -import java.util.Map; -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; - -import burp.IBurpExtenderCallbacks; - -public class RequestFilterDialog extends JPanel { - private LinkedHashMap filterSettings; - - public RequestFilterDialog() { - this.filterSettings = new LinkedHashMap<>(); - this.filterSettings.put(new Filter("Proxy", IBurpExtenderCallbacks.TOOL_PROXY), false); - this.filterSettings.put(new Filter("Repeater", IBurpExtenderCallbacks.TOOL_REPEATER), false); - this.filterSettings.put(new Filter("Spider", IBurpExtenderCallbacks.TOOL_SPIDER), false); - this.filterSettings.put(new Filter("Scanner", IBurpExtenderCallbacks.TOOL_SCANNER), false); - this.filterSettings.put(new Filter("Intruder", IBurpExtenderCallbacks.TOOL_INTRUDER), false); - - this.setLayout(new GridLayout(0, 2)); - - for (Map.Entry entry : this.filterSettings.entrySet()) { - Filter filter = entry.getKey(); - boolean selected = entry.getValue(); - this.add(new JLabel(filter.getName() + ": ")); - - JCheckBox box = new JCheckBox(); - box.setSelected(selected); - box.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - filterSettings.put(filter, box.isSelected()); - } - }); - this.add(box); - } - } - - public int getFilterMask() { - int filterMask = 0; - for (Map.Entry entry : this.filterSettings.entrySet()) { - Filter filter = entry.getKey(); - boolean selected = entry.getValue(); - if (selected) { - filterMask |= filter.getValue(); - } - } - return filterMask; - } - - class Filter { - private String name; - private int value; - - public Filter(String name, int value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } - } -} diff --git a/src/de/usd/cstchef/view/VariablesWindow.java b/src/de/usd/cstchef/view/VariablesWindow.java deleted file mode 100644 index 01a5756..0000000 --- a/src/de/usd/cstchef/view/VariablesWindow.java +++ /dev/null @@ -1,103 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridBagLayout; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.util.HashMap; -import java.util.SortedMap; -import java.util.TreeMap; - -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.JTextArea; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumn; - -public class VariablesWindow extends JFrame { - - private static VariablesWindow instance; - - public static VariablesWindow getInstance() { - if (VariablesWindow.instance == null) { - VariablesWindow.instance = new VariablesWindow(); - } - return VariablesWindow.instance; - } - - private JLabel emptyLbl; - private JTable table; - - private VariablesWindow() { - super("Variables"); - this.setSize(new Dimension(600, 480)); - - DefaultTableModel model = new DefaultTableModel(new String[] { "Variable Name", "Content" }, 0); - this.table = new JTable(model) { - public boolean isCellEditable(int row, int column) { - return false; - }; - }; - - this.addComponentListener(new ComponentAdapter() { - public void componentResized(ComponentEvent e) { - if (table.getModel().getRowCount() == 0) { - setColumnWidth(new Dimension()); - } - } - }); - - this.table.setLayout(new GridBagLayout()); - this.table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); - this.table.getColumnModel().getColumn(0).setPreferredWidth(200); - this.table.getColumnModel().getColumn(1).setCellRenderer(new WordWrapCellRenderer()); - this.table.getTableHeader().setReorderingAllowed(false); - this.table.getTableHeader().setResizingAllowed(false); - this.table.setFillsViewportHeight(true); - ((DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.LEFT); - - this.emptyLbl = new JLabel("no variables defined"); - this.table.add(this.emptyLbl); - - JScrollPane scrollPane = new JScrollPane(this.table); - this.add(scrollPane); - } - - public void refresh(HashMap variables) { - DefaultTableModel model = (DefaultTableModel) this.table.getModel(); - model.setRowCount(0); - this.emptyLbl.setVisible(variables.isEmpty()); - SortedMap sortedMap = new TreeMap(variables); - - for (String key : sortedMap.keySet()) { - model.addRow(new String[] { key, new String(sortedMap.get(key)) }); - } - } - - private void setColumnWidth(Dimension preferredSize) { - TableColumn contentColumn = this.table.getColumnModel().getColumn(1); - int parentWidth = this.table.getParent().getWidth(); - int width = Integer.max(preferredSize.width + WordWrapCellRenderer.MARGIN, parentWidth - this.table.getColumnModel().getColumn(0).getWidth()); - contentColumn.setPreferredWidth(width); - } - - class WordWrapCellRenderer extends JTextArea implements TableCellRenderer { - private static final int MARGIN = 20; - - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - Dimension preferredSize = getPreferredSize(); - setText(value.toString()); - setSize(preferredSize.width, getPreferredSize().height); - if (table.getRowHeight(row) != getPreferredSize().height) { - table.setRowHeight(row, getPreferredSize().height); - } - setColumnWidth(preferredSize); - return this; - } - } -} diff --git a/src/de/usd/cstchef/view/View.java b/src/de/usd/cstchef/view/View.java deleted file mode 100644 index 22faa09..0000000 --- a/src/de/usd/cstchef/view/View.java +++ /dev/null @@ -1,57 +0,0 @@ -package de.usd.cstchef.view; - -import java.awt.BorderLayout; -import java.security.Security; - -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JTabbedPane; -import javax.swing.WindowConstants; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -public class View extends JPanel { - - private RecipePanel incomingRecipePanel; - private RecipePanel outgoingRecipePanel; - private RecipePanel formatRecipePanel; - - public View() { - Security.addProvider(new BouncyCastleProvider()); - - this.setLayout(new BorderLayout()); - JTabbedPane tabbedPane = new JTabbedPane(); - - incomingRecipePanel = new RecipePanel("Incomming", false); - outgoingRecipePanel = new RecipePanel("Outgoing", true); - formatRecipePanel = new RecipePanel("Formatting", true); - - tabbedPane.addTab("Outgoing Requests", null, outgoingRecipePanel, "Outgoing requests from the browser, the repeater or another tool."); - tabbedPane.addTab("Incoming Responses", null, incomingRecipePanel, "Responses from the server."); - tabbedPane.addTab("Formating", null, formatRecipePanel, "Formating for messages."); - this.add(tabbedPane); - } - - public RecipePanel getIncomingRecipePanel() { - return this.incomingRecipePanel; - } - - public RecipePanel getOutgoingRecipePanel() { - return this.outgoingRecipePanel; - } - - public RecipePanel getFormatRecipePanel() { - return this.formatRecipePanel; - } - - public static void main(String[] args) { - JFrame frame = new JFrame("CSTC"); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - View view = new View(); - - frame.setContentPane(view); - frame.setSize(800, 600); - frame.setVisible(true); -// frame.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH); - } -} diff --git a/src/de/usd/cstchef/view/ui/FormatTextField.java b/src/de/usd/cstchef/view/ui/FormatTextField.java deleted file mode 100644 index 53e0b39..0000000 --- a/src/de/usd/cstchef/view/ui/FormatTextField.java +++ /dev/null @@ -1,90 +0,0 @@ -package de.usd.cstchef.view.ui; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.UnsupportedEncodingException; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.Box; -import javax.swing.JComboBox; -import javax.swing.JPanel; -import javax.swing.event.DocumentListener; -import org.bouncycastle.util.encoders.Hex; - -public class FormatTextField extends JPanel implements ActionListener { - - public VariableTextField txtField; - private JComboBox formatBox; - private DocumentListener docListener; - - public FormatTextField() { - this.setLayout(new BorderLayout()); - this.setBackground(new Color(0, 0, 0, 0)); - this.txtField = new VariableTextField(); - this.formatBox = new JComboBox<>(new String[] {"Raw", "UTF-8", "Hex", "Latin1", "Base64"}); - this.formatBox.addActionListener(this); - - Box box = Box.createHorizontalBox(); - box.add(formatBox); - box.add(Box.createHorizontalStrut(10)); - box.add(txtField); - - this.add(box); - } - - public Map getValues() { - Map values = new HashMap<>(); - values.put("text", this.txtField.getText()); - values.put("encoding", this.formatBox.getSelectedItem().toString()); - return values; - } - - public void setValues(Map values) { - String text = values.get("text"); - this.txtField.setText(text); - Object encoding = values.get("encoding"); - this.formatBox.setSelectedItem(encoding); - } - - public byte[] getText() throws UnsupportedEncodingException { - - byte[] raw = this.txtField.getBytes(); - byte[] result = null; - - switch ((String) this.formatBox.getSelectedItem()) { - case "Raw": - result = raw; - break; - case "Hex": - result = Hex.decode(raw); - break; - case "Base64": - result = Base64.getDecoder().decode(raw); - break; - case "Latin1": - result = this.txtField.getText().getBytes("ISO-8859-1"); - break; - case "UTF-8": - result = this.txtField.getText().getBytes("UTF-8"); - break; - } - return result; - } - - public void addDocumentListener(DocumentListener listener) { - this.docListener = listener; - this.txtField.getDocument().addDocumentListener(listener); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (this.docListener != null) { - this.docListener.changedUpdate(null); - } - } - -} diff --git a/src/de/usd/cstchef/view/ui/VariableTextArea.java b/src/de/usd/cstchef/view/ui/VariableTextArea.java deleted file mode 100644 index 0b8b1c3..0000000 --- a/src/de/usd/cstchef/view/ui/VariableTextArea.java +++ /dev/null @@ -1,44 +0,0 @@ -package de.usd.cstchef.view.ui; - -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.event.DocumentListener; - -import de.usd.cstchef.Utils; -import de.usd.cstchef.view.PopupVariableMenu; - - -public class VariableTextArea extends JScrollPane { - - private JTextArea txtArea; - - public VariableTextArea() { - this.txtArea = new JTextArea(); - this.setViewportView(this.txtArea); - this.txtArea.setRows(5); - this.txtArea.setComponentPopupMenu(new PopupVariableMenu(this.txtArea)); - } - - public String getText() { - String text = this.txtArea.getText(); - return Utils.replaceVariables(text); - } - - public byte[] getBytes() { - byte[] bytes = this.txtArea.getText().getBytes(); - return Utils.replaceVariablesByte(bytes); - } - - public void setText(String text) { - this.txtArea.setText(text); - } - - public String getRawText() { - return this.txtArea.getText(); - } - - public void addDocumentListener(DocumentListener notifyChangeListener) { - this.txtArea.getDocument().addDocumentListener(notifyChangeListener); - } - -} diff --git a/src/de/usd/cstchef/view/ui/VariableTextField.java b/src/de/usd/cstchef/view/ui/VariableTextField.java deleted file mode 100644 index c9f2caf..0000000 --- a/src/de/usd/cstchef/view/ui/VariableTextField.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.usd.cstchef.view.ui; - -import javax.swing.JTextField; - -import de.usd.cstchef.Utils; -import de.usd.cstchef.view.PopupVariableMenu; - -public class VariableTextField extends JTextField { - - public VariableTextField() { - super(); - this.setComponentPopupMenu(new PopupVariableMenu(this)); - } - - @Override - public String getText() { - String text = super.getText(); - return Utils.replaceVariables(text); - } - - public byte[] getBytes() { - byte[] bytes = super.getText().getBytes(); - return Utils.replaceVariablesByte(bytes); - } - - public String getRawText() { - return super.getText(); - } - -} diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java new file mode 100644 index 0000000..8262661 --- /dev/null +++ b/src/main/java/burp/BurpExtender.java @@ -0,0 +1,114 @@ +package burp; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JMenuItem; + +import de.usd.cstchef.view.FormatTab; +import de.usd.cstchef.view.RecipePanel; +import de.usd.cstchef.view.View; + +public class BurpExtender implements IBurpExtender, ITab, IMessageEditorTabFactory, IHttpListener, IContextMenuFactory { + + private final String extensionName = "CSTC"; + private IBurpExtenderCallbacks callbacks; + private View view; + + @Override + public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) { + this.callbacks = callbacks; + Logger.getInstance().init(callbacks.getStdout(), callbacks.getStderr()); + BurpUtils.getInstance().init(callbacks); + + callbacks.setExtensionName(this.extensionName); + callbacks.addSuiteTab(this); + callbacks.registerHttpListener(this); + callbacks.registerContextMenuFactory(this); + callbacks.registerMessageEditorTabFactory(this); + } + + + @Override + public String getTabCaption() { + return this.extensionName; + } + + @Override + public Component getUiComponent() { + this.view = new View(); + return this.view; + } + + @Override + public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) { + if (messageIsRequest && view.getOutgoingRecipePanel().shouldProcess(toolFlag)) { + byte[] request = messageInfo.getRequest(); + byte[] modifiedRequest = view.getOutgoingRecipePanel().bake(request); + Logger.getInstance().log("modified request: \n" + new String(modifiedRequest)); + messageInfo.setRequest(modifiedRequest); + } else if (view.getIncomingRecipePanel().shouldProcess(toolFlag)) { + byte[] response = messageInfo.getResponse(); + byte[] modifiedResponse = view.getIncomingRecipePanel().bake(response); + messageInfo.setResponse(modifiedResponse); + Logger.getInstance().log("modified response: \n" + new String(modifiedResponse)); + } + } + + @Override + public List createMenuItems(IContextMenuInvocation invoc) { + + List menuItems = new ArrayList<>(); + JMenuItem incomingMenu = new JMenuItem("Send to CSTC (Incoming)"); + JMenuItem outgoingMenu = new JMenuItem("Send to CSTC (Outgoing)"); + JMenuItem incomingFormatMenu = new JMenuItem("Send to CSTC (Formating)"); + + menuItems.add(incomingMenu); + menuItems.add(outgoingMenu); + menuItems.add(incomingFormatMenu); + + incomingMenu.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + IHttpRequestResponse[] msgs = invoc.getSelectedMessages(); + if (msgs != null && msgs.length > 0) { + view.getIncomingRecipePanel().setInput(msgs[0]); + } + } + }); + + outgoingMenu.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + IHttpRequestResponse[] msgs = invoc.getSelectedMessages(); + if (msgs != null && msgs.length > 0) { + view.getOutgoingRecipePanel().setInput(msgs[0]); + } + + } + }); + + incomingFormatMenu.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + IHttpRequestResponse[] msgs = invoc.getSelectedMessages(); + if (msgs != null && msgs.length > 0) { + view.getFormatRecipePanel().setInput(msgs[0]); + } + } + }); + + return menuItems; + } + + @Override + public IMessageEditorTab createNewInstance(IMessageEditorController controller, boolean editable) { + RecipePanel requestFormatPanel = this.view.getOutgoingRecipePanel(); + // TODO do we need the format panel or do we want to use the incoming recipe? + RecipePanel responseFormatPanel = this.view.getFormatRecipePanel(); + return new FormatTab(requestFormatPanel, responseFormatPanel, editable); + } +} diff --git a/src/main/java/burp/BurpUtils.java b/src/main/java/burp/BurpUtils.java new file mode 100644 index 0000000..251d052 --- /dev/null +++ b/src/main/java/burp/BurpUtils.java @@ -0,0 +1,38 @@ +package burp; + +public class BurpUtils { + + private static BurpUtils instance; + private IBurpExtenderCallbacks callbacks; + + public static BurpUtils getInstance() { + if (BurpUtils.instance == null) { + BurpUtils.instance = new BurpUtils(); + } + return BurpUtils.instance; + } + + private BurpUtils() { + } + + public void init(IBurpExtenderCallbacks callbacks) { + this.callbacks = callbacks; + } + + public IBurpExtenderCallbacks getCallbacks() throws IllegalAccessError { + if (this.callbacks == null) { + throw new IllegalAccessError("Only works within burpsuite"); + } + return callbacks; + } + + public static boolean inBurp() { + try { + BurpUtils.getInstance().getCallbacks(); + return true; + } catch (IllegalAccessError e) { + return false; + } + } + +} diff --git a/src/main/java/burp/CstcMessageEditorController.java b/src/main/java/burp/CstcMessageEditorController.java new file mode 100644 index 0000000..79aecd0 --- /dev/null +++ b/src/main/java/burp/CstcMessageEditorController.java @@ -0,0 +1,37 @@ +package burp; + +public class CstcMessageEditorController implements IMessageEditorController { + + private IHttpService httpService = null; + private byte[] request = null; + private byte[] response = null; + + public void setHttpRequestResponse(IHttpRequestResponse requestResponse) { + this.httpService = requestResponse.getHttpService(); + this.request = requestResponse.getRequest(); + this.response = requestResponse.getResponse(); + } + + public void setRequest(byte[] request) { + this.request = request; + } + + public void setResponse(byte[] response) { + this.request = response; + } + + @Override + public IHttpService getHttpService() { + return httpService; + } + + @Override + public byte[] getRequest() { + return request; + } + + @Override + public byte[] getResponse() { + return response; + } +} diff --git a/src/main/java/burp/Logger.java b/src/main/java/burp/Logger.java new file mode 100644 index 0000000..c3a73dd --- /dev/null +++ b/src/main/java/burp/Logger.java @@ -0,0 +1,44 @@ +package burp; + +import java.io.OutputStream; +import java.io.PrintWriter; + +public class Logger { + + private static Logger instance; + + private PrintWriter stdout; + private PrintWriter stderr; + + public static Logger getInstance() { + if (Logger.instance == null) { + Logger.instance = new Logger(); + } + return Logger.instance; + } + + private Logger() { + + } + + public void init(OutputStream stdOut, OutputStream stdErr) { + this.stdout = new PrintWriter(stdOut, true); + this.stderr = new PrintWriter(stdErr, true); + } + + public void log(String msg) { + if (this.stdout == null) { + System.out.println(msg); + } else { + this.stdout.println(msg); + } + } + + public void err(String msg) { + if (this.stderr == null) { + System.err.println(msg); + } else { + this.stderr.println(msg); + } + } +} diff --git a/src/main/java/de/usd/cstchef/Delimiter.java b/src/main/java/de/usd/cstchef/Delimiter.java new file mode 100644 index 0000000..f08ff52 --- /dev/null +++ b/src/main/java/de/usd/cstchef/Delimiter.java @@ -0,0 +1,46 @@ +package de.usd.cstchef; + +public enum Delimiter +{ + COMMA("Comma", ","), + SPACE("Space", " "), + LINE_FEED("Line feed", "\n"), + COLON("Colon", ":"), + CLRF("CLRF", "\r\n"), + SEMICOLON("Semicolon", ";"); + + private String name; + private String value; + + Delimiter(String name, String value) + { + this.name = name; + this.value = value; + } + + public String getValue() + { + return this.value; + } + + public static Delimiter getByName(String name) + { + for(Delimiter delim : Delimiter.values() ) + + if( delim.name.equals(name) ) + return delim; + + return null; + } + + public static String[] getNames() + { + Delimiter[] delims = Delimiter.values(); + String[] names = new String[delims.length]; + + for(int ctr = 0; ctr < delims.length; ctr++ ) + names[ctr] = delims[ctr].name; + + return names; + } +} \ No newline at end of file diff --git a/src/de/usd/cstchef/Utils.java b/src/main/java/de/usd/cstchef/Utils.java similarity index 67% rename from src/de/usd/cstchef/Utils.java rename to src/main/java/de/usd/cstchef/Utils.java index 506585f..0e7b4f8 100644 --- a/src/de/usd/cstchef/Utils.java +++ b/src/main/java/de/usd/cstchef/Utils.java @@ -101,123 +101,113 @@ import de.usd.cstchef.operations.string.Length; import de.usd.cstchef.operations.string.Prefix; import de.usd.cstchef.operations.string.Replace; +import de.usd.cstchef.operations.string.Reverse; import de.usd.cstchef.operations.string.SplitAndSelect; import de.usd.cstchef.operations.string.StaticString; import de.usd.cstchef.operations.string.Substring; import de.usd.cstchef.operations.string.Suffix; +import de.usd.cstchef.operations.string.Uppercase; +import de.usd.cstchef.operations.string.Lowercase; import de.usd.cstchef.operations.utils.GetVariable; import de.usd.cstchef.operations.utils.NoOperation; import de.usd.cstchef.operations.utils.RandomNumber; +import de.usd.cstchef.operations.utils.RandomUUID; import de.usd.cstchef.operations.utils.SetIfEmpty; import de.usd.cstchef.operations.utils.StoreVariable; import de.usd.cstchef.view.View; public class Utils { - // TODO find a better way to do this - - - public static HashMap delimiters = new HashMap() { - { - put("Comma", ","); - put("Space", " "); - put("Line feed", "\n"); - put("Colon", ":"); - put("CLRF", "\r\n"); - put("Semi-colon", ";"); - } - }; - - public static double parseNumber(String in) { - // TODO hex values?? - return Double.valueOf(in); - } - - public static String replaceVariables(String text) { - HashMap variables = VariableStore.getInstance().getVariables(); - for (Entry entry : variables.entrySet()) { - // TODO this is easy, but very bad, how to do this right? - text = text.replace("$" + entry.getKey(), new String(entry.getValue())); - } - - return text; - } - - public static byte[] replaceVariablesByte(byte[] bytes) { - HashMap variables = VariableStore.getInstance().getVariables(); + public static double parseNumber(String in) { + // TODO hex values?? + return Double.valueOf(in); + } + + public static String replaceVariables(String text) { + HashMap variables = VariableStore.getInstance().getVariables(); + for (Entry entry : variables.entrySet()) { + // TODO this is easy, but very bad, how to do this right? + text = text.replace("$" + entry.getKey(), new String(entry.getValue())); + } + + return text; + } + + public static byte[] replaceVariablesByte(byte[] bytes) { + HashMap variables = VariableStore.getInstance().getVariables(); IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = callbacks.getHelpers(); + IExtensionHelpers helpers = callbacks.getHelpers(); - byte[] currentKey; - for (Entry entry : variables.entrySet()) { + byte[] currentKey; + for (Entry entry : variables.entrySet()) { int offset = 0; - currentKey = ("$" + entry.getKey()).getBytes(); + currentKey = ("$" + entry.getKey()).getBytes(); while( offset >= 0 ) { offset = helpers.indexOf(bytes, currentKey, true, offset, bytes.length); if( offset >= 0 ) bytes = insertAtOffset(bytes, offset, offset + currentKey.length, entry.getValue()); } - } - return bytes; - } + } + return bytes; + } public static byte[] insertAtOffset(byte[] input, int start, int end, byte[] newValue) { - byte[] prefix = Arrays.copyOfRange(input, 0, start); - byte[] rest = Arrays.copyOfRange(input, end, input.length); - - byte[] output = new byte[prefix.length + newValue.length + rest.length]; - System.arraycopy(prefix, 0, output, 0, prefix.length); - System.arraycopy(newValue, 0, output, prefix.length, newValue.length); - System.arraycopy(rest, 0, output, prefix.length + newValue.length, rest.length); - - return output; - } - - public static Class[] getOperationsBurp() { - ZipInputStream zip = null; - List> operations = new ArrayList>(); - - try { - File f = new File(View.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - zip = new ZipInputStream(new FileInputStream(f.getAbsolutePath())); - for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) { - if (entry.isDirectory() || !entry.getName().endsWith(".class")) { - continue; - } - - String className = entry.getName().replace('/', '.'); - className = className.substring(0, className.length() - ".class".length()); - if (!className.contains("de.usd.operations")) { - continue; - } - - Class cls = Class.forName(className); - if (Operation.class.isAssignableFrom(cls)) { - Logger.getInstance().log(cls.toString()); - operations.add(cls); - } - } - } catch (URISyntaxException e) { - } catch (ClassNotFoundException e) { - } catch (FileNotFoundException e) { - } catch (IOException e) { - } finally { - try { - zip.close(); - } catch (IOException e) { - } - } - - return operations.toArray(new Class[operations.size()]); - } - - // TODO reflection does not work in Burp Suite - @SuppressWarnings("unchecked") - public static Class[] getOperationsDev() { - return new Class[] { + byte[] prefix = Arrays.copyOfRange(input, 0, start); + byte[] rest = Arrays.copyOfRange(input, end, input.length); + + byte[] output = new byte[prefix.length + newValue.length + rest.length]; + System.arraycopy(prefix, 0, output, 0, prefix.length); + System.arraycopy(newValue, 0, output, prefix.length, newValue.length); + System.arraycopy(rest, 0, output, prefix.length + newValue.length, rest.length); + + return output; + } + + public static Class[] getOperationsBurp() { + ZipInputStream zip = null; + List> operations = new ArrayList>(); + + try { + File f = new File(View.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + zip = new ZipInputStream(new FileInputStream(f.getAbsolutePath())); + for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) { + if (entry.isDirectory() || !entry.getName().endsWith(".class")) { + continue; + } + + String className = entry.getName().replace('/', '.'); + className = className.substring(0, className.length() - ".class".length()); + if (!className.contains("de.usd.operations")) { + continue; + } + + Class cls = Class.forName(className); + if (Operation.class.isAssignableFrom(cls)) { + Logger.getInstance().log(cls.toString()); + operations.add(cls); + } + } + } catch (URISyntaxException e) { + } catch (ClassNotFoundException e) { + } catch (FileNotFoundException e) { + } catch (IOException e) { + } finally { + try { + zip.close(); + } catch (IOException e) { + } + } + + return operations.toArray(new Class[operations.size()]); + } + + // TODO reflection does not work in Burp Suite + @SuppressWarnings("unchecked") + public static Class[] getOperationsDev() { + return new Class[] { Addition.class, AddKey.class, AesDecryption.class, AesEncryption.class, And.class, Blake.class, DateTime.class, Deflate.class, DesDecryption.class, DesEncryption.class, Divide.class, DivideList.class, DSTU7564.class, FromBase64.class, FromHex.class, @@ -231,19 +221,19 @@ public static Class[] getOperationsDev() { JsonExtractor.class, JsonSetter.class, Length.class, LineExtractor.class, LineSetter.class, MD2.class, MD4.class, MD5.class, Mean.class, Median.class, Multiply.class, MultiplyList.class, NoOperation.class, NumberCompare.class, Prefix.class, - RandomNumber.class, ReadFile.class, RegexExtractor.class, Replace.class, RIPEMD.class, - RsaDecryption.class, RsaEncryption.class, RsaSignature.class, RegexMatch.class, + RandomNumber.class, RandomUUID.class ,ReadFile.class, RegexExtractor.class, Reverse.class, Replace.class, + RIPEMD.class, RsaDecryption.class, RsaEncryption.class, RsaSignature.class, RegexMatch.class, SetIfEmpty.class, SHA1.class, SHA2.class, SHA3.class, Skein.class, SplitAndSelect.class, - StaticString.class, StoreVariable.class, Sub.class, Substring.class, Subtraction.class, + StaticString.class, StoreVariable.class, Sub.class, Substring.class, Uppercase.class, Lowercase.class, Subtraction.class, Suffix.class, Sum.class, StringContains.class, StringMatch.class, Tiger.class, ToBase64.class, ToHex.class, UnixTimestamp.class, UrlDecode.class, UrlEncode.class, Whirlpool.class, WriteFile.class, XmlFullSignature.class, XmlMultiSignature.class, Xor.class, SoapMultiSignature.class - }; - } + }; + } - public static Class[] getOperations() { - return BurpUtils.inBurp() ? Utils.getOperationsDev() : Utils.getOperationsDev(); - } + public static Class[] getOperations() { + return BurpUtils.inBurp() ? Utils.getOperationsDev() : Utils.getOperationsDev(); + } } diff --git a/src/main/java/de/usd/cstchef/VariableStore.java b/src/main/java/de/usd/cstchef/VariableStore.java new file mode 100644 index 0000000..a182599 --- /dev/null +++ b/src/main/java/de/usd/cstchef/VariableStore.java @@ -0,0 +1,56 @@ +package de.usd.cstchef; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +public class VariableStore { + + private static VariableStore instance; + + private HashMap variables = new HashMap<>(); + private ReentrantLock lock = new ReentrantLock(); + + public static VariableStore getInstance() { + if (VariableStore.instance == null) { + VariableStore.instance = new VariableStore(); + } + return VariableStore.instance; + } + + private VariableStore() { + } + + public void lock() { + this.lock.lock(); + } + + public void unlock() { + this.lock.unlock(); + } + + public synchronized byte[] getVariable(String name) { + return this.variables.get(name); + } + + public synchronized void setVariable(String key, byte[] value) { + this.variables.put(key, value); + } + + public synchronized void removeVariable(String key) { + this.variables.remove(key); + } + + public synchronized HashMap getVariables() { + HashMap variablesCopy = new HashMap<>(); + + for (Map.Entry entry : this.variables.entrySet()) { + byte[] orig = entry.getValue(); + byte[] newContent = new byte[orig.length]; + System.arraycopy(orig, 0, newContent, 0, orig.length); + variablesCopy.put(entry.getKey(), newContent); + } + return variablesCopy; + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/Operation.java b/src/main/java/de/usd/cstchef/operations/Operation.java new file mode 100644 index 0000000..3e38acd --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/Operation.java @@ -0,0 +1,496 @@ +package de.usd.cstchef.operations; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.EOFException; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JSpinner; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.MatteBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import burp.Logger; +import de.usd.cstchef.view.ui.FormatTextField; +import de.usd.cstchef.view.ui.VariableTextArea; +import de.usd.cstchef.view.ui.VariableTextField; + +public abstract class Operation extends JPanel { + + private static Color defaultBgColor = new Color(223, 240, 216); + private static Color defaultFontColor = new Color(70, 136, 71); + private static Color disabledBgColor = new Color(223, 223, 223); + private static Color disabledFontColor = new Color(153, 153, 153); + private static Color breakBgColor = new Color(242, 222, 222); + private static Color breakFontColor = new Color(185, 74, 72); + private static Color errorBgColor = new Color(255, 121, 128); + private static Color errorFontColor = new Color(185, 74, 72); + + private static ImageIcon breakIcon = new ImageIcon(Operation.class.getResource("/stop.png")); + private static ImageIcon breakIconActive = new ImageIcon(Operation.class.getResource("/stop_active.png")); + private static ImageIcon disableIcon = new ImageIcon(Operation.class.getResource("/disable.png")); + private static ImageIcon removeIcon = new ImageIcon(Operation.class.getResource("/remove.png")); + private static ImageIcon helpIcon = new ImageIcon(Operation.class.getResource("/help.png")); + + private NotifyChangeListener notifyChangeListener; + + private boolean breakpoint = false; + private boolean disabled = false; + private boolean error = false; + + private ChangeListener changeListener; + private JTextArea errorArea; + private Box contentBox; + private Map uiElements; + + private int operationSkip = 0; + private int laneSkip = 0; + + public Operation() { + super(); + this.uiElements = new HashMap<>(); + + this.setLayout(new BorderLayout()); + this.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + // set border + Border margin = BorderFactory.createEmptyBorder(10, 10, 10, 10); + MatteBorder lineBorder = new MatteBorder(0, 0, 1, 0, Color.BLACK); + CompoundBorder border = new CompoundBorder(lineBorder, margin); + this.setBorder(border); + + // add header + JPanel header = new JPanel(); + header.setBackground(new Color(0, 0, 0, 0)); // transparent + + BoxLayout layout = new BoxLayout(header, BoxLayout.X_AXIS); + header.setLayout(layout); + header.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); + OperationInfos opInfos = this.getClass().getAnnotation(OperationInfos.class); + + JLabel titleLbl = new JLabel(opInfos.name()); + Font f = titleLbl.getFont(); + titleLbl.setFont(f.deriveFont(f.getStyle() | Font.BOLD)); + + JButton disableBtn = createIconButton(Operation.disableIcon); + disableBtn.setToolTipText("Disable"); + JButton breakpointBtn = createIconButton(Operation.breakIcon); + breakpointBtn.setToolTipText("Breakpoint"); + JButton removeBtn = createIconButton(Operation.removeIcon); + removeBtn.setToolTipText("Remove"); + JButton helpBtn = createIconButton(Operation.helpIcon); + helpBtn.setToolTipText(opInfos.description()); + + disableBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + disabled = !isDisabled(); + refreshColors(); + validate(); + repaint(); + notifyChange(); + } + }); + + breakpointBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + breakpoint = !isBreakpoint(); + ImageIcon newIcon = isBreakpoint() ? Operation.breakIconActive : Operation.breakIcon; + breakpointBtn.setIcon(newIcon); + refreshColors(); + validate(); + repaint(); + notifyChange(); + } + }); + JPanel me = this; + removeBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Container parent = getParent(); + onRemove(); + parent.remove(me); + parent.validate(); + parent.repaint(); + notifyChange(); + } + }); + + header.add(titleLbl); + header.add(Box.createHorizontalStrut(6)); + header.add(helpBtn); + header.add(Box.createHorizontalGlue()); + header.add(disableBtn); + header.add(Box.createHorizontalStrut(3)); + header.add(breakpointBtn); + header.add(Box.createHorizontalStrut(3)); + header.add(removeBtn); + + this.add(header, BorderLayout.NORTH); + + errorArea = new JTextArea(); + errorArea.setEditable(false); + errorArea.setLineWrap(true); + errorArea.setWrapStyleWord(true); + errorArea.setBackground(new Color(0, 0, 0, 0)); + errorArea.setFont(f.deriveFont(f.getStyle() | Font.BOLD)); + errorArea.setFocusable(false); + errorArea.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + + this.add(errorArea, BorderLayout.SOUTH); + + contentBox = Box.createVerticalBox(); + this.add(contentBox, BorderLayout.CENTER); + + this.createUI(); + this.refreshColors(); + } + + public Map getState() { + Map properties = new HashMap<>(); + for (String key : this.uiElements.keySet()) { + if( key.startsWith("noupdate") ) + properties.put(key, null); + else + properties.put(key, getUiValues(this.uiElements.get(key))); + } + + return properties; + } + + private Object getUiValues(Component comp) { + Object result = null; + if (comp instanceof JPasswordField) { + result = ""; + } else if (comp instanceof VariableTextArea) { + result = ((VariableTextArea) comp).getRawText(); + } else if (comp instanceof VariableTextField) { + result = ((VariableTextField) comp).getRawText(); + } else if (comp instanceof JTextField) { + result = ((JTextField) comp).getText(); + } else if (comp instanceof JSpinner) { + result = ((JSpinner) comp).getValue(); + } else if (comp instanceof JComboBox) { + result = ((JComboBox) comp).getSelectedItem(); + if( result != null ) + result = result.toString(); + } else if (comp instanceof JCheckBox) { + result = ((JCheckBox) comp).isSelected(); + } else if (comp instanceof FormatTextField) { + result = ((FormatTextField) comp).getValues(); + } else if (comp instanceof JFileChooser) { + result = ((JFileChooser) comp).getName(); + } + + return result; + } + + public void load(Map parameters) { + for (String key : this.uiElements.keySet()) { + Object value = parameters.get(key); + this.setUiValue(this.uiElements.get(key), value); + } + } + + private void setUiValue(Component comp, Object value) { + if (comp == null || value == null) { + return; + } + + if (comp instanceof JTextField) { + ((JTextField) comp).setText((String) value); + } else if (comp instanceof JSpinner) { + ((JSpinner) comp).setValue(value); + } else if (comp instanceof JComboBox) { + ((JComboBox) comp).setSelectedItem(value); + } else if (comp instanceof VariableTextArea) { + ((VariableTextArea) comp).setText((String) value); + } else if (comp instanceof JCheckBox) { + ((JCheckBox) comp).setSelected((boolean) value); + } else if (comp instanceof FormatTextField) { + ((FormatTextField) comp).setValues((Map) value); + } else if (comp instanceof JFileChooser) { + ((JFileChooser) comp).setName((String)value); + } + } + + private JButton createIconButton(ImageIcon icon) { + JButton btn = new JButton(); + btn.setBorder(BorderFactory.createEmptyBorder()); + btn.setIcon(icon); + btn.setContentAreaFilled(false); + btn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + btn.setAlignmentX(Component.RIGHT_ALIGNMENT); + + return btn; + } + + private void refreshColors() { + Color bgColor; + Color fontColor; + if (this.isDisabled()) { + bgColor = Operation.disabledBgColor; + fontColor = Operation.disabledFontColor; + } else if (this.isError()) { + bgColor = Operation.errorBgColor; + fontColor = Operation.errorFontColor; + } else if (this.isBreakpoint()) { + bgColor = Operation.breakBgColor; + fontColor = Operation.breakFontColor; + } else { + bgColor = Operation.defaultBgColor; + fontColor = Operation.defaultFontColor; + } + + this.setBackground(bgColor); + this.changeFontColor(this, fontColor); + } + + private void changeFontColor(Container container, Color color) { + for (Component comp : container.getComponents()) { + if (comp instanceof JLabel || comp.equals(errorArea)) { + comp.setForeground(color); + } else if (comp instanceof Container) { + changeFontColor((Container) comp, color); + } + } + } + + protected void addUIElement(String caption, Component comp) { + this.addUIElement(caption, comp, true, null); + } + + protected void addUIElement(String caption, Component comp, boolean notifyChange) { + this.addUIElement(caption, comp, notifyChange, null); + } + + protected void addUIElement(String caption, Component comp, String identifier) { + this.addUIElement(caption, comp, true, identifier); + } + + protected void addUIElement(String caption, Component comp, boolean notifyChange, String identifier) { + comp.setCursor(Cursor.getDefaultCursor()); + + Box box = Box.createHorizontalBox(); + box.setAlignmentX(Component.LEFT_ALIGNMENT); + if (comp instanceof JCheckBox) { + comp.setBackground(new Color(0, 0, 0, 0)); + } + JLabel lbl = new JLabel(caption); + box.add(lbl); + box.add(Box.createHorizontalStrut(10)); + box.add(comp); + this.contentBox.add(box); + this.contentBox.add(Box.createVerticalStrut(10)); + if( identifier == null ) + identifier = caption; + this.uiElements.put(identifier, comp); + + if (notifyChange) { + if (notifyChangeListener == null) { + notifyChangeListener = new NotifyChangeListener(); + } + + if (comp instanceof JTextField) { + ((JTextField) comp).getDocument().addDocumentListener(notifyChangeListener); + } else if (comp instanceof JSpinner) { + ((JSpinner) comp).addChangeListener(notifyChangeListener); + } else if (comp instanceof JComboBox) { + ((JComboBox) comp).addActionListener(notifyChangeListener); + } else if (comp instanceof VariableTextArea) { + ((VariableTextArea) comp).addDocumentListener(notifyChangeListener); + } else if (comp instanceof JCheckBox) { + ((JCheckBox) comp).addActionListener(notifyChangeListener); + } else if (comp instanceof FormatTextField) { + ((FormatTextField) comp).addDocumentListener(notifyChangeListener); + } else { + Logger.getInstance().err("could not add a default change listener for " + comp.getClass()); + } + } + } + + @Override + public Dimension getPreferredSize() { + Dimension dim = super.getPreferredSize(); + int width = this.getParent().getWidth(); + dim.setSize(width, dim.height); + return dim; + } + + public byte[] performOperation(byte[] input) { + try { + byte[] result = this.perform(input); + this.setErrorMessage(null); + return result; + } catch (EOFException e) { + this.setErrorMessage(new EOFException("End of file")); + return new byte[0]; + } catch (Throwable e) { + this.setErrorMessage(e); + return new byte[0]; + } + } + + public void setErrorMessage(Throwable e) { + boolean error = e != null; + + String msg = error ? e.getMessage() : ""; + String text; + if (msg == null) { + text = e.getClass().getName(); + } else { + text = error ? (msg.isEmpty() ? e.toString() : msg) : ""; + } + + this.errorArea.setText(text); + + this.setError(error); + this.refreshColors(); + this.validate(); + this.repaint(); + } + + public void removeChangeListener() { + this.changeListener = null; + } + + public void setChangeListener(ChangeListener listener) { + this.changeListener = listener; + } + + protected void notifyChange() { + if (this.changeListener != null) { + this.changeListener.stateChanged(new ChangeEvent(this)); + } + } + + public boolean isBreakpoint() { + return breakpoint; + } + + public void setBreakpoint(boolean breakpoint) { + this.breakpoint = breakpoint; + } + + public boolean isDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + refreshColors(); + validate(); + repaint(); + notifyChange(); + } + + public boolean isError() { + return error; + } + + public void setError(boolean error) { + this.error = error; + } + + public void setOperationSkip(int count) { + if( count < 0 ) + count = 0; + this.operationSkip = count; + } + + public int getOperationSkip() { + return this.operationSkip; + } + + public void setLaneSkip(int count) { + if( count < 0 ) + count = 0; + this.laneSkip = count; + } + + public int getLaneSkip() { + return this.laneSkip; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface OperationInfos { + + public String name() + + default "Unnamed plugin!"; + + public String description() + + default "Change this description!"; + + public OperationCategory category() default OperationCategory.MISC; + } + + protected abstract byte[] perform(byte[] input) throws Exception; + + public void createUI() { + + } + + public void onRemove() { + + } + + private class NotifyChangeListener implements DocumentListener, ActionListener, ChangeListener { + + @Override + public void changedUpdate(DocumentEvent e) { + notifyChange(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + notifyChange(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + notifyChange(); + } + + @Override + public void actionPerformed(ActionEvent e) { + notifyChange(); + } + + @Override + public void stateChanged(ChangeEvent e) { + notifyChange(); + } + } +} diff --git a/src/main/java/de/usd/cstchef/operations/OperationCategory.java b/src/main/java/de/usd/cstchef/operations/OperationCategory.java new file mode 100644 index 0000000..01e8a3d --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/OperationCategory.java @@ -0,0 +1,32 @@ +package de.usd.cstchef.operations; + +public enum OperationCategory { + ARITHMETIC("Arithmetic"), + BYTEOPERATION("Byte Operations"), + COMPRESSION("Compression"), + CONDITIONALS("Conditionals"), + DATAFORMAT("Data format"), + DATES("Date / Time"), + ENCRYPTION("Encryption / Encoding"), + EXTRACTORS("Extractors"), + HASHING("Hashing"), + MISC("Misc"), + NETWORKING("Networking"), + SETTER("Setter"), + SIGNATURE("Signature"), + STRING("String"), + UTILS("Utils"); +// LANGUAGE("Language"), +// FLOWCONTROL("Flow control"); + + private final String text; + + OperationCategory(final String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } +} diff --git a/src/de/usd/cstchef/operations/arithmetic/Addition.java b/src/main/java/de/usd/cstchef/operations/arithmetic/Addition.java similarity index 59% rename from src/de/usd/cstchef/operations/arithmetic/Addition.java rename to src/main/java/de/usd/cstchef/operations/arithmetic/Addition.java index 4daacd0..61c3f2c 100644 --- a/src/de/usd/cstchef/operations/arithmetic/Addition.java +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/Addition.java @@ -4,10 +4,11 @@ import de.usd.cstchef.operations.OperationCategory; @OperationInfos(name = "Single - Add", category = OperationCategory.ARITHMETIC, description = "Add to the input the given number.") -public class Addition extends ArithmeticOperation { - - @Override - protected double calculate(double input_number, double static_number) { - return input_number + static_number; - } +public class Addition extends ArithmeticOperation +{ + @Override + protected double calculate(double input_number, double static_number) + { + return input_number + static_number; + } } diff --git a/src/main/java/de/usd/cstchef/operations/arithmetic/ArithmeticDelimiterOperation.java b/src/main/java/de/usd/cstchef/operations/arithmetic/ArithmeticDelimiterOperation.java new file mode 100644 index 0000000..9050058 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/ArithmeticDelimiterOperation.java @@ -0,0 +1,74 @@ +package de.usd.cstchef.operations.arithmetic; + +import javax.swing.JCheckBox; +import javax.swing.JComboBox; + +import de.usd.cstchef.Delimiter; +import de.usd.cstchef.Utils; +import de.usd.cstchef.operations.Operation; + +public abstract class ArithmeticDelimiterOperation extends Operation +{ + private JComboBox delimiterBox; + private JCheckBox floatCheckBox; + + protected Delimiter getDelimiter() throws IllegalArgumentException + { + String delimString = (String)this.delimiterBox.getSelectedItem(); + Delimiter delim = Delimiter.getByName(delimString); + + if( delim == null ) + throw new IllegalArgumentException("Invalid delimiter."); + + return delim; + } + + protected boolean isFloat() + { + return floatCheckBox.isSelected(); + } + + @Override + protected byte[] perform(byte[] input) throws Exception + { + String delimiter = getDelimiter().getValue(); + String[] lines = new String(input).split(delimiter); + + if (lines.length < 2) + return input; + + double[] numbers = new double[lines.length]; + double result = Utils.parseNumber(lines[0].trim()); + + for(int i = 1; i < lines.length; i++) + { + numbers[i] = Utils.parseNumber(lines[i].trim()); + result = this.calculate(result, numbers[i]); + } + + result = onFinish(result, numbers); + + if( !isFloat() ) + return String.valueOf(Math.round(result)).getBytes(); + + return String.valueOf(result).getBytes(); + } + + protected double onFinish(double result, double[] lines) + { + return result; + } + + protected abstract double calculate(double a, double b); + + @Override + public void createUI() + { + this.delimiterBox = new JComboBox(Delimiter.getNames()); + this.addUIElement("Delimiter", this.delimiterBox); + + this.floatCheckBox = new JCheckBox(); + this.addUIElement("Point Number", this.floatCheckBox); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/arithmetic/ArithmeticOperation.java b/src/main/java/de/usd/cstchef/operations/arithmetic/ArithmeticOperation.java new file mode 100644 index 0000000..c17bf06 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/ArithmeticOperation.java @@ -0,0 +1,61 @@ +package de.usd.cstchef.operations.arithmetic; + +import javax.swing.JCheckBox; +import javax.swing.JTextField; + +import de.usd.cstchef.operations.Operation; + +public abstract class ArithmeticOperation extends Operation +{ + private JTextField numberInput; + private JCheckBox floatCheckBox; + + protected double getNumber() + { + return Double.valueOf(numberInput.getText()); + } + + protected boolean isFloat() + { + return floatCheckBox.isSelected(); + } + + @Override + protected byte[] perform(byte[] input) throws Exception + { + try + { + String i = new String(input); + + if (i.isEmpty()) + i = "0"; + + Double input_number = Double.valueOf(i); + Double static_number = getNumber(); + Double result_number = calculate(input_number, static_number); + + if ( isFloat() ) + return String.valueOf(result_number).getBytes(); + + return String.valueOf(Math.round(result_number)).getBytes(); + + } + + catch( Exception e ) + { + throw new IllegalArgumentException("Input is not a number."); + } + } + + protected abstract double calculate(double input_number, double static_number); + + @Override + public void createUI() + { + this.numberInput = new JTextField("1"); + this.addUIElement("Number", this.numberInput); + + this.floatCheckBox = new JCheckBox(); + this.addUIElement("Point Number", this.floatCheckBox); + } +} \ No newline at end of file diff --git a/src/main/java/de/usd/cstchef/operations/arithmetic/Divide.java b/src/main/java/de/usd/cstchef/operations/arithmetic/Divide.java new file mode 100644 index 0000000..46a7e31 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/Divide.java @@ -0,0 +1,46 @@ +package de.usd.cstchef.operations.arithmetic; + +import javax.swing.JCheckBox; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "Single - Divide", category = OperationCategory.ARITHMETIC, description = "Divide input by the given number") +public class Divide extends ArithmeticOperation +{ + private JCheckBox reverse; + + protected boolean isReverse() + { + return reverse.isSelected(); + } + + @Override + protected double calculate(double input_number, double static_number) + { + if( isReverse() ) + { + if( input_number == 0 ) + input_number = 1; + + return static_number / input_number; + } + + else + { + if( static_number == 0 ) + static_number = 1; + + return input_number / static_number; + } + } + + @Override + public void createUI() + { + super.createUI(); + + this.reverse = new JCheckBox(); + this.addUIElement("Reverse", this.reverse); + } +} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/arithmetic/DivideList.java b/src/main/java/de/usd/cstchef/operations/arithmetic/DivideList.java similarity index 63% rename from src/de/usd/cstchef/operations/arithmetic/DivideList.java rename to src/main/java/de/usd/cstchef/operations/arithmetic/DivideList.java index bc4992c..c3bee77 100644 --- a/src/de/usd/cstchef/operations/arithmetic/DivideList.java +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/DivideList.java @@ -4,11 +4,11 @@ import de.usd.cstchef.operations.Operation.OperationInfos; @OperationInfos(name = "List - Divide", category = OperationCategory.ARITHMETIC, description = "Divides a list of numbers.") -public class DivideList extends ArithmeticDelimiterOperation { - - @Override - protected double calculate(double a, double b) { - return a / b; - } - -} +public class DivideList extends ArithmeticDelimiterOperation +{ + @Override + protected double calculate(double a, double b) + { + return a / b; + } +} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/arithmetic/Mean.java b/src/main/java/de/usd/cstchef/operations/arithmetic/Mean.java similarity index 51% rename from src/de/usd/cstchef/operations/arithmetic/Mean.java rename to src/main/java/de/usd/cstchef/operations/arithmetic/Mean.java index c0b96f1..a1b3798 100644 --- a/src/de/usd/cstchef/operations/arithmetic/Mean.java +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/Mean.java @@ -4,16 +4,17 @@ import de.usd.cstchef.operations.Operation.OperationInfos; @OperationInfos(name = "List - Mean", category = OperationCategory.ARITHMETIC, description = "Computes the mean of a list of numbers.") -public class Mean extends ArithmeticDelimiterOperation { +public class Mean extends ArithmeticDelimiterOperation +{ + @Override + protected double calculate(double a, double b) + { + return a + b; + } - @Override - protected double calculate(double a, double b) { - return a + b; - } - - @Override - protected double onFinish(double result, double[] lines) { - return result / lines.length; - } - -} + @Override + protected double onFinish(double result, double[] lines) + { + return result / lines.length; + } +} \ No newline at end of file diff --git a/src/main/java/de/usd/cstchef/operations/arithmetic/Median.java b/src/main/java/de/usd/cstchef/operations/arithmetic/Median.java new file mode 100644 index 0000000..ab29e6e --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/Median.java @@ -0,0 +1,36 @@ +package de.usd.cstchef.operations.arithmetic; + +import java.util.Arrays; + +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "List - Median", category = OperationCategory.ARITHMETIC, description = "Computes the median of a list of numbers.") +public class Median extends ArithmeticDelimiterOperation +{ + @Override + protected double calculate(double a, double b) + { + return a; + } + + @Override + protected double onFinish(double intermediateResult, double[] lines) + { + Arrays.sort(lines); + double result; + + if (lines.length % 2 == 0) + { + int mid = lines.length / 2; + result = (lines[mid] + lines[mid - 1]) / 2; + } + + else + { + result = lines[(int) (Math.floor(lines.length / 2))]; + } + + return result; + } +} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/arithmetic/Multiply.java b/src/main/java/de/usd/cstchef/operations/arithmetic/Multiply.java similarity index 60% rename from src/de/usd/cstchef/operations/arithmetic/Multiply.java rename to src/main/java/de/usd/cstchef/operations/arithmetic/Multiply.java index 0b9b5a9..1fd4934 100644 --- a/src/de/usd/cstchef/operations/arithmetic/Multiply.java +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/Multiply.java @@ -4,11 +4,11 @@ import de.usd.cstchef.operations.OperationCategory; @OperationInfos(name = "Single - Multiply", category = OperationCategory.ARITHMETIC, description = "Multiply input with the given number") -public class Multiply extends ArithmeticOperation { - - @Override - protected double calculate(double input_number, double static_number) { - return input_number * static_number; - } - -} +public class Multiply extends ArithmeticOperation +{ + @Override + protected double calculate(double input_number, double static_number) + { + return input_number * static_number; + } +} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/arithmetic/MultiplyList.java b/src/main/java/de/usd/cstchef/operations/arithmetic/MultiplyList.java similarity index 63% rename from src/de/usd/cstchef/operations/arithmetic/MultiplyList.java rename to src/main/java/de/usd/cstchef/operations/arithmetic/MultiplyList.java index 2ba1e6e..5672221 100644 --- a/src/de/usd/cstchef/operations/arithmetic/MultiplyList.java +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/MultiplyList.java @@ -4,11 +4,11 @@ import de.usd.cstchef.operations.Operation.OperationInfos; @OperationInfos(name = "List - Multiply", category = OperationCategory.ARITHMETIC, description = "Multiplies a list of numbers.") -public class MultiplyList extends ArithmeticDelimiterOperation { - - @Override - protected double calculate(double a, double b) { - return a * b; - } - -} +public class MultiplyList extends ArithmeticDelimiterOperation +{ + @Override + protected double calculate(double a, double b) + { + return a * b; + } +} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/arithmetic/Subtraction.java b/src/main/java/de/usd/cstchef/operations/arithmetic/Subtraction.java similarity index 60% rename from src/de/usd/cstchef/operations/arithmetic/Subtraction.java rename to src/main/java/de/usd/cstchef/operations/arithmetic/Subtraction.java index 63e6c34..f8e2721 100644 --- a/src/de/usd/cstchef/operations/arithmetic/Subtraction.java +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/Subtraction.java @@ -4,10 +4,11 @@ import de.usd.cstchef.operations.Operation.OperationInfos; @OperationInfos(name = "Single - Subtract", category = OperationCategory.ARITHMETIC, description = "Subtract from the input the given number.") -public class Subtraction extends ArithmeticOperation { - - @Override - protected double calculate(double input_number, double static_number) { - return input_number - static_number; - } -} +public class Subtraction extends ArithmeticOperation +{ + @Override + protected double calculate(double input_number, double static_number) + { + return input_number - static_number; + } +} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/arithmetic/Sum.java b/src/main/java/de/usd/cstchef/operations/arithmetic/Sum.java similarity index 64% rename from src/de/usd/cstchef/operations/arithmetic/Sum.java rename to src/main/java/de/usd/cstchef/operations/arithmetic/Sum.java index 9f6256d..65880ca 100644 --- a/src/de/usd/cstchef/operations/arithmetic/Sum.java +++ b/src/main/java/de/usd/cstchef/operations/arithmetic/Sum.java @@ -4,11 +4,12 @@ import de.usd.cstchef.operations.Operation.OperationInfos; @OperationInfos(name = "List - Sum", category = OperationCategory.ARITHMETIC, description = "Sums a list of numbers.") -public class Sum extends ArithmeticDelimiterOperation { - - @Override - protected double calculate(double a, double b) { - return a + b; - } - -} +public class Sum extends ArithmeticDelimiterOperation +{ + + @Override + protected double calculate(double a, double b) + { + return a + b; + } +} \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/byteoperation/AddKey.java b/src/main/java/de/usd/cstchef/operations/byteoperation/AddKey.java similarity index 74% rename from src/de/usd/cstchef/operations/byteoperation/AddKey.java rename to src/main/java/de/usd/cstchef/operations/byteoperation/AddKey.java index 955c598..57c5fba 100644 --- a/src/de/usd/cstchef/operations/byteoperation/AddKey.java +++ b/src/main/java/de/usd/cstchef/operations/byteoperation/AddKey.java @@ -6,9 +6,9 @@ @OperationInfos(name = "Add", category = OperationCategory.BYTEOPERATION, description = "Adds the input with the given key.") public class AddKey extends ByteKeyOperation { - @Override - protected byte calculate(byte input, byte var) { - return (byte) ((input + var) % 255); - } + @Override + protected byte calculate(byte input, byte var) { + return (byte) ((input + var) % 255); + } } diff --git a/src/de/usd/cstchef/operations/byteoperation/And.java b/src/main/java/de/usd/cstchef/operations/byteoperation/And.java similarity index 74% rename from src/de/usd/cstchef/operations/byteoperation/And.java rename to src/main/java/de/usd/cstchef/operations/byteoperation/And.java index 571e8c7..ad11cc4 100644 --- a/src/de/usd/cstchef/operations/byteoperation/And.java +++ b/src/main/java/de/usd/cstchef/operations/byteoperation/And.java @@ -6,9 +6,9 @@ @OperationInfos(name = "And", category = OperationCategory.BYTEOPERATION, description = "Ands the input with the given key.") public class And extends ByteKeyOperation { - @Override - protected byte calculate(byte input, byte var) { - return (byte) ((input & var) % 255); - } + @Override + protected byte calculate(byte input, byte var) { + return (byte) ((input & var) % 255); + } } diff --git a/src/main/java/de/usd/cstchef/operations/byteoperation/ByteKeyOperation.java b/src/main/java/de/usd/cstchef/operations/byteoperation/ByteKeyOperation.java new file mode 100644 index 0000000..54026fc --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/byteoperation/ByteKeyOperation.java @@ -0,0 +1,37 @@ +package de.usd.cstchef.operations.byteoperation; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.view.ui.FormatTextField; + +public abstract class ByteKeyOperation extends Operation { + + private FormatTextField inputTxt; + + public void createUI() { + this.inputTxt = new FormatTextField(); + this.addUIElement("Key", inputTxt); + } + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] result = new byte[input.length]; + byte[] key = this.inputTxt.getText(); + + if (key.length == 0) { + return input; + } + + int keyCounter = 0; + for (int i = 0; i < input.length; i++) { + byte var = key[keyCounter]; + keyCounter = (keyCounter + 1) % key.length; + result[i] = calculate(input[i], var); + } + + return result; + } + + protected abstract byte calculate(byte input, byte var); + +} diff --git a/src/de/usd/cstchef/operations/byteoperation/Sub.java b/src/main/java/de/usd/cstchef/operations/byteoperation/Sub.java similarity index 74% rename from src/de/usd/cstchef/operations/byteoperation/Sub.java rename to src/main/java/de/usd/cstchef/operations/byteoperation/Sub.java index 68e4cf8..0f7892b 100644 --- a/src/de/usd/cstchef/operations/byteoperation/Sub.java +++ b/src/main/java/de/usd/cstchef/operations/byteoperation/Sub.java @@ -6,9 +6,9 @@ @OperationInfos(name = "Sub", category = OperationCategory.BYTEOPERATION, description = "Substracts the input with the given key.") public class Sub extends ByteKeyOperation { - @Override - protected byte calculate(byte input, byte var) { - return (byte) ((input - var) % 255); - } + @Override + protected byte calculate(byte input, byte var) { + return (byte) ((input - var) % 255); + } } diff --git a/src/de/usd/cstchef/operations/byteoperation/Xor.java b/src/main/java/de/usd/cstchef/operations/byteoperation/Xor.java similarity index 74% rename from src/de/usd/cstchef/operations/byteoperation/Xor.java rename to src/main/java/de/usd/cstchef/operations/byteoperation/Xor.java index cda432e..bc91ad6 100644 --- a/src/de/usd/cstchef/operations/byteoperation/Xor.java +++ b/src/main/java/de/usd/cstchef/operations/byteoperation/Xor.java @@ -6,9 +6,9 @@ @OperationInfos(name = "Xor", category = OperationCategory.BYTEOPERATION, description = "Xors the input with the given key.") public class Xor extends ByteKeyOperation { - @Override - protected byte calculate(byte input, byte var) { - return (byte) ((input ^ var) % 255); - } + @Override + protected byte calculate(byte input, byte var) { + return (byte) ((input ^ var) % 255); + } } diff --git a/src/de/usd/cstchef/operations/compression/Deflate.java b/src/main/java/de/usd/cstchef/operations/compression/Deflate.java similarity index 82% rename from src/de/usd/cstchef/operations/compression/Deflate.java rename to src/main/java/de/usd/cstchef/operations/compression/Deflate.java index e8d3c01..a98b7a9 100644 --- a/src/de/usd/cstchef/operations/compression/Deflate.java +++ b/src/main/java/de/usd/cstchef/operations/compression/Deflate.java @@ -16,16 +16,16 @@ protected byte[] perform(byte[] input) throws Exception { Deflater deflater = new Deflater(); deflater.setInput(input); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(input.length); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(input.length); deflater.finish(); - byte[] buffer = new byte[1024]; - while( !deflater.finished() ) { + byte[] buffer = new byte[1024]; + while( !deflater.finished() ) { int count = deflater.deflate(buffer); - outputStream.write(buffer, 0, count); + outputStream.write(buffer, 0, count); } outputStream.close(); return outputStream.toByteArray(); - } + } } diff --git a/src/de/usd/cstchef/operations/compression/GUnzip.java b/src/main/java/de/usd/cstchef/operations/compression/GUnzip.java similarity index 71% rename from src/de/usd/cstchef/operations/compression/GUnzip.java rename to src/main/java/de/usd/cstchef/operations/compression/GUnzip.java index 7cf6efa..8216951 100644 --- a/src/de/usd/cstchef/operations/compression/GUnzip.java +++ b/src/main/java/de/usd/cstchef/operations/compression/GUnzip.java @@ -13,20 +13,20 @@ public class GUnzip extends Operation { @Override protected byte[] perform(byte[] input) throws Exception { - ByteArrayInputStream in = new ByteArrayInputStream(input); - ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = new ByteArrayInputStream(input); + ByteArrayOutputStream out = new ByteArrayOutputStream(); GZIPInputStream gis = new GZIPInputStream(in); - - byte[] buffer = new byte[1024]; + + byte[] buffer = new byte[1024]; int len; - while((len = gis.read(buffer)) != -1){ - out.write(buffer, 0, len); + while((len = gis.read(buffer)) != -1){ + out.write(buffer, 0, len); } - gis.close(); + gis.close(); out.close(); in.close(); return out.toByteArray(); - } + } } diff --git a/src/de/usd/cstchef/operations/compression/Gzip.java b/src/main/java/de/usd/cstchef/operations/compression/Gzip.java similarity index 66% rename from src/de/usd/cstchef/operations/compression/Gzip.java rename to src/main/java/de/usd/cstchef/operations/compression/Gzip.java index 8c8e1ec..656ef6d 100644 --- a/src/de/usd/cstchef/operations/compression/Gzip.java +++ b/src/main/java/de/usd/cstchef/operations/compression/Gzip.java @@ -13,20 +13,20 @@ public class Gzip extends Operation { @Override protected byte[] perform(byte[] input) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - GZIPOutputStream gzos = new GZIPOutputStream(out); - ByteArrayInputStream in = new ByteArrayInputStream(input); - - byte[] buffer = new byte[1024]; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + GZIPOutputStream gzos = new GZIPOutputStream(out); + ByteArrayInputStream in = new ByteArrayInputStream(input); + + byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) > 0) { - gzos.write(buffer, 0, len); + gzos.write(buffer, 0, len); } - - in.close(); - gzos.close(); - out.close(); + + in.close(); + gzos.close(); + out.close(); return out.toByteArray(); - } + } } diff --git a/src/de/usd/cstchef/operations/compression/Inflate.java b/src/main/java/de/usd/cstchef/operations/compression/Inflate.java similarity index 82% rename from src/de/usd/cstchef/operations/compression/Inflate.java rename to src/main/java/de/usd/cstchef/operations/compression/Inflate.java index 76c083b..93668cb 100644 --- a/src/de/usd/cstchef/operations/compression/Inflate.java +++ b/src/main/java/de/usd/cstchef/operations/compression/Inflate.java @@ -16,15 +16,15 @@ protected byte[] perform(byte[] input) throws Exception { Inflater inflater = new Inflater(); inflater.setInput(input); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(input.length); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(input.length); - byte[] buffer = new byte[1024]; - while( !inflater.finished() ) { + byte[] buffer = new byte[1024]; + while( !inflater.finished() ) { int count = inflater.inflate(buffer); - outputStream.write(buffer, 0, count); + outputStream.write(buffer, 0, count); } outputStream.close(); return outputStream.toByteArray(); - } + } } diff --git a/src/main/java/de/usd/cstchef/operations/conditional/ConditionalOperation.java b/src/main/java/de/usd/cstchef/operations/conditional/ConditionalOperation.java new file mode 100644 index 0000000..3a9acd7 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/conditional/ConditionalOperation.java @@ -0,0 +1,52 @@ +package de.usd.cstchef.operations.conditional; + +import javax.swing.JTextField; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.view.ui.VariableTextField; + +public abstract class ConditionalOperation extends Operation { + + protected VariableTextField expr; + private JTextField operationSkipField; + private JTextField laneSkipField; + + public void setOperationSkip() { + + try { + int operationSkip = Integer.valueOf(operationSkipField.getText()); + this.setOperationSkip(operationSkip); + } catch( Exception e ) { + throw new IllegalArgumentException("Input is not a number."); + } + } + + public void setLaneSkip() { + + try { + int laneSkip = Integer.valueOf(laneSkipField.getText()); + this.setLaneSkip(laneSkip); + } catch( Exception e ) { + throw new IllegalArgumentException("Input is not a number."); + } + } + + public void resetSkips() { + this.setOperationSkip(0); + this.setLaneSkip(0); + } + + @Override + public void createUI() { + this.expr = new VariableTextField(); + this.addUIElement("Expr", this.expr); + + this.operationSkipField = new JTextField("0"); + this.addUIElement("Skip Operations", this.operationSkipField); + + this.laneSkipField = new JTextField("0"); + this.addUIElement("Skip Lanes", this.laneSkipField); + + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/conditional/NumberCompare.java b/src/main/java/de/usd/cstchef/operations/conditional/NumberCompare.java new file mode 100644 index 0000000..6358b9e --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/conditional/NumberCompare.java @@ -0,0 +1,73 @@ +package de.usd.cstchef.operations.conditional; + +import javax.swing.JComboBox; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "Number Compare", category = OperationCategory.CONDITIONALS, description = "Skip if evaluates to true") +public class NumberCompare extends ConditionalOperation { + + private JComboBox operationBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + Double inputNumber; + Double userNumber; + + try { + String tmp = new String(input); + inputNumber = Double.valueOf(tmp); + userNumber = Double.valueOf(this.expr.getText()); + } catch( Exception e ) { + throw new IllegalArgumentException("Input is not a number."); + } + + boolean condition = false; + switch ((String)this.operationBox.getSelectedItem()) { + case "equal": + if( inputNumber.compareTo(userNumber) == 0 ) + condition = true; + break; + case "not equal": + if( inputNumber.compareTo(userNumber) != 0 ) + condition = true; + break; + case "greater": + if( inputNumber < userNumber ) + condition = true; + break; + case "lower": + if( inputNumber > userNumber ) + condition = true; + break; + case "greater equal": + if( inputNumber <= userNumber ) + condition = true; + break; + case "lower equal": + if( inputNumber >= userNumber ) + condition = true; + break; + } + + if( condition ) { + this.setOperationSkip(); + this.setLaneSkip(); + } else { + this.resetSkips(); + } + + return input; + } + + @Override + public void createUI() { + super.createUI(); + this.operationBox = new JComboBox<>(new String[] {"equal", "not equal", "lower", "greater", "lower equal", "greater equal"}); + this.operationBox.setSelectedItem("equal"); + this.addUIElement("Lineseperator", this.operationBox); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/conditional/RegexMatch.java b/src/main/java/de/usd/cstchef/operations/conditional/RegexMatch.java new file mode 100644 index 0000000..fb9b9a8 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/conditional/RegexMatch.java @@ -0,0 +1,51 @@ +package de.usd.cstchef.operations.conditional; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.JCheckBox; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "Regex Match", category = OperationCategory.CONDITIONALS, description = "Skip if regex matches") +public class RegexMatch extends ConditionalOperation { + + private JCheckBox invert; + private JCheckBox find; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + Pattern p = Pattern.compile(this.expr.getText()); + Matcher m = p.matcher(new String(input)); + + boolean condition = false; + if( find.isSelected() ) { + condition = m.find(); + } else { + condition = m.matches(); + } + + if( condition ^ invert.isSelected() ) { + this.setOperationSkip(); + this.setLaneSkip(); + } else { + this.resetSkips(); + } + + return input; + } + + @Override + public void createUI() { + super.createUI(); + + this.invert = new JCheckBox(); + this.addUIElement("Invert Match", this.invert); + + this.find = new JCheckBox(); + this.addUIElement("Find anywhere", this.find); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/conditional/StringContains.java b/src/main/java/de/usd/cstchef/operations/conditional/StringContains.java new file mode 100644 index 0000000..ec118d4 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/conditional/StringContains.java @@ -0,0 +1,45 @@ +package de.usd.cstchef.operations.conditional; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "String Contains", category = OperationCategory.CONDITIONALS, description = "Skip if input contains") +public class StringContains extends ConditionalOperation { + + private JCheckBox invert; + private JCheckBox caseSensitive; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = cbs.getHelpers(); + int start = helpers.indexOf(input, this.expr.getBytes(), caseSensitive.isSelected(), 0, input.length); + + if( (start >= 0) ^ invert.isSelected() ) { + this.setOperationSkip(); + this.setLaneSkip(); + } else { + this.resetSkips(); + } + + return input; + } + + @Override + public void createUI() { + super.createUI(); + + this.invert = new JCheckBox(); + this.addUIElement("Invert Match", this.invert); + + this.caseSensitive = new JCheckBox(); + this.addUIElement("Case Sensitive", this.caseSensitive); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/conditional/StringMatch.java b/src/main/java/de/usd/cstchef/operations/conditional/StringMatch.java new file mode 100644 index 0000000..cd749a5 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/conditional/StringMatch.java @@ -0,0 +1,56 @@ +package de.usd.cstchef.operations.conditional; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "String Match", category = OperationCategory.CONDITIONALS, description = "Skip if input matches") +public class StringMatch extends ConditionalOperation { + + private JCheckBox invert; + private JCheckBox caseSensitive; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] search = this.expr.getBytes(); + if( search.length != input.length ) { + if( invert.isSelected() ) { + this.setOperationSkip(); + this.setLaneSkip(); + } else { + this.resetSkips(); + } + return input; + } + + IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = cbs.getHelpers(); + int start = helpers.indexOf(input, search, caseSensitive.isSelected(), 0, input.length); + + if( (start >= 0) ^ invert.isSelected() ) { + this.setOperationSkip(); + this.setLaneSkip(); + } else { + this.resetSkips(); + } + + return input; + } + + @Override + public void createUI() { + super.createUI(); + + this.invert = new JCheckBox(); + this.addUIElement("Invert Match", this.invert); + + this.caseSensitive = new JCheckBox(); + this.addUIElement("Case Sensitive", this.caseSensitive); + } + +} diff --git a/src/de/usd/cstchef/operations/dataformat/FromBase64.java b/src/main/java/de/usd/cstchef/operations/dataformat/FromBase64.java similarity index 77% rename from src/de/usd/cstchef/operations/dataformat/FromBase64.java rename to src/main/java/de/usd/cstchef/operations/dataformat/FromBase64.java index 39fb351..7caa4b0 100644 --- a/src/de/usd/cstchef/operations/dataformat/FromBase64.java +++ b/src/main/java/de/usd/cstchef/operations/dataformat/FromBase64.java @@ -9,8 +9,8 @@ @OperationInfos(name = "From Base64", category = OperationCategory.DATAFORMAT, description = "Decode a base64 string.") public class FromBase64 extends Operation { - @Override - protected byte[] perform(byte[] input) { - return Base64.getDecoder().decode(input); - } + @Override + protected byte[] perform(byte[] input) { + return Base64.getDecoder().decode(input); + } } diff --git a/src/main/java/de/usd/cstchef/operations/dataformat/FromHex.java b/src/main/java/de/usd/cstchef/operations/dataformat/FromHex.java new file mode 100644 index 0000000..7122eb9 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/dataformat/FromHex.java @@ -0,0 +1,43 @@ +package de.usd.cstchef.operations.dataformat; + +import java.util.Set; + +import javax.swing.JComboBox; +import org.bouncycastle.util.encoders.Hex; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.dataformat.ToHex.Delimiter; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "From Hex", category = OperationCategory.DATAFORMAT, description = "From hex") +public class FromHex extends Operation { + + private JComboBox delimiterBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + String selectedKey = (String) this.delimiterBox.getSelectedItem(); + Delimiter delimiter = ToHex.delimiters.get(selectedKey); + + if (delimiter.value.length == 0) { // No delimiter + return Hex.decode(input); + } + + String delimiterStr = new String(delimiter.value); + String inputStr = new String(input); + inputStr = inputStr.replace(delimiterStr, ""); + + return Hex.decode(inputStr); + } + + @Override + public void createUI() { + Set choices = ToHex.delimiters.keySet(); + delimiterBox = new JComboBox(choices.toArray(new String[choices.size()])); + delimiterBox.setSelectedIndex(0); + + this.addUIElement("Delimiter", delimiterBox); + } + +} diff --git a/src/de/usd/cstchef/operations/dataformat/HtmlDecode.java b/src/main/java/de/usd/cstchef/operations/dataformat/HtmlDecode.java similarity index 63% rename from src/de/usd/cstchef/operations/dataformat/HtmlDecode.java rename to src/main/java/de/usd/cstchef/operations/dataformat/HtmlDecode.java index 918d0d1..6d6c445 100644 --- a/src/de/usd/cstchef/operations/dataformat/HtmlDecode.java +++ b/src/main/java/de/usd/cstchef/operations/dataformat/HtmlDecode.java @@ -11,12 +11,12 @@ @OperationInfos(name = "HTML Decode", category = OperationCategory.DATAFORMAT, description = "HTML Decode") public class HtmlDecode extends Operation { - @Override - protected byte[] perform(byte[] input) throws Exception { - - String tmp = new String(input, StandardCharsets.ISO_8859_1); - tmp = StringEscapeUtils.unescapeHtml4(tmp); - return tmp.getBytes(StandardCharsets.ISO_8859_1); - } + @Override + protected byte[] perform(byte[] input) throws Exception { + + String tmp = new String(input, StandardCharsets.ISO_8859_1); + tmp = StringEscapeUtils.unescapeHtml4(tmp); + return tmp.getBytes(StandardCharsets.ISO_8859_1); + } } diff --git a/src/main/java/de/usd/cstchef/operations/dataformat/HtmlEncode.java b/src/main/java/de/usd/cstchef/operations/dataformat/HtmlEncode.java new file mode 100644 index 0000000..b73e076 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/dataformat/HtmlEncode.java @@ -0,0 +1,54 @@ +package de.usd.cstchef.operations.dataformat; + +import java.io.ByteArrayOutputStream; + +import javax.swing.JCheckBox; + +import org.apache.commons.text.StringEscapeUtils; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTML Encode", category = OperationCategory.DATAFORMAT, description = "HTML Encode") +public class HtmlEncode extends Operation { + + private JCheckBox checkbox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] result = null; + if( checkbox.isSelected() ) { + + byte[] delimiter = "&#".getBytes(); + byte[] closer = ";".getBytes(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(delimiter); + for (int i = 0; i < input.length - 1; i++) { + out.write(String.valueOf(Byte.toUnsignedInt(input[i])).getBytes()); + out.write(closer); + out.write(delimiter); + } + + out.write(String.valueOf(Byte.toUnsignedInt(input[input.length - 1])).getBytes()); + out.write(closer); + result = out.toByteArray(); + + } else { + String tmp = new String(input); + tmp = StringEscapeUtils.escapeHtml4(tmp); + result = tmp.getBytes(); + } + + return result; + } + + @Override + public void createUI() { + this.checkbox = new JCheckBox("Encode all"); + this.checkbox.setSelected(false); + this.addUIElement(null, this.checkbox, "checkbox1"); + } +} diff --git a/src/de/usd/cstchef/operations/dataformat/ToBase64.java b/src/main/java/de/usd/cstchef/operations/dataformat/ToBase64.java similarity index 77% rename from src/de/usd/cstchef/operations/dataformat/ToBase64.java rename to src/main/java/de/usd/cstchef/operations/dataformat/ToBase64.java index 4070650..2606483 100644 --- a/src/de/usd/cstchef/operations/dataformat/ToBase64.java +++ b/src/main/java/de/usd/cstchef/operations/dataformat/ToBase64.java @@ -9,9 +9,9 @@ @OperationInfos(name = "To Base64", category = OperationCategory.DATAFORMAT, description = "Encodes a string to base64.") public class ToBase64 extends Operation { - @Override - protected byte[] perform(byte[] input) { - return Base64.getEncoder().encode(input); - } - + @Override + protected byte[] perform(byte[] input) { + return Base64.getEncoder().encode(input); + } + } diff --git a/src/main/java/de/usd/cstchef/operations/dataformat/ToHex.java b/src/main/java/de/usd/cstchef/operations/dataformat/ToHex.java new file mode 100644 index 0000000..3885cb4 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/dataformat/ToHex.java @@ -0,0 +1,92 @@ +package de.usd.cstchef.operations.dataformat; + +import java.io.ByteArrayOutputStream; +import java.util.HashMap; +import java.util.Set; + +import javax.swing.JComboBox; +import org.bouncycastle.util.encoders.Hex; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "To Hex", category = OperationCategory.DATAFORMAT, description = "To hex") +public class ToHex extends Operation { + + static HashMap delimiters = new HashMap() { + { + put("None", new Delimiter("")); + put("Space", new Delimiter(" ")); + put("Comma", new Delimiter(",")); + put("Colon", new Delimiter(":")); + put("Semi-colon", new Delimiter(";")); + put("Colon", new Delimiter(":")); + put("Line feed", new Delimiter("\n")); + put("CRLF", new Delimiter("\r\n")); + put("0x", new Delimiter("0x", true)); + put("\\x", new Delimiter("\\x", true)); + } + }; + + private JComboBox delimiterBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + String selectedKey = (String) this.delimiterBox.getSelectedItem(); + Delimiter delimiter = ToHex.delimiters.get(selectedKey); + + if (delimiter.value.length == 0) { // No delimiter + return Hex.encode(input); + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + if (input.length > 0 && delimiter.writeAtStart) { + out.write(delimiter.value); + } + + for (int i = 0; i < input.length - 1; i++) { + out.write(Hex.encode(new byte[] { input[i] })); + out.write(delimiter.value); + } + + if (input.length > 0) { + out.write(Hex.encode(new byte[] { input[input.length - 1] })); // wow + if (delimiter.writeAtEnd) { + out.write(delimiter.value); + } + } + + return out.toByteArray(); + } + + @Override + public void createUI() { + Set choices = ToHex.delimiters.keySet(); + delimiterBox = new JComboBox(choices.toArray(new String[choices.size()])); + delimiterBox.setSelectedIndex(0); + + this.addUIElement("Delimiter", delimiterBox); + } + + public static class Delimiter { + public byte[] value; + public boolean writeAtStart; + public boolean writeAtEnd; + + public Delimiter(String value) { + this(value, false, false); + } + + public Delimiter(String value, boolean writeAtStart) { + this(value, writeAtStart, false); + } + + public Delimiter(String value, boolean writeAtStart, boolean writeAtEnd) { + this.value = value.getBytes(); + this.writeAtStart = writeAtStart; + this.writeAtEnd = writeAtEnd; + } + } +} diff --git a/src/de/usd/cstchef/operations/dataformat/UrlDecode.java b/src/main/java/de/usd/cstchef/operations/dataformat/UrlDecode.java similarity index 60% rename from src/de/usd/cstchef/operations/dataformat/UrlDecode.java rename to src/main/java/de/usd/cstchef/operations/dataformat/UrlDecode.java index 0a04ff1..dd9dd46 100644 --- a/src/de/usd/cstchef/operations/dataformat/UrlDecode.java +++ b/src/main/java/de/usd/cstchef/operations/dataformat/UrlDecode.java @@ -10,13 +10,13 @@ @OperationInfos(name = "Url Decode", category = OperationCategory.DATAFORMAT, description = "Url decoding") public class UrlDecode extends Operation { - @Override - protected byte[] perform(byte[] input) throws Exception { - IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); - IExtensionHelpers helpers = cbs.getHelpers(); - - byte[] result = helpers.urlDecode(input); - return result; - } + @Override + protected byte[] perform(byte[] input) throws Exception { + IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = cbs.getHelpers(); + + byte[] result = helpers.urlDecode(input); + return result; + } } diff --git a/src/main/java/de/usd/cstchef/operations/dataformat/UrlEncode.java b/src/main/java/de/usd/cstchef/operations/dataformat/UrlEncode.java new file mode 100644 index 0000000..e481530 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/dataformat/UrlEncode.java @@ -0,0 +1,54 @@ +package de.usd.cstchef.operations.dataformat; + +import java.io.ByteArrayOutputStream; + +import javax.swing.JCheckBox; + +import org.bouncycastle.util.encoders.Hex; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "Url Encode", category = OperationCategory.DATAFORMAT, description = "Url encode") +public class UrlEncode extends Operation { + + private JCheckBox checkbox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = cbs.getHelpers(); + + byte[] result = null; + if( checkbox.isSelected() ) { + + byte[] delimiter = "%".getBytes(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(delimiter); + + for (int i = 0; i < input.length - 1; i++) { + out.write(Hex.encode(new byte[] { input[i] })); + out.write(delimiter); + } + + out.write(Hex.encode(new byte[] { input[input.length - 1] })); + result = out.toByteArray(); + + } else { + result = helpers.urlEncode(input); + } + + return result; + } + + @Override + public void createUI() { + this.checkbox = new JCheckBox("Encode all"); + this.checkbox.setSelected(false); + this.addUIElement(null, this.checkbox, "checkbox1"); + } +} diff --git a/src/de/usd/cstchef/operations/datetime/DateTime.java b/src/main/java/de/usd/cstchef/operations/datetime/DateTime.java similarity index 54% rename from src/de/usd/cstchef/operations/datetime/DateTime.java rename to src/main/java/de/usd/cstchef/operations/datetime/DateTime.java index 85d7577..24a6b8e 100644 --- a/src/de/usd/cstchef/operations/datetime/DateTime.java +++ b/src/main/java/de/usd/cstchef/operations/datetime/DateTime.java @@ -11,18 +11,18 @@ @OperationInfos(name = "Date Time", category = OperationCategory.DATES, description = "Returnes the current date time formatted with the provided date time pattern.") public class DateTime extends Operation { - private VariableTextField patternTxt; + private VariableTextField patternTxt; - @Override - protected byte[] perform(byte[] input) throws Exception { - String pattern = this.patternTxt.getText().trim(); - SimpleDateFormat format = new SimpleDateFormat(pattern); - return format.format(new Date()).getBytes(); - } + @Override + protected byte[] perform(byte[] input) throws Exception { + String pattern = this.patternTxt.getText().trim(); + SimpleDateFormat format = new SimpleDateFormat(pattern); + return format.format(new Date()).getBytes(); + } - public void createUI() { - this.patternTxt = new VariableTextField(); - this.addUIElement("Pattern", this.patternTxt); - } + public void createUI() { + this.patternTxt = new VariableTextField(); + this.addUIElement("Pattern", this.patternTxt); + } } diff --git a/src/main/java/de/usd/cstchef/operations/datetime/UnixTimestamp.java b/src/main/java/de/usd/cstchef/operations/datetime/UnixTimestamp.java new file mode 100644 index 0000000..f8004fd --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/datetime/UnixTimestamp.java @@ -0,0 +1,31 @@ +package de.usd.cstchef.operations.datetime; + +import javax.swing.JCheckBox; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "Unix Timestamp", category = OperationCategory.DATES, description = "Returnes the current unix timestamp.") +public class UnixTimestamp extends Operation { + + private JCheckBox milliBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + long timestamp = 0; + if (milliBox.isSelected()) { + timestamp = System.currentTimeMillis(); + } + else { + timestamp = System.currentTimeMillis() / 1000L; + } + return String.valueOf(timestamp).getBytes(); + } + + public void createUI() { + this.milliBox = new JCheckBox(); + this.addUIElement("Milliseconds", this.milliBox); + } + +} diff --git a/src/de/usd/cstchef/operations/encryption/AesDecryption.java b/src/main/java/de/usd/cstchef/operations/encryption/AesDecryption.java similarity index 86% rename from src/de/usd/cstchef/operations/encryption/AesDecryption.java rename to src/main/java/de/usd/cstchef/operations/encryption/AesDecryption.java index 0e5abc6..d6267a3 100644 --- a/src/de/usd/cstchef/operations/encryption/AesDecryption.java +++ b/src/main/java/de/usd/cstchef/operations/encryption/AesDecryption.java @@ -6,8 +6,8 @@ @OperationInfos(name = "AES Decryption", category = OperationCategory.ENCRYPTION, description = "Decrypts via the aes algorithm.") public class AesDecryption extends DecryptionOperation { - public AesDecryption() { - super("AES"); - } + public AesDecryption() { + super("AES"); + } } diff --git a/src/de/usd/cstchef/operations/encryption/AesEncryption.java b/src/main/java/de/usd/cstchef/operations/encryption/AesEncryption.java similarity index 86% rename from src/de/usd/cstchef/operations/encryption/AesEncryption.java rename to src/main/java/de/usd/cstchef/operations/encryption/AesEncryption.java index 8d3a02f..c9ea238 100644 --- a/src/de/usd/cstchef/operations/encryption/AesEncryption.java +++ b/src/main/java/de/usd/cstchef/operations/encryption/AesEncryption.java @@ -6,8 +6,8 @@ @OperationInfos(name = "AES Encryption", category = OperationCategory.ENCRYPTION, description = "Encrypts via the aes algorithm.") public class AesEncryption extends EncryptionOperation { - public AesEncryption() { - super("AES"); - } + public AesEncryption() { + super("AES"); + } } diff --git a/src/main/java/de/usd/cstchef/operations/encryption/CipherUtils.java b/src/main/java/de/usd/cstchef/operations/encryption/CipherUtils.java new file mode 100644 index 0000000..5a38482 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/encryption/CipherUtils.java @@ -0,0 +1,106 @@ +package de.usd.cstchef.operations.encryption; + +import java.security.Provider; +import java.security.Security; +import java.util.HashMap; + +public class CipherUtils { + + private static CipherUtils instance; + + private HashMap algos; + + private CipherUtils() { + algos = new HashMap<>(); + + getCipherInfos(); + } + + private void getCipherInfos() { + for (Provider provider : Security.getProviders()) { + for (String key : provider.stringPropertyNames()) { + if (key.startsWith("Cipher")) { + String[] parts = key.split(" "); + if (parts.length < 2) { + continue; + } + String cipherName = parts[0].substring(7); + String type = parts[1]; + + CipherInfo info = algos.getOrDefault(cipherName, new CipherInfo()); + String property = provider.getProperty(key); + + if (type.equals("SupportedModes")) { + String[] modes = property.split("\\|"); + info.setModes(modes); + } else if (type.equals("SupportedPaddings")) { + String[] paddings = property.split("\\|"); + info.setPaddings(paddings); + } + this.algos.put(cipherName, info); + } + } + } + } + + public static CipherUtils getInstance() { + if (instance == null) { + instance = new CipherUtils(); + } + return instance; + } + + public CipherInfo getCipherInfo(String algorithm) { + return this.algos.getOrDefault(algorithm, new CipherInfo()); + } + + public class CipherInfo { + + private String[] modes; + private String[] paddings; + + + public CipherInfo() { + this.modes = new String[0]; + this.paddings = new String[0]; + } + + public CipherInfo(String[] modes, String[] paddings) { + this.modes = modes; + this.paddings = paddings; + } + + public String[] getModes() { + return modes; + } + + public void setModes(String[] modes) { + this.modes = modes; + } + + public String[] getPaddings() { + return paddings; + } + + public void setPaddings(String[] paddings) { + this.paddings = paddings; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("Modes: "); + for (String mode : this.modes) { + buf.append(mode); + buf.append("|"); + } + buf.append(", Paddings: "); + for (String padding : this.paddings) { + buf.append(padding); + buf.append("|"); + } + + return buf.toString(); + } + + } +} diff --git a/src/main/java/de/usd/cstchef/operations/encryption/CryptOperation.java b/src/main/java/de/usd/cstchef/operations/encryption/CryptOperation.java new file mode 100644 index 0000000..552989f --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/encryption/CryptOperation.java @@ -0,0 +1,89 @@ +package de.usd.cstchef.operations.encryption; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.swing.JComboBox; + +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.encoders.Base64; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.encryption.CipherUtils.CipherInfo; +import de.usd.cstchef.view.ui.FormatTextField; + +public abstract class CryptOperation extends Operation { + + private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" }; + + protected String algorithm; + protected FormatTextField ivTxt; + protected FormatTextField keyTxt; + + protected JComboBox cipherMode; + protected JComboBox inputMode; + protected JComboBox outputMode; + protected JComboBox paddings; + + public CryptOperation(String alogrithm) { + super(); + this.algorithm = alogrithm; + this.createMyUI(); + } + + protected byte[] crypt(byte[] input, int cipherMode, String algorithm, String mode, String padding) + throws Exception { + byte[] key = keyTxt.getText(); + byte[] iv = ivTxt.getText(); + + SecretKeySpec secretKeySpec = new SecretKeySpec(key, algorithm); + IvParameterSpec ivSpec = new IvParameterSpec(iv); + Cipher cipher = Cipher.getInstance(String.format("%s/%s/%s", algorithm, mode, padding)); + + if( mode.equals("ECB") ) { + cipher.init(cipherMode, secretKeySpec); + } else { + cipher.init(cipherMode, secretKeySpec, ivSpec); + } + + String selectedInputMode = (String)inputMode.getSelectedItem(); + String selectedOutputMode = (String)outputMode.getSelectedItem(); + + if( selectedInputMode.equals("Hex") ) + input = Hex.decode(input); + if( selectedInputMode.equals("Base64") ) + input = Base64.decode(input); + + byte[] encrypted = cipher.doFinal(input); + + if( selectedOutputMode.equals("Hex") ) + encrypted = Hex.encode(encrypted); + if( selectedOutputMode.equals("Base64") ) + encrypted = Base64.encode(encrypted); + + return encrypted; + } + + public void createMyUI() { + this.ivTxt = new FormatTextField(); + this.addUIElement("IV", this.ivTxt); + + this.keyTxt = new FormatTextField(); + this.addUIElement("Key", this.keyTxt); + CipherUtils utils = CipherUtils.getInstance(); + + CipherInfo info = utils.getCipherInfo(this.algorithm); + this.cipherMode = new JComboBox<>(info.getModes()); + this.addUIElement("Mode", this.cipherMode); + + this.paddings = new JComboBox<>(info.getPaddings()); + this.addUIElement("Padding", this.paddings); + + this.inputMode = new JComboBox<>(inOutModes); + this.addUIElement("Input", this.inputMode); + + this.outputMode = new JComboBox<>(inOutModes); + this.addUIElement("Output", this.outputMode); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/encryption/DecryptionOperation.java b/src/main/java/de/usd/cstchef/operations/encryption/DecryptionOperation.java new file mode 100644 index 0000000..a232ad7 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/encryption/DecryptionOperation.java @@ -0,0 +1,17 @@ +package de.usd.cstchef.operations.encryption; + +import javax.crypto.Cipher; + +public abstract class DecryptionOperation extends CryptOperation { + + public DecryptionOperation(String alogrithm) { + super(alogrithm); + } + + @Override + protected byte[] perform(byte[] input) throws Exception { + return this.crypt(input, Cipher.DECRYPT_MODE, this.algorithm, (String) this.cipherMode.getSelectedItem(), + (String) this.paddings.getSelectedItem()); + } + +} diff --git a/src/de/usd/cstchef/operations/encryption/DesDecryption.java b/src/main/java/de/usd/cstchef/operations/encryption/DesDecryption.java similarity index 86% rename from src/de/usd/cstchef/operations/encryption/DesDecryption.java rename to src/main/java/de/usd/cstchef/operations/encryption/DesDecryption.java index 6a4253e..9b35a1e 100644 --- a/src/de/usd/cstchef/operations/encryption/DesDecryption.java +++ b/src/main/java/de/usd/cstchef/operations/encryption/DesDecryption.java @@ -6,8 +6,8 @@ @OperationInfos(name = "DES Decryption", category = OperationCategory.ENCRYPTION, description = "Decrypts via the des algorithm.") public class DesDecryption extends DecryptionOperation { - public DesDecryption() { - super("DES"); - } + public DesDecryption() { + super("DES"); + } } diff --git a/src/de/usd/cstchef/operations/encryption/DesEncryption.java b/src/main/java/de/usd/cstchef/operations/encryption/DesEncryption.java similarity index 86% rename from src/de/usd/cstchef/operations/encryption/DesEncryption.java rename to src/main/java/de/usd/cstchef/operations/encryption/DesEncryption.java index 032298e..9e8bcf8 100644 --- a/src/de/usd/cstchef/operations/encryption/DesEncryption.java +++ b/src/main/java/de/usd/cstchef/operations/encryption/DesEncryption.java @@ -6,8 +6,8 @@ @OperationInfos(name = "DES Encryption", category = OperationCategory.ENCRYPTION, description = "Encrypts via the des algorithm.") public class DesEncryption extends EncryptionOperation { - public DesEncryption() { - super("DES"); - } + public DesEncryption() { + super("DES"); + } } diff --git a/src/main/java/de/usd/cstchef/operations/encryption/EncryptionOperation.java b/src/main/java/de/usd/cstchef/operations/encryption/EncryptionOperation.java new file mode 100644 index 0000000..0026cc8 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/encryption/EncryptionOperation.java @@ -0,0 +1,17 @@ +package de.usd.cstchef.operations.encryption; + +import javax.crypto.Cipher; + +public abstract class EncryptionOperation extends CryptOperation { + + public EncryptionOperation(String alogrithm) { + super(alogrithm); + } + + @Override + protected byte[] perform(byte[] input) throws Exception { + return this.crypt(input, Cipher.ENCRYPT_MODE, this.algorithm, (String) this.cipherMode.getSelectedItem(), + (String) this.paddings.getSelectedItem()); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/encryption/RsaDecryption.java b/src/main/java/de/usd/cstchef/operations/encryption/RsaDecryption.java new file mode 100644 index 0000000..16b363e --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/encryption/RsaDecryption.java @@ -0,0 +1,75 @@ +package de.usd.cstchef.operations.encryption; + +import javax.crypto.Cipher; +import javax.swing.JComboBox; + +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; + +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.encryption.CipherUtils.CipherInfo; +import de.usd.cstchef.operations.signature.KeystoreOperation; + +@OperationInfos(name = "RSA Decryption", category = OperationCategory.ENCRYPTION, description = "Decrypt input using a private key") +public class RsaDecryption extends KeystoreOperation { + + private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" }; + + protected String algorithm = "RSA"; + protected String cipherMode = "ECB"; + + protected JComboBox inputMode; + protected JComboBox outputMode; + protected JComboBox paddings; + + public RsaDecryption() { + super(); + this.createMyUI(); + } + + protected byte[] perform(byte[] input) throws Exception { + + if( ! this.keyAvailable.isSelected() ) + throw new IllegalArgumentException("No private key available."); + + String padding = (String)paddings.getSelectedItem(); + Cipher cipher = Cipher.getInstance(String.format("%s/%s/%s", algorithm, cipherMode, padding)); + cipher.init(Cipher.DECRYPT_MODE, this.selectedEntry.getPrivateKey()); + + String selectedInputMode = (String)inputMode.getSelectedItem(); + String selectedOutputMode = (String)outputMode.getSelectedItem(); + + if( selectedInputMode.equals("Hex") ) + input = Hex.decode(input); + if( selectedInputMode.equals("Base64") ) + input = Base64.decode(input); + + byte[] encrypted = cipher.doFinal(input); + + if( selectedOutputMode.equals("Hex") ) + encrypted = Hex.encode(encrypted); + if( selectedOutputMode.equals("Base64") ) + encrypted = Base64.encode(encrypted); + + return encrypted; + } + + public void createMyUI() { + + super.createMyUI(); + + CipherUtils utils = CipherUtils.getInstance(); + CipherInfo info = utils.getCipherInfo(this.algorithm); + + this.paddings = new JComboBox<>(info.getPaddings()); + this.addUIElement("Padding", this.paddings); + + this.inputMode = new JComboBox<>(inOutModes); + this.addUIElement("Input", this.inputMode); + + this.outputMode = new JComboBox<>(inOutModes); + this.addUIElement("Output", this.outputMode); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/encryption/RsaEncryption.java b/src/main/java/de/usd/cstchef/operations/encryption/RsaEncryption.java new file mode 100644 index 0000000..49db61a --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/encryption/RsaEncryption.java @@ -0,0 +1,75 @@ +package de.usd.cstchef.operations.encryption; + +import javax.crypto.Cipher; +import javax.swing.JComboBox; + +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; + +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.encryption.CipherUtils.CipherInfo; +import de.usd.cstchef.operations.signature.KeystoreOperation; + +@OperationInfos(name = "RSA Encryption", category = OperationCategory.ENCRYPTION, description = "Encrypt input using a certificate") +public class RsaEncryption extends KeystoreOperation { + + private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" }; + + protected String algorithm = "RSA"; + protected String cipherMode = "ECB"; + + protected JComboBox inputMode; + protected JComboBox outputMode; + protected JComboBox paddings; + + public RsaEncryption() { + super(); + this.createMyUI(); + } + + protected byte[] perform(byte[] input) throws Exception { + + if( ! this.certAvailable.isSelected() ) + throw new IllegalArgumentException("No certificate available."); + + String padding = (String)paddings.getSelectedItem(); + Cipher cipher = Cipher.getInstance(String.format("%s/%s/%s", algorithm, cipherMode, padding)); + cipher.init(Cipher.ENCRYPT_MODE, this.cert.getPublicKey()); + + String selectedInputMode = (String)inputMode.getSelectedItem(); + String selectedOutputMode = (String)outputMode.getSelectedItem(); + + if( selectedInputMode.equals("Hex") ) + input = Hex.decode(input); + if( selectedInputMode.equals("Base64") ) + input = Base64.decode(input); + + byte[] encrypted = cipher.doFinal(input); + + if( selectedOutputMode.equals("Hex") ) + encrypted = Hex.encode(encrypted); + if( selectedOutputMode.equals("Base64") ) + encrypted = Base64.encode(encrypted); + + return encrypted; + } + + public void createMyUI() { + + super.createMyUI(); + + CipherUtils utils = CipherUtils.getInstance(); + CipherInfo info = utils.getCipherInfo(this.algorithm); + + this.paddings = new JComboBox<>(info.getPaddings()); + this.addUIElement("Padding", this.paddings); + + this.inputMode = new JComboBox<>(inOutModes); + this.addUIElement("Input", this.inputMode); + + this.outputMode = new JComboBox<>(inOutModes); + this.addUIElement("Output", this.outputMode); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpBodyExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpBodyExtractor.java new file mode 100644 index 0000000..ac682e6 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpBodyExtractor.java @@ -0,0 +1,28 @@ +package de.usd.cstchef.operations.extractors; + +import java.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IRequestInfo; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "HTTP Body", category = OperationCategory.EXTRACTORS, description = "Extracts the body of a HTTP request.") +public class HttpBodyExtractor extends Operation { + + @Override + protected byte[] perform(byte[] input) throws Exception { + try { + IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); + IRequestInfo requestInfo = cbs.getHelpers().analyzeRequest(input); + int bodyOffset = requestInfo.getBodyOffset(); + + byte[] body = Arrays.copyOfRange(input, bodyOffset, input.length); + return body; + } catch (Exception e) { + throw new IllegalArgumentException("Provided input is not a valid http request."); + } + } +} \ No newline at end of file diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpCookieExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpCookieExtractor.java new file mode 100644 index 0000000..ae1d10f --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpCookieExtractor.java @@ -0,0 +1,63 @@ +package de.usd.cstchef.operations.extractors; + +import org.bouncycastle.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IResponseInfo; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "HTTP Cookie", category = OperationCategory.EXTRACTORS, description = "Extracts a cookie from a HTTP request.") +public class HttpCookieExtractor extends Operation { + + private VariableTextField cookieNameField; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] cookieName = cookieNameField.getBytes(); + if( cookieName.length == 0 ) + return input; + + byte[] cookieSearch = new byte[cookieName.length + 1]; + System.arraycopy(cookieName, 0, cookieSearch, 0, cookieName.length); + System.arraycopy("=".getBytes(), 0, cookieSearch, cookieName.length, 1); + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + IResponseInfo resp = helpers.analyzeResponse(input); + boolean isRequest = (resp.getStatusCode() == 0); + + String cookieHeader = "\r\nSet-Cookie: "; + if(isRequest) + cookieHeader = "\r\nCookie: "; + + try { + + int offset = helpers.indexOf(input, cookieHeader.getBytes(), false, 0, length); + int line_end = helpers.indexOf(input, "\r\n".getBytes(), false, offset + 2, length); + int start = helpers.indexOf(input, cookieSearch, true, offset, line_end); + int end = helpers.indexOf(input, ";".getBytes(), true, start, line_end); + + if( end < 0 ) + end = line_end; + + return Arrays.copyOfRange(input, start + cookieName.length + 1, end); + + } catch( IllegalArgumentException e ) { + throw new IllegalArgumentException("Cookie not found."); + } + } + + @Override + public void createUI() { + this.cookieNameField = new VariableTextField(); + this.addUIElement("Name", this.cookieNameField); + } +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpGetExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpGetExtractor.java new file mode 100644 index 0000000..21e06a7 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpGetExtractor.java @@ -0,0 +1,49 @@ +package de.usd.cstchef.operations.extractors; + +import java.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IParameter; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "HTTP GET Param", category = OperationCategory.EXTRACTORS, description = "Extracts a GET Parameter of a HTTP request.") +public class HttpGetExtractor extends Operation { + + protected VariableTextField parameter; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + String parameterName = parameter.getText(); + if( parameterName.equals("") ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + IParameter param = helpers.getRequestParameter(input, parameterName); + if( param == null) + throw new IllegalArgumentException("Parameter name not found."); + if( param.getType() != IParameter.PARAM_URL ) + throw new IllegalArgumentException("Parameter type is not GET."); + + int start = param.getValueStart(); + int end = param.getValueEnd(); + + byte[] result = Arrays.copyOfRange(input, start, end); + return result; + + } + + @Override + public void createUI() { + this.parameter = new VariableTextField(); + this.addUIElement("Parameter", this.parameter); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpHeaderExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpHeaderExtractor.java new file mode 100644 index 0000000..91870cb --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpHeaderExtractor.java @@ -0,0 +1,56 @@ +package de.usd.cstchef.operations.extractors; + +import org.bouncycastle.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "HTTP Header", category = OperationCategory.EXTRACTORS, description = "Extracts a header of a HTTP request.") +public class HttpHeaderExtractor extends Operation { + + private VariableTextField headerNameField; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] headerName = headerNameField.getBytes(); + if( headerName.length == 0 ) + return input; + + byte[] headerSearch = new byte[headerName.length + 4]; + System.arraycopy("\r\n".getBytes(), 0, headerSearch, 0, 2); + System.arraycopy(headerName, 0, headerSearch, 2, headerName.length); + System.arraycopy(": ".getBytes(), 0, headerSearch, headerName.length + 2, 2); + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + int offset = helpers.indexOf(input, headerSearch, true, 0, length); + + if( offset < 0 ) + throw new IllegalArgumentException("Header not found."); + + int valueStart = helpers.indexOf(input, " ".getBytes(), false, offset, length); + if( valueStart < 0 ) + throw new IllegalArgumentException("Invalid Header format."); + int valueEnd = helpers.indexOf(input, "\r\n".getBytes(), false, valueStart, length); + if( valueEnd < 0 ) + throw new IllegalArgumentException("Invalid Header format."); + + byte[] result = Arrays.copyOfRange(input, valueStart + 1, valueEnd); + return result; + } + + @Override + public void createUI() { + this.headerNameField = new VariableTextField(); + this.addUIElement("Name", this.headerNameField); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpJsonExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpJsonExtractor.java new file mode 100644 index 0000000..3f639e2 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpJsonExtractor.java @@ -0,0 +1,48 @@ +package de.usd.cstchef.operations.extractors; + +import java.util.Arrays; + +import javax.swing.JTextField; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IParameter; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP JSON", category = OperationCategory.EXTRACTORS, description = "Get a JSON value from HTTP message.") +public class HttpJsonExtractor extends Operation { + + private JTextField fieldTxt; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + String keyName = fieldTxt.getText(); + if( keyName.equals("") ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + IParameter param = helpers.getRequestParameter(input, keyName); + if( param == null) + throw new IllegalArgumentException("Key not found."); + if( param.getType() != IParameter.PARAM_JSON ) + throw new IllegalArgumentException("Parameter type is not JSON"); + + int start = param.getValueStart(); + int end = param.getValueEnd(); + + byte[] result = Arrays.copyOfRange(input, start, end); + return result; + } + + @Override + public void createUI() { + this.fieldTxt = new JTextField(); + this.addUIElement("Field", this.fieldTxt); + } +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpMethodExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpMethodExtractor.java new file mode 100644 index 0000000..3789a05 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpMethodExtractor.java @@ -0,0 +1,31 @@ +package de.usd.cstchef.operations.extractors; + +import org.bouncycastle.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP Method", category = OperationCategory.EXTRACTORS, description = "Extracts the method of a HTTP request.") +public class HttpMethodExtractor extends Operation { + + @Override + protected byte[] perform(byte[] input) throws Exception { + try { + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + int methodEnd = helpers.indexOf(input, " ".getBytes(), false, 0, length); + byte[] result = Arrays.copyOfRange(input, 0, methodEnd); + + return result; + + } catch (Exception e) { + throw new IllegalArgumentException("Provided input is not a valid http request."); + } + } +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpPostExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpPostExtractor.java new file mode 100644 index 0000000..a253ea0 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpPostExtractor.java @@ -0,0 +1,47 @@ +package de.usd.cstchef.operations.extractors; + +import java.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IParameter; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "HTTP POST Param", category = OperationCategory.EXTRACTORS, description = "Extracts a POST parameter of a HTTP request.") +public class HttpPostExtractor extends Operation { + + protected VariableTextField parameter; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + String parameterName = parameter.getText(); + if( parameterName.equals("") ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + IParameter param = helpers.getRequestParameter(input, parameterName); + if( param == null) + throw new IllegalArgumentException("Parameter name not found."); + if( param.getType() != IParameter.PARAM_BODY ) + throw new IllegalArgumentException("Parameter type is not POST"); + + int start = param.getValueStart(); + int end = param.getValueEnd(); + + byte[] result = Arrays.copyOfRange(input, start, end); + return result; + } + + @Override + public void createUI() { + this.parameter = new VariableTextField(); + this.addUIElement("Parameter", this.parameter); + } +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpUriExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpUriExtractor.java new file mode 100644 index 0000000..cc67c5e --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpUriExtractor.java @@ -0,0 +1,50 @@ +package de.usd.cstchef.operations.extractors; + +import java.util.Arrays; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP URI", category = OperationCategory.EXTRACTORS, description = "Extracts the URI of a HTTP request.") +public class HttpUriExtractor extends Operation { + + private JCheckBox checkbox; + + @Override + public void createUI() { + this.checkbox = new JCheckBox("With parameters"); + this.checkbox.setSelected(true); + this.addUIElement(null, this.checkbox, "checkbox1"); + } + + @Override + protected byte[] perform(byte[] input) throws Exception { + try { + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + int firstMark = helpers.indexOf(input, " ".getBytes(), false, 0, length); + int lineMark = helpers.indexOf(input, " ".getBytes(), false, firstMark + 1, length); + + int secondMark = helpers.indexOf(input, "?".getBytes(), false, firstMark + 1, length); + + if( this.checkbox.isSelected() || secondMark < 0 || secondMark >= lineMark) { + secondMark = lineMark; + } + + byte[] result = Arrays.copyOfRange(input, firstMark + 1, secondMark); + return result; + + } catch (Exception e) { + throw new IllegalArgumentException("Provided input is not a valid http request."); + } + } +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/HttpXmlExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/HttpXmlExtractor.java new file mode 100644 index 0000000..37f845c --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/HttpXmlExtractor.java @@ -0,0 +1,48 @@ +package de.usd.cstchef.operations.extractors; + +import java.util.Arrays; + +import javax.swing.JTextField; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IParameter; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP XML", category = OperationCategory.EXTRACTORS, description = "Extract XML value from HTTP message.") +public class HttpXmlExtractor extends Operation { + + private JTextField fieldTxt; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + String keyName = fieldTxt.getText(); + if( keyName.equals("") ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + IParameter param = helpers.getRequestParameter(input, keyName); + if( param == null) + throw new IllegalArgumentException("Key not found."); + if( param.getType() != IParameter.PARAM_XML ) + throw new IllegalArgumentException("Parameter type is not XML"); + + int start = param.getValueStart(); + int end = param.getValueEnd(); + + byte[] result = Arrays.copyOfRange(input, start, end); + return result; + } + + @Override + public void createUI() { + this.fieldTxt = new JTextField(); + this.addUIElement("Field", this.fieldTxt); + } +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/JsonExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/JsonExtractor.java new file mode 100644 index 0000000..0975fa3 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/JsonExtractor.java @@ -0,0 +1,59 @@ +package de.usd.cstchef.operations.extractors; + +import javax.swing.JTextField; + +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.spi.json.JsonProvider; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "JSON", category = OperationCategory.EXTRACTORS, description = "Extracts values of json objects.") +public class JsonExtractor extends Operation { + + private static JsonProvider provider; + + //TODO should this be a VariableTextField? + private JTextField fieldTxt; + + public JsonExtractor() { + super(); + if (JsonExtractor.provider == null) { + JsonExtractor.provider = Configuration.defaultConfiguration().jsonProvider(); + } + } + + @Override + protected byte[] perform(byte[] input) throws Exception { + + if( fieldTxt.getText().equals("") ) + return input; + + Object document = provider.parse(new String(input)); + Object result = JsonPath.read(document, fieldTxt.getText()); + + if( result == null ) + result = "null"; + + Class resultClass = result.getClass(); + + if( resultClass == String.class ) { + return ((String)result).getBytes(); + } else if( resultClass == Integer.class || resultClass == Float.class || resultClass == Double.class ) { + return String.valueOf(result).getBytes(); + } else if( resultClass == Boolean.class ) { + return String.valueOf(result).getBytes(); + } + + throw new IllegalArgumentException("JSON data of unknown type."); + } + + @Override + public void createUI() { + this.fieldTxt = new JTextField(); + this.addUIElement("Field", this.fieldTxt); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/LineExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/LineExtractor.java new file mode 100644 index 0000000..59de978 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/LineExtractor.java @@ -0,0 +1,82 @@ +package de.usd.cstchef.operations.extractors; + +import javax.swing.JComboBox; + +import org.bouncycastle.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "Line Extractor", category = OperationCategory.EXTRACTORS, description = "Extracts the specified line number.") +public class LineExtractor extends Operation { + + private VariableTextField lineNumberField; + private JComboBox formatBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + int lineNumber = 0; + try { + String number = lineNumberField.getText(); + lineNumber = Integer.valueOf(number); + } catch(Exception e) { + return input; + } + + if( lineNumber <= 0 ) + return input; + + byte[] lineEndings = "\r\n".getBytes(); + switch ((String) this.formatBox.getSelectedItem()) { + case "\\r\\n": + lineEndings = "\r\n".getBytes(); + break; + case "\\r": + lineEndings = "\r".getBytes(); + break; + case "\\n": + lineEndings = "\n".getBytes(); + break; + } + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + int start = 0; + int offset = 0; + int counter = 0; + while( counter < lineNumber - 1 ) { + offset = helpers.indexOf(input, lineEndings, false, start, length); + if( offset >= 0 ) { + start = offset + lineEndings.length; + counter++; + } else { + break; + } + } + + int end = helpers.indexOf(input, lineEndings, false, start, length); + if( end < 0 ) + end = length; + + byte[] result = Arrays.copyOfRange(input, start, end); + return result; + } + + @Override + public void createUI() { + this.lineNumberField = new VariableTextField(); + this.addUIElement("Name", this.lineNumberField); + this.formatBox = new JComboBox<>(new String[] {"\\r\\n", "\\r", "\\n"}); + this.formatBox.setSelectedItem("\\r\\n"); + this.addUIElement("Lineseperator", this.formatBox); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/extractors/RegexExtractor.java b/src/main/java/de/usd/cstchef/operations/extractors/RegexExtractor.java new file mode 100644 index 0000000..d3a7c9d --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/extractors/RegexExtractor.java @@ -0,0 +1,54 @@ +package de.usd.cstchef.operations.extractors; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.JComboBox; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "Regex", category = OperationCategory.EXTRACTORS, description = "Extracts using a regex.") +public class RegexExtractor extends Operation { + + private static String LIST_MATCHES = "List matches"; + private static String LIST_GROUPS = "List capture groups"; + + private VariableTextField regexTxt; + private JComboBox outputBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + Pattern p = Pattern.compile(this.regexTxt.getText()); + Matcher m = p.matcher(new String(input)); + String outputType = (String) this.outputBox.getSelectedItem(); + + StringBuffer buf = new StringBuffer(); + + while (m.find()) { + if (outputType.equals(LIST_MATCHES)) { + buf.append(m.group()).append("\n"); + } else { + for (int i = 1; i <= m.groupCount(); i++) { + buf.append(m.group(i)).append("\n"); + } + } + } + + if( buf.length() > 0 ) + buf.setLength(buf.length() - 1); + + return buf.toString().getBytes(); + } + + @Override + public void createUI() { + this.regexTxt = new VariableTextField(); + this.addUIElement("Regex", this.regexTxt); + + this.outputBox = new JComboBox<>(new String[] { LIST_MATCHES, LIST_GROUPS }); + this.addUIElement("Output format", this.outputBox); + } +} diff --git a/src/de/usd/cstchef/operations/hashing/Blake.java b/src/main/java/de/usd/cstchef/operations/hashing/Blake.java similarity index 70% rename from src/de/usd/cstchef/operations/hashing/Blake.java rename to src/main/java/de/usd/cstchef/operations/hashing/Blake.java index f66702e..ff58992 100644 --- a/src/de/usd/cstchef/operations/hashing/Blake.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/Blake.java @@ -6,8 +6,8 @@ @OperationInfos(name = "Blake", category = OperationCategory.HASHING, description = "The Blake algorithm") public class Blake extends HashOperation { - public Blake() { - super("BLAKE", "2B-512", "2B-384", "2B-256", "2B-160", "2S-256", "2S-224", "2S-160", "2S-128"); - } + public Blake() { + super("BLAKE", "2B-512", "2B-384", "2B-256", "2B-160", "2S-256", "2S-224", "2S-160", "2S-128"); + } } diff --git a/src/de/usd/cstchef/operations/hashing/DSTU7564.java b/src/main/java/de/usd/cstchef/operations/hashing/DSTU7564.java similarity index 80% rename from src/de/usd/cstchef/operations/hashing/DSTU7564.java rename to src/main/java/de/usd/cstchef/operations/hashing/DSTU7564.java index 51c6e16..b253593 100644 --- a/src/de/usd/cstchef/operations/hashing/DSTU7564.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/DSTU7564.java @@ -6,8 +6,8 @@ @OperationInfos(name = "DSTU7564", category = OperationCategory.HASHING, description = "The Whirlpool algorithm") public class DSTU7564 extends HashOperation { - public DSTU7564() { - super("DSTU7564-", "256", "384", "512"); - } + public DSTU7564() { + super("DSTU7564-", "256", "384", "512"); + } } diff --git a/src/de/usd/cstchef/operations/hashing/Gost.java b/src/main/java/de/usd/cstchef/operations/hashing/Gost.java similarity index 80% rename from src/de/usd/cstchef/operations/hashing/Gost.java rename to src/main/java/de/usd/cstchef/operations/hashing/Gost.java index 9756c4b..5215f78 100644 --- a/src/de/usd/cstchef/operations/hashing/Gost.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/Gost.java @@ -6,8 +6,8 @@ @OperationInfos(name = "Gost", category = OperationCategory.HASHING, description = "The Gost algorithm") public class Gost extends HashOperation { - public Gost() { - super("GOST-3411-2012-", "256", "512"); - } + public Gost() { + super("GOST-3411-2012-", "256", "512"); + } } diff --git a/src/main/java/de/usd/cstchef/operations/hashing/HashOperation.java b/src/main/java/de/usd/cstchef/operations/hashing/HashOperation.java new file mode 100644 index 0000000..8b134ff --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/hashing/HashOperation.java @@ -0,0 +1,47 @@ +package de.usd.cstchef.operations.hashing; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.swing.JComboBox; + +import org.bouncycastle.util.encoders.Hex; + +import de.usd.cstchef.operations.Operation; + +public abstract class HashOperation extends Operation { + + private JComboBox sizeBox; + private String algorithm; + + public HashOperation(String alogrithm) { + super(); + this.algorithm = alogrithm; + } + + public HashOperation(String alogrithm, String... sizes) { + super(); + this.algorithm = alogrithm; + createMyUI(sizes); + } + + @Override + protected byte[] perform(byte[] input) throws Exception { + return this.hash(input); + } + + protected byte[] hash(byte[] input) throws NoSuchAlgorithmException { + String algo = this.algorithm + (this.sizeBox != null ? (String) sizeBox.getSelectedItem() : ""); + + MessageDigest digest = MessageDigest.getInstance(algo); + byte[] hash = digest.digest(input); + return Hex.encode(hash); + } + + public void createMyUI(String[] sizes) { + sizeBox = new JComboBox(sizes); + sizeBox.setSelectedIndex(0); + this.addUIElement("Size", sizeBox); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/hashing/Hmac.java b/src/main/java/de/usd/cstchef/operations/hashing/Hmac.java new file mode 100644 index 0000000..88ed871 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/hashing/Hmac.java @@ -0,0 +1,39 @@ +package de.usd.cstchef.operations.hashing; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.swing.JComboBox; +import org.bouncycastle.util.encoders.Hex; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "HMAC", category = OperationCategory.HASHING, description = "Creates an HMAC with the chosen hashing function.") +public class Hmac extends Operation { + + private VariableTextField keyTxt; + private JComboBox hashAlgoBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + byte[] key = this.keyTxt.getText().getBytes(); + String algo = "Hmac" + (String) hashAlgoBox.getSelectedItem(); + SecretKeySpec signingKey = new SecretKeySpec(key, algo); + Mac mac = Mac.getInstance(algo); + mac.init(signingKey); + return Hex.encode(mac.doFinal(input)); + } + + @Override + public void createUI() { + String[] algorithms = { "MD5", "SHA1", "SHA256", "SHA224", "SHA384", "SHA512", "GOST3411" }; + this.hashAlgoBox = new JComboBox<>(algorithms); + this.addUIElement("Hashing function", this.hashAlgoBox); + + this.keyTxt = new VariableTextField(); + this.addUIElement("Key", this.keyTxt); + } + +} diff --git a/src/de/usd/cstchef/operations/hashing/MD2.java b/src/main/java/de/usd/cstchef/operations/hashing/MD2.java similarity index 86% rename from src/de/usd/cstchef/operations/hashing/MD2.java rename to src/main/java/de/usd/cstchef/operations/hashing/MD2.java index b00c7ad..d178e9e 100644 --- a/src/de/usd/cstchef/operations/hashing/MD2.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/MD2.java @@ -5,9 +5,9 @@ @OperationInfos(name = "MD2", category = OperationCategory.HASHING, description = "The MD2 (Message-Digest 2) algorithm") public class MD2 extends HashOperation { - - public MD2() { - super("MD2"); - } - + + public MD2() { + super("MD2"); + } + } diff --git a/src/de/usd/cstchef/operations/hashing/MD4.java b/src/main/java/de/usd/cstchef/operations/hashing/MD4.java similarity index 87% rename from src/de/usd/cstchef/operations/hashing/MD4.java rename to src/main/java/de/usd/cstchef/operations/hashing/MD4.java index e1e8103..3719dbe 100644 --- a/src/de/usd/cstchef/operations/hashing/MD4.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/MD4.java @@ -6,8 +6,8 @@ @OperationInfos(name = "MD4", category = OperationCategory.HASHING, description = "The MD4 (Message-Digest 4) algorithm") public class MD4 extends HashOperation { - public MD4() { - super("MD4"); - } + public MD4() { + super("MD4"); + } } diff --git a/src/de/usd/cstchef/operations/hashing/MD5.java b/src/main/java/de/usd/cstchef/operations/hashing/MD5.java similarity index 86% rename from src/de/usd/cstchef/operations/hashing/MD5.java rename to src/main/java/de/usd/cstchef/operations/hashing/MD5.java index 40d5fd3..2771957 100644 --- a/src/de/usd/cstchef/operations/hashing/MD5.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/MD5.java @@ -5,10 +5,10 @@ @OperationInfos(name = "MD5", category = OperationCategory.HASHING, description = "The MD5 (Message-Digest 5) algorithm") public class MD5 extends HashOperation { - - public MD5() { - super("MD5"); - } - + + public MD5() { + super("MD5"); + } + } diff --git a/src/de/usd/cstchef/operations/hashing/RIPEMD.java b/src/main/java/de/usd/cstchef/operations/hashing/RIPEMD.java similarity index 80% rename from src/de/usd/cstchef/operations/hashing/RIPEMD.java rename to src/main/java/de/usd/cstchef/operations/hashing/RIPEMD.java index bee5ed7..4f77e32 100644 --- a/src/de/usd/cstchef/operations/hashing/RIPEMD.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/RIPEMD.java @@ -6,8 +6,8 @@ @OperationInfos(name = "RIPEMD", category = OperationCategory.HASHING, description = "The RIPEMD algorithm") public class RIPEMD extends HashOperation { - public RIPEMD() { - super("RIPEMD", "256", "128", "160"); - } + public RIPEMD() { + super("RIPEMD", "256", "128", "160"); + } } \ No newline at end of file diff --git a/src/de/usd/cstchef/operations/hashing/SHA1.java b/src/main/java/de/usd/cstchef/operations/hashing/SHA1.java similarity index 85% rename from src/de/usd/cstchef/operations/hashing/SHA1.java rename to src/main/java/de/usd/cstchef/operations/hashing/SHA1.java index beb6d48..a6e650b 100644 --- a/src/de/usd/cstchef/operations/hashing/SHA1.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/SHA1.java @@ -5,9 +5,9 @@ @OperationInfos(name = "SHA1", category = OperationCategory.HASHING, description = "The SHA1 algorithm") public class SHA1 extends HashOperation { - - public SHA1() { - super("SHA1"); - } + + public SHA1() { + super("SHA1"); + } } diff --git a/src/de/usd/cstchef/operations/hashing/SHA2.java b/src/main/java/de/usd/cstchef/operations/hashing/SHA2.java similarity index 75% rename from src/de/usd/cstchef/operations/hashing/SHA2.java rename to src/main/java/de/usd/cstchef/operations/hashing/SHA2.java index 1377935..568e6c9 100644 --- a/src/de/usd/cstchef/operations/hashing/SHA2.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/SHA2.java @@ -6,8 +6,8 @@ @OperationInfos(name = "SHA2", category = OperationCategory.HASHING, description = "The SHA2 algorithm") public class SHA2 extends HashOperation { - public SHA2() { - super("SHA-", "224", "256", "384", "512", "512/224", "512/256"); - } + public SHA2() { + super("SHA-", "224", "256", "384", "512", "512/224", "512/256"); + } } diff --git a/src/de/usd/cstchef/operations/hashing/SHA3.java b/src/main/java/de/usd/cstchef/operations/hashing/SHA3.java similarity index 79% rename from src/de/usd/cstchef/operations/hashing/SHA3.java rename to src/main/java/de/usd/cstchef/operations/hashing/SHA3.java index 655fc35..1024cff 100644 --- a/src/de/usd/cstchef/operations/hashing/SHA3.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/SHA3.java @@ -6,8 +6,8 @@ @OperationInfos(name = "SHA3", category = OperationCategory.HASHING, description = "The SHA3 algorithm") public class SHA3 extends HashOperation { - public SHA3() { - super("SHA3-", "224", "256", "384", "512"); - } - + public SHA3() { + super("SHA3-", "224", "256", "384", "512"); + } + } diff --git a/src/de/usd/cstchef/operations/hashing/Skein.java b/src/main/java/de/usd/cstchef/operations/hashing/Skein.java similarity index 60% rename from src/de/usd/cstchef/operations/hashing/Skein.java rename to src/main/java/de/usd/cstchef/operations/hashing/Skein.java index e3ea2b3..c4538d5 100644 --- a/src/de/usd/cstchef/operations/hashing/Skein.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/Skein.java @@ -6,8 +6,8 @@ @OperationInfos(name = "Skein", category = OperationCategory.HASHING, description = "The Skein algorithm") public class Skein extends HashOperation { - public Skein() { - super("Skein-", "256-128", "256-160", "256-224", "256-256", "512-128", "512-160", "512-224", "512-256", "512-384", "512-512", "1024-384", "1024-512", "1024-1024"); - } - + public Skein() { + super("Skein-", "256-128", "256-160", "256-224", "256-256", "512-128", "512-160", "512-224", "512-256", "512-384", "512-512", "1024-384", "1024-512", "1024-1024"); + } + } diff --git a/src/de/usd/cstchef/operations/hashing/Tiger.java b/src/main/java/de/usd/cstchef/operations/hashing/Tiger.java similarity index 85% rename from src/de/usd/cstchef/operations/hashing/Tiger.java rename to src/main/java/de/usd/cstchef/operations/hashing/Tiger.java index 162f50c..3b9f4ba 100644 --- a/src/de/usd/cstchef/operations/hashing/Tiger.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/Tiger.java @@ -6,8 +6,8 @@ @OperationInfos(name = "Tiger", category = OperationCategory.HASHING, description = "The Tiger algorithm") public class Tiger extends HashOperation { - public Tiger() { - super("Tiger"); - } - + public Tiger() { + super("Tiger"); + } + } diff --git a/src/de/usd/cstchef/operations/hashing/Whirlpool.java b/src/main/java/de/usd/cstchef/operations/hashing/Whirlpool.java similarity index 84% rename from src/de/usd/cstchef/operations/hashing/Whirlpool.java rename to src/main/java/de/usd/cstchef/operations/hashing/Whirlpool.java index 5f32952..2e7ff1f 100644 --- a/src/de/usd/cstchef/operations/hashing/Whirlpool.java +++ b/src/main/java/de/usd/cstchef/operations/hashing/Whirlpool.java @@ -6,8 +6,8 @@ @OperationInfos(name = "Whirlpool", category = OperationCategory.HASHING, description = "The Whirlpool algorithm") public class Whirlpool extends HashOperation { - public Whirlpool() { - super("WHIRLPOOL"); - } + public Whirlpool() { + super("WHIRLPOOL"); + } } diff --git a/src/main/java/de/usd/cstchef/operations/misc/ReadFile.java b/src/main/java/de/usd/cstchef/operations/misc/ReadFile.java new file mode 100644 index 0000000..f40acee --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/misc/ReadFile.java @@ -0,0 +1,52 @@ +package de.usd.cstchef.operations.misc; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileInputStream; +import javax.swing.JButton; +import javax.swing.JFileChooser; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "Read File", category = OperationCategory.MISC, description = "Reads data from a file.") +public class ReadFile extends Operation implements ActionListener { + + private final JFileChooser fileChooser = new JFileChooser(); + private VariableTextField fileNameTxt; + + @Override + protected byte[] perform(byte[] input) throws Exception { + String path = fileNameTxt.getText(); + + File file = new File(path); + FileInputStream fis = new FileInputStream(file); + byte[] data = new byte[(int) file.length()]; + fis.read(data); + fis.close(); + + return data; + } + + public void createUI() { + this.fileNameTxt = new VariableTextField(); + this.addUIElement("Filename", this.fileNameTxt); + + JButton chooseFileButton = new JButton("Select file"); + chooseFileButton.addActionListener(this); + this.addUIElement(null, chooseFileButton, false, "button1"); + } + + @Override + public void actionPerformed(ActionEvent e) { + int returnVal = fileChooser.showOpenDialog(this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fileChooser.getSelectedFile(); + this.fileNameTxt.setText(file.getAbsolutePath()); + } + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/misc/WriteFile.java b/src/main/java/de/usd/cstchef/operations/misc/WriteFile.java new file mode 100644 index 0000000..f2cf7bb --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/misc/WriteFile.java @@ -0,0 +1,78 @@ +package de.usd.cstchef.operations.misc; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.swing.JButton; +import javax.swing.JFileChooser; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "Write File", category = OperationCategory.MISC, description = "Appends data to the end of a file.") +public class WriteFile extends Operation implements ActionListener { + + private final JFileChooser fileChooser = new JFileChooser(); + private VariableTextField fileNameTxt; + private String lastPath = ""; + private FileOutputStream out; + + @Override + protected byte[] perform(byte[] input) throws Exception { + String path = fileNameTxt.getText(); + + if (!lastPath.equals(path)) { + if (out != null) { + out.close(); + out = null; + } + if (!path.isEmpty()) { + out = new FileOutputStream(path); + } + lastPath = path; + } + + if (out != null) { + out.write(input); + out.write('\n'); + } + + return input; + } + + public void createUI() { + this.fileNameTxt = new VariableTextField(); + this.fileNameTxt.setEditable(false); + this.addUIElement("Filename", this.fileNameTxt); + + JButton chooseFileButton = new JButton("Select file"); + chooseFileButton.addActionListener(this); + this.addUIElement(null, chooseFileButton, false, "button1"); + } + + + @Override + public void actionPerformed(ActionEvent e) { + int returnVal = fileChooser.showOpenDialog(this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fileChooser.getSelectedFile(); + this.fileNameTxt.setText(file.getAbsolutePath()); + } + } + + @Override + public void onRemove() { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + } + } + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/networking/HTTPRequest.java b/src/main/java/de/usd/cstchef/operations/networking/HTTPRequest.java new file mode 100644 index 0000000..d76335c --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/networking/HTTPRequest.java @@ -0,0 +1,43 @@ +package de.usd.cstchef.operations.networking; + +import javax.swing.JCheckBox; +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IHttpRequestResponse; +import burp.IHttpService; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "HTTP Request", category = OperationCategory.NETWORKING, description = "Makes an http reqeust and returns the response.") +public class HTTPRequest extends Operation { + + private VariableTextField hostTxt; + private VariableTextField portTxt; + private JCheckBox sslEnabledBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helper = callbacks.getHelpers(); + String protocol = sslEnabledBox.isSelected() ? "https" : "http"; + IHttpService service = helper.buildHttpService(hostTxt.getText(), Integer.valueOf(portTxt.getText()), protocol); + IHttpRequestResponse response = callbacks.makeHttpRequest(service, input); + return response.getResponse(); + } + + @Override + public void createUI() { + this.hostTxt = new VariableTextField(); + this.addUIElement("Host", this.hostTxt); + + this.portTxt = new VariableTextField(); + this.addUIElement("Port", this.portTxt); + + this.sslEnabledBox = new JCheckBox(); + this.addUIElement("SSL", this.sslEnabledBox); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/HttpGetSetter.java b/src/main/java/de/usd/cstchef/operations/setter/HttpGetSetter.java new file mode 100644 index 0000000..c241dcf --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/HttpGetSetter.java @@ -0,0 +1,66 @@ +package de.usd.cstchef.operations.setter; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IParameter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP GET Param", category = OperationCategory.SETTER, description = "Sets a GET parameter to the specified value.") +public class HttpGetSetter extends SetterOperation { + + private JCheckBox addIfNotPresent; + private JCheckBox urlEncode; + private JCheckBox urlEncodeAll; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + String parameterName = getWhere(); + if( parameterName.equals("") ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + byte[] newValue = getWhatBytes(); + + if( urlEncodeAll.isSelected() || urlEncode.isSelected() ) + newValue = urlEncode(newValue, urlEncodeAll.isSelected(), helpers); + + IParameter param = getParameter(input, parameterName, IParameter.PARAM_URL, helpers); + + if( param == null ) { + + if( !addIfNotPresent.isSelected() ) + return input; + + param = helpers.buildParameter(parameterName, "dummy", IParameter.PARAM_URL); + input = helpers.addParameter(input, param); + param = getParameter(input, parameterName, IParameter.PARAM_URL, helpers); + } + + byte[] newRequest = replaceParam(input, param, newValue); + return newRequest; + } + + @Override + public void createUI() { + super.createUI(); + + this.urlEncode = new JCheckBox("URL encode"); + this.urlEncode.setSelected(false); + this.addUIElement(null, this.urlEncode, "checkbox1"); + + this.urlEncodeAll = new JCheckBox("URL encode all"); + this.urlEncodeAll.setSelected(false); + this.addUIElement(null, this.urlEncodeAll, "checkbox2"); + + this.addIfNotPresent = new JCheckBox("Add if not present"); + this.addIfNotPresent.setSelected(true); + this.addUIElement(null, this.addIfNotPresent, "checkbox3"); + } +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/HttpHeaderSetter.java b/src/main/java/de/usd/cstchef/operations/setter/HttpHeaderSetter.java new file mode 100644 index 0000000..9feb7e1 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/HttpHeaderSetter.java @@ -0,0 +1,66 @@ +package de.usd.cstchef.operations.setter; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IRequestInfo; +import de.usd.cstchef.Utils; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP Header", category = OperationCategory.SETTER, description = "Set a HTTP header to the specified value.") +public class HttpHeaderSetter extends SetterOperation { + + private JCheckBox addIfNotPresent; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] newValue = getWhatBytes(); + byte[] headerName = getWhereBytes(); + if( headerName.length == 0 ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + byte[] headerSearch = new byte[headerName.length + 2]; + System.arraycopy(headerName, 0, headerSearch, 0, headerName.length); + System.arraycopy(": ".getBytes(), 0, headerSearch, headerName.length, 2); + + try { + + int offset = helpers.indexOf(input, headerSearch, false, 0, length); + int start = helpers.indexOf(input, ": ".getBytes(), false, offset, length) + 2; + int end = helpers.indexOf(input, "\r\n".getBytes(), false, start, length); + return Utils.insertAtOffset(input, start, end, newValue); + + } catch( IllegalArgumentException e ) { + + if( !addIfNotPresent.isSelected() ) + return input; + + IRequestInfo info = helpers.analyzeRequest(input); + int bodyOffset = info.getBodyOffset() - 2; + + byte[] value = new byte[headerSearch.length + newValue.length + 2]; + System.arraycopy(headerSearch, 0, value, 0, headerSearch.length); + System.arraycopy(newValue, 0, value, headerName.length + 2, newValue.length); + System.arraycopy("\r\n".getBytes(), 0, value, headerName.length + 2 + newValue.length, 2); + return Utils.insertAtOffset(input, bodyOffset, bodyOffset, value); + + } + } + + @Override + public void createUI() { + super.createUI(); + this.addIfNotPresent = new JCheckBox("Add if not present"); + this.addIfNotPresent.setSelected(true); + this.addUIElement(null, this.addIfNotPresent, "checkbox1"); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/HttpJsonSetter.java b/src/main/java/de/usd/cstchef/operations/setter/HttpJsonSetter.java new file mode 100644 index 0000000..542e92c --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/HttpJsonSetter.java @@ -0,0 +1,33 @@ +package de.usd.cstchef.operations.setter; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IParameter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP JSON", category = OperationCategory.SETTER, description = "Set a JSON parameter to the specified value.") +public class HttpJsonSetter extends SetterOperation { + + @Override + protected byte[] perform(byte[] input) throws Exception { + + String parameterName = getWhere(); + if( parameterName.equals("") ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + byte[] newValue = getWhatBytes(); + IParameter param = getParameter(input, parameterName, IParameter.PARAM_JSON, helpers); + + if( param == null ) + return input; + + byte[] newRequest = replaceParam(input, param, newValue); + return newRequest; + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/HttpPostSetter.java b/src/main/java/de/usd/cstchef/operations/setter/HttpPostSetter.java new file mode 100644 index 0000000..8dc1158 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/HttpPostSetter.java @@ -0,0 +1,71 @@ +package de.usd.cstchef.operations.setter; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IParameter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP POST Param", category = OperationCategory.SETTER, description = "Set a POST parameter to the specified value.") +public class HttpPostSetter extends SetterOperation { + + private JCheckBox addIfNotPresent; + private JCheckBox urlEncode; + private JCheckBox urlEncodeAll; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + String parameterName = getWhere(); + if( parameterName.equals("") ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + byte[] newValue = getWhatBytes(); + + if( urlEncodeAll.isSelected() || urlEncode.isSelected() ) + newValue = urlEncode(newValue, urlEncodeAll.isSelected(), helpers); + + IParameter param = getParameter(input, parameterName, IParameter.PARAM_BODY, helpers); + + if( param == null ) { + + if( !addIfNotPresent.isSelected() ) + return input; + + param = helpers.buildParameter(parameterName, "dummy", IParameter.PARAM_BODY); + input = helpers.addParameter(input, param); + param = getParameter(input, parameterName, IParameter.PARAM_BODY, helpers); + if( param == null ) + // This case occurs when the HTTP request is a JSON or XML request. Burp does not + // support adding parameters to these and therefore the request should stay unmodified. + throw new IllegalArgumentException("Failure while adding the parameter. Operation cannot be used on XML or JSON."); + } + + byte[] newRequest = replaceParam(input, param, newValue); + return newRequest; + } + + @Override + public void createUI() { + super.createUI(); + + this.urlEncode = new JCheckBox("URL encode"); + this.urlEncode.setSelected(false); + this.addUIElement(null, this.urlEncode, "checkbox1"); + + this.urlEncodeAll = new JCheckBox("URL encode all"); + this.urlEncodeAll.setSelected(false); + this.addUIElement(null, this.urlEncodeAll, "checkbox2"); + + this.addIfNotPresent = new JCheckBox("Add if not present"); + this.addIfNotPresent.setSelected(true); + this.addUIElement(null, this.addIfNotPresent, "checkbox3"); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/HttpSetBody.java b/src/main/java/de/usd/cstchef/operations/setter/HttpSetBody.java new file mode 100644 index 0000000..b07ff2e --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/HttpSetBody.java @@ -0,0 +1,39 @@ +package de.usd.cstchef.operations.setter; + +import java.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IRequestInfo; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.FormatTextField; + +@OperationInfos(name = "HTTP Body", category = OperationCategory.SETTER, description = "Set the HTTP body to the specified value.") +public class HttpSetBody extends Operation { + + private FormatTextField replacementTxt; + + @Override + protected byte[] perform(byte[] input) throws Exception { + IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); + IRequestInfo requestInfo = cbs.getHelpers().analyzeRequest(input); + int bodyOffset = requestInfo.getBodyOffset(); + + byte[] noBody = Arrays.copyOfRange(input, 0, bodyOffset); + byte[] newBody = replacementTxt.getText(); + byte[] newRequest = new byte[noBody.length + newBody.length]; + System.arraycopy(noBody, 0, newRequest, 0, noBody.length); + System.arraycopy(newBody, 0, newRequest, noBody.length, newBody.length); + + return newRequest; + } + + @Override + public void createUI() { + this.replacementTxt = new FormatTextField(); + this.addUIElement("Body", this.replacementTxt); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/HttpSetCookie.java b/src/main/java/de/usd/cstchef/operations/setter/HttpSetCookie.java new file mode 100644 index 0000000..2c8a3a5 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/HttpSetCookie.java @@ -0,0 +1,92 @@ +package de.usd.cstchef.operations.setter; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IResponseInfo; +import de.usd.cstchef.Utils; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP Cookie", category = OperationCategory.SETTER, description = "Set a HTTP cookie to the specified value.") +public class HttpSetCookie extends SetterOperation { + + private JCheckBox addIfNotPresent; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] newValue = getWhatBytes(); + byte[] cookieName = getWhereBytes(); + if( cookieName.length == 0 ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + byte[] cookieSearch = new byte[cookieName.length + 1]; + System.arraycopy(cookieName, 0, cookieSearch, 0, cookieName.length); + System.arraycopy("=".getBytes(), 0, cookieSearch, cookieName.length, 1); + + IResponseInfo resp = helpers.analyzeResponse(input); + boolean isRequest = (resp.getStatusCode() == 0); + + String cookieHeader = "\r\nSet-Cookie: "; + if(isRequest) + cookieHeader = "\r\nCookie: "; + + int offset = -1; + int cookieHeaderLength = cookieHeader.length(); + + try { + + offset = helpers.indexOf(input, cookieHeader.getBytes(), false, 0, length); + int line_end = helpers.indexOf(input, "\r\n".getBytes(), false, offset + 2, length); + int start = helpers.indexOf(input, cookieSearch, true, offset, line_end); + int end = helpers.indexOf(input, ";".getBytes(), true, start, line_end); + + if( end < 0 ) + end = line_end; + + return Utils.insertAtOffset(input, start + cookieSearch.length, end, newValue); + + } catch( IllegalArgumentException e ) { + + if( !addIfNotPresent.isSelected() ) + return input; + + if( (offset > 0) && isRequest ) { + + byte[] value = new byte[cookieName.length + newValue.length + 3]; + System.arraycopy(cookieName, 0, value, 0, cookieName.length); + System.arraycopy("=".getBytes(), 0, value, cookieName.length, 1); + System.arraycopy(newValue, 0, value, cookieName.length + 1, newValue.length); + System.arraycopy("; ".getBytes(), 0, value, cookieName.length + 1 + newValue.length, 2); + return Utils.insertAtOffset(input, offset + cookieHeaderLength, offset + cookieHeaderLength, value); + + } else { + + int bodyOffset = resp.getBodyOffset() - 4; + byte[] value = new byte[cookieName.length + newValue.length + cookieHeaderLength + 2]; + System.arraycopy(cookieHeader.getBytes(), 0, value, 0, cookieHeaderLength); + System.arraycopy(cookieName, 0, value, cookieHeaderLength, cookieName.length); + System.arraycopy("=".getBytes(), 0, value, cookieHeaderLength + cookieName.length, 1); + System.arraycopy(newValue, 0, value, cookieHeaderLength + cookieName.length + 1, newValue.length); + System.arraycopy(";".getBytes(), 0, value, cookieHeaderLength + cookieName.length + 1 + newValue.length, 1); + return Utils.insertAtOffset(input, bodyOffset, bodyOffset, value); + } + } + } + + @Override + public void createUI() { + super.createUI(); + this.addIfNotPresent = new JCheckBox("Add if not present"); + this.addIfNotPresent.setSelected(true); + this.addUIElement(null, this.addIfNotPresent, "checkbox1"); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/HttpSetUri.java b/src/main/java/de/usd/cstchef/operations/setter/HttpSetUri.java new file mode 100644 index 0000000..348d4c0 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/HttpSetUri.java @@ -0,0 +1,64 @@ +package de.usd.cstchef.operations.setter; + +import java.util.Arrays; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "HTTP URI", category = OperationCategory.SETTER, description = "Sets the specified variable as the uri.") +public class HttpSetUri extends Operation { + + private VariableTextField uriTxt; + private JCheckBox checkbox; + + @Override + public void createUI() { + this.uriTxt = new VariableTextField(); + this.addUIElement("Uri", this.uriTxt); + + this.checkbox = new JCheckBox("Keep parameters"); + this.checkbox.setSelected(false); + this.addUIElement(null, this.checkbox, "checkbox1"); + } + + + @Override + protected byte[] perform(byte[] input) throws Exception { + try { + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + int firstMark = helpers.indexOf(input, " ".getBytes(), false, 0, length); + int lineMark = helpers.indexOf(input, " ".getBytes(), false, firstMark + 1, length); + + int secondMark = helpers.indexOf(input, "?".getBytes(), false, firstMark + 1, length); + + if( !this.checkbox.isSelected() || secondMark < 0 || secondMark >= lineMark ) { + secondMark = lineMark; + } + + byte[] method = Arrays.copyOfRange(input, 0, firstMark + 1); + byte[] newUri = this.uriTxt.getBytes(); + byte[] rest = Arrays.copyOfRange(input, secondMark, length); + + byte[] newRequest = new byte[method.length + newUri.length + rest.length]; + System.arraycopy(method, 0, newRequest, 0, method.length); + System.arraycopy(newUri, 0, newRequest, method.length, newUri.length); + System.arraycopy(rest, 0, newRequest, method.length + newUri.length, rest.length); + + return newRequest; + + } catch (Exception e) { + throw new IllegalArgumentException("Provided input is not a valid http request."); + } + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/HttpXmlSetter.java b/src/main/java/de/usd/cstchef/operations/setter/HttpXmlSetter.java new file mode 100644 index 0000000..a291fa4 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/HttpXmlSetter.java @@ -0,0 +1,33 @@ +package de.usd.cstchef.operations.setter; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IParameter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "HTTP XML", category = OperationCategory.SETTER, description = "Set a XML parameter to the specified value.") +public class HttpXmlSetter extends SetterOperation { + + @Override + protected byte[] perform(byte[] input) throws Exception { + + String parameterName = getWhere(); + if( parameterName.equals("") ) + return input; + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + byte[] newValue = getWhatBytes(); + IParameter param = getParameter(input, parameterName, IParameter.PARAM_XML, helpers); + + if( param == null ) + return input; + + byte[] newRequest = replaceParam(input, param, newValue); + return newRequest; + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/JsonSetter.java b/src/main/java/de/usd/cstchef/operations/setter/JsonSetter.java new file mode 100644 index 0000000..d22d0e8 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/JsonSetter.java @@ -0,0 +1,91 @@ +package de.usd.cstchef.operations.setter; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +import javax.swing.JCheckBox; + +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "JSON", category = OperationCategory.SETTER, description = "Set value of json object.") +public class JsonSetter extends SetterOperation implements ActionListener { + + private JCheckBox addIfNotPresent; + private VariableTextField path; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + if( getWhere().equals("") ) + return input; + + DocumentContext document = JsonPath.parse(new String(input)); + + try { + document.read(getWhere()); + } catch( Exception e ) { + + if( !addIfNotPresent.isSelected() ) + throw new IllegalArgumentException("Key not found."); + + String insertPath = this.path.getText(); + if( insertPath.equals("Insert-Path") || insertPath.equals("") ) + insertPath = "$"; + + document = document.put(insertPath, getWhere(), getWhat()); + return document.jsonString().getBytes(); + } + + document.set(getWhere(), getWhat()); + return document.jsonString().getBytes(); + } + + @Override + public void createUI() { + super.createUI(); + this.addIfNotPresent = new JCheckBox("Add if not present"); + this.addIfNotPresent.setSelected(true); + this.addIfNotPresent.addActionListener(this); + this.addUIElement(null, this.addIfNotPresent, "checkbox1"); + + this.path = new VariableTextField(); + this.path.setText("Insert-Path"); + this.path.setForeground(Color.GRAY); + this.path.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + if (path.getText().equals("Insertion Path")) { + path.setText(""); + path.setForeground(null); + } + } + @Override + public void focusLost(FocusEvent e) { + if (path.getText().isEmpty()) { + path.setForeground(Color.GRAY); + path.setText("Insertion Path"); + } + } + }); + this.addUIElement(null, this.path, "textbox1"); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + if( arg0.getSource() == this.addIfNotPresent ) { + if( this.addIfNotPresent.isSelected() ) { + this.path.setEditable(true); + } else { + this.path.setEditable(false); + } + } + } +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/LineSetter.java b/src/main/java/de/usd/cstchef/operations/setter/LineSetter.java new file mode 100644 index 0000000..9ef1b1e --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/LineSetter.java @@ -0,0 +1,92 @@ +package de.usd.cstchef.operations.setter; + +import java.util.Arrays; + +import javax.swing.JCheckBox; +import javax.swing.JComboBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.Utils; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "Line Setter", category = OperationCategory.SETTER, description = "Sets a line to the specified value.") +public class LineSetter extends SetterOperation { + + private JCheckBox append; + private JComboBox formatBox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + int lineNumber; + try { + String number = getWhere(); + lineNumber = Integer.valueOf(number); + } catch( Exception e ) { + return input; + } + + if( lineNumber <= 0 ) + return input; + + byte[] newValue = getWhatBytes(); + byte[] lineEndings = "\r\n".getBytes(); + switch ((String) this.formatBox.getSelectedItem()) { + case "\\r\\n": + lineEndings = "\r\n".getBytes(); + break; + case "\\r": + lineEndings = "\r".getBytes(); + break; + case "\\n": + lineEndings = "\n".getBytes(); + break; + } + + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + int length = input.length; + + int start = 0; + int offset = 0; + int counter = 0; + while( counter < lineNumber - 1 ) { + offset = helpers.indexOf(input, lineEndings, false, start, length); + if( offset >= 0 ) { + start = offset + lineEndings.length; + counter++; + } else { + break; + } + } + + int end = helpers.indexOf(input, lineEndings, false, start, length); + if( end < 0 ) + end = length; + + if( append.isSelected() ) { + byte[] value = new byte[newValue.length + lineEndings.length]; + System.arraycopy(lineEndings, 0, value, 0, lineEndings.length); + System.arraycopy(newValue, 0, value, lineEndings.length, newValue.length); + return Utils.insertAtOffset(input, end, end, value); + } else { + return Utils.insertAtOffset(input, start, end, newValue); + } + } + + @Override + public void createUI() { + super.createUI(); + this.append = new JCheckBox("Insert below"); + this.append.setSelected(false); + this.addUIElement(null, this.append, "checkbox1"); + + this.formatBox = new JComboBox<>(new String[] {"\\r\\n", "\\r", "\\n"}); + this.formatBox.setSelectedItem("\\r\\n"); + this.addUIElement("Lineseperator", this.formatBox); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/setter/SetterOperation.java b/src/main/java/de/usd/cstchef/operations/setter/SetterOperation.java new file mode 100644 index 0000000..2a6aafb --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/setter/SetterOperation.java @@ -0,0 +1,104 @@ +package de.usd.cstchef.operations.setter; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.bouncycastle.util.encoders.Hex; + +import burp.IExtensionHelpers; +import burp.IParameter; +import burp.IRequestInfo; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.view.ui.VariableTextField; + +public abstract class SetterOperation extends Operation { + + private VariableTextField whereToSet; + private VariableTextField whatToSet; + + @Override + public void createUI() { + this.whereToSet = new VariableTextField(); + this.whatToSet = new VariableTextField(); + this.addUIElement("Key", this.whereToSet); + this.addUIElement("Value", this.whatToSet); + } + + protected String getWhere() { + return whereToSet.getText(); + } + + protected byte[] getWhereBytes() { + return whereToSet.getBytes(); + } + + protected String getWhat() { + return whatToSet.getText(); + } + + protected byte[] getWhatBytes() { + return whatToSet.getBytes(); + } + + // This is required because Burps getRequestParameter returns always the first occurrence of the parameter name. + // If you have e.g. a cookie with the same name as the POST parameter, you have no chance of getting the POST + // parameter using getRequestParameter (at least I do not know how). + protected IParameter getParameter(byte[] request, String paramName, byte type, IExtensionHelpers helpers) { + + IRequestInfo info = helpers.analyzeRequest(request); + List parameters = info.getParameters(); + IParameter param = null; + + for(IParameter p:parameters) { + if( p.getName().equals(paramName) ) + if( p.getType() == type ) { + param = p; + break; + } + } + return param; + } + + protected byte[] urlEncode(byte[] input, boolean all, IExtensionHelpers helpers) throws IOException { + + byte[] newValue = input; + + if( all ) { + byte[] delimiter = "%".getBytes(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(delimiter); + + for (int i = 0; i < newValue.length - 1; i++) { + out.write(Hex.encode(new byte[] { newValue[i] })); + out.write(delimiter); + } + + out.write(Hex.encode(new byte[] { newValue[newValue.length - 1] })); + newValue = out.toByteArray(); + + } else { + newValue = helpers.urlEncode(input); + } + + return newValue; + } + + protected byte[] replaceParam(byte[] request, IParameter param, byte[] newValue) { + + int length = request.length; + int start = param.getValueStart(); + int end = param.getValueEnd(); + + byte[] prefix = Arrays.copyOfRange(request, 0, start); + byte[] rest = Arrays.copyOfRange(request, end, length); + + byte[] newRequest = new byte[prefix.length + newValue.length + rest.length]; + System.arraycopy(prefix, 0, newRequest, 0, prefix.length); + System.arraycopy(newValue, 0, newRequest, prefix.length, newValue.length); + System.arraycopy(rest, 0, newRequest, prefix.length + newValue.length, rest.length); + + return newRequest; + } +} diff --git a/src/de/usd/cstchef/operations/signature/KeystoreOperation.java b/src/main/java/de/usd/cstchef/operations/signature/KeystoreOperation.java similarity index 53% rename from src/de/usd/cstchef/operations/signature/KeystoreOperation.java rename to src/main/java/de/usd/cstchef/operations/signature/KeystoreOperation.java index fc4911e..090aa78 100644 --- a/src/de/usd/cstchef/operations/signature/KeystoreOperation.java +++ b/src/main/java/de/usd/cstchef/operations/signature/KeystoreOperation.java @@ -24,7 +24,7 @@ public abstract class KeystoreOperation extends Operation implements ActionListe protected String[] keyStoreTypes = new String[] {"JKS", "PKCS12"}; protected VariableTextField fileNameTxt; - protected JPasswordField keyStorePass; + protected JPasswordField keyStorePass; protected Certificate cert = null; protected KeyStore keyStore = null; @@ -36,35 +36,35 @@ public abstract class KeystoreOperation extends Operation implements ActionListe protected JButton chooseFileButton; protected JButton openKeyStoreButton; - protected JComboBox keyEntry; - protected JComboBox keyStoreType; - protected JFileChooser fileChooser = new JFileChooser(); - - public KeystoreOperation() { - super(); - } - - private void openKeyStore() { - try { - String path = fileNameTxt.getText(); - File keyStoreFile = new File(path); - String storeType = (String)keyStoreType.getSelectedItem(); - char[] password = keyStorePass.getPassword(); - KeyStore ks = KeyStore.getInstance(storeType); - ks.load(new FileInputStream(keyStoreFile), password); - this.keyStore = ks; - this.keyStoreOpen.setSelected(true); - this.certAvailable.setSelected(false); - this.keyAvailable.setSelected(false); - this.updateKeyEntries(); - - } catch( Exception e ) { - this.resetKeyStore(); - } - } + protected JComboBox keyEntry; + protected JComboBox keyStoreType; + protected JFileChooser fileChooser = new JFileChooser(); + + public KeystoreOperation() { + super(); + } + + private void openKeyStore() { + try { + String path = fileNameTxt.getText(); + File keyStoreFile = new File(path); + String storeType = (String)keyStoreType.getSelectedItem(); + char[] password = keyStorePass.getPassword(); + KeyStore ks = KeyStore.getInstance(storeType); + ks.load(new FileInputStream(keyStoreFile), password); + this.keyStore = ks; + this.keyStoreOpen.setSelected(true); + this.certAvailable.setSelected(false); + this.keyAvailable.setSelected(false); + this.updateKeyEntries(); + + } catch( Exception e ) { + this.resetKeyStore(); + } + } private void updateKeyEntries(){ - try { + try { Enumeration entries = keyStore.aliases(); keyEntry.removeAllItems(); while (entries.hasMoreElements()) { @@ -91,13 +91,13 @@ private void selectKeyEntry() { char[] password = keyStorePass.getPassword(); try { - this.selectedEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(entry, new KeyStore.PasswordProtection(password)); - if ( this.selectedEntry != null ) - this.keyAvailable.setSelected(true); - else - this.keyAvailable.setSelected(false); + this.selectedEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(entry, new KeyStore.PasswordProtection(password)); + if ( this.selectedEntry != null ) + this.keyAvailable.setSelected(true); + else + this.keyAvailable.setSelected(false); } catch( Exception e) { - this.keyAvailable.setSelected(false); + this.keyAvailable.setSelected(false); } } @@ -105,70 +105,70 @@ private void selectKeyEntry() { private void resetKeyStore() { this.keyStoreOpen.setSelected(false); - this.certAvailable.setSelected(false); - this.keyAvailable.setSelected(false); + this.certAvailable.setSelected(false); + this.keyAvailable.setSelected(false); keyStore = null; selectedEntry = null; } - public void createMyUI() { - this.keyStoreType = new JComboBox<>(this.keyStoreTypes); - this.keyStoreType.addActionListener(this); - this.addUIElement("KeyStoreType", this.keyStoreType); + public void createMyUI() { + this.keyStoreType = new JComboBox<>(this.keyStoreTypes); + this.keyStoreType.addActionListener(this); + this.addUIElement("KeyStoreType", this.keyStoreType); - this.fileNameTxt = new VariableTextField(); - this.addUIElement("Filename", this.fileNameTxt); + this.fileNameTxt = new VariableTextField(); + this.addUIElement("Filename", this.fileNameTxt); - chooseFileButton = new JButton("Select file"); - chooseFileButton.addActionListener(this); - this.addUIElement(null, this.chooseFileButton, false, "button1"); + chooseFileButton = new JButton("Select file"); + chooseFileButton.addActionListener(this); + this.addUIElement(null, this.chooseFileButton, false, "button1"); - this.keyStorePass = new JPasswordField(); - this.addUIElement("PrivKeyPassword", this.keyStorePass); + this.keyStorePass = new JPasswordField(); + this.addUIElement("PrivKeyPassword", this.keyStorePass); - openKeyStoreButton = new JButton("Open keystore"); - openKeyStoreButton.addActionListener(this); - this.addUIElement(null, this.openKeyStoreButton, false, "button2"); + openKeyStoreButton = new JButton("Open keystore"); + openKeyStoreButton.addActionListener(this); + this.addUIElement(null, this.openKeyStoreButton, false, "button2"); - this.keyEntry = new JComboBox<>(keyEntries); - this.keyEntry.addActionListener(this); - this.addUIElement("KeyEntry", this.keyEntry); + this.keyEntry = new JComboBox<>(keyEntries); + this.keyEntry.addActionListener(this); + this.addUIElement("KeyEntry", this.keyEntry); this.keyStoreOpen = new JCheckBox("KeyStore Opened"); this.keyStoreOpen.setSelected(false); this.keyStoreOpen.setEnabled(false); this.keyStoreOpen.addActionListener(this); - this.addUIElement(null, this.keyStoreOpen, "noupdate-checkbox1"); - - this.certAvailable = new JCheckBox("Certificate available"); + this.addUIElement(null, this.keyStoreOpen, "noupdate-checkbox1"); + + this.certAvailable = new JCheckBox("Certificate available"); this.certAvailable.setSelected(false); this.certAvailable.setEnabled(false); - this.certAvailable.addActionListener(this); - this.addUIElement(null, this.certAvailable, "noupdate-checkbox2"); - - this.keyAvailable = new JCheckBox("PrivKey available"); + this.certAvailable.addActionListener(this); + this.addUIElement(null, this.certAvailable, "noupdate-checkbox2"); + + this.keyAvailable = new JCheckBox("PrivKey available"); this.keyAvailable.setSelected(false); this.keyAvailable.setEnabled(false); - this.keyAvailable.addActionListener(this); - this.addUIElement(null, this.keyAvailable, "noupdate-checkbox3"); + this.keyAvailable.addActionListener(this); + this.addUIElement(null, this.keyAvailable, "noupdate-checkbox3"); + + } - } + @Override + public void actionPerformed(ActionEvent arg0) { - @Override - public void actionPerformed(ActionEvent arg0) { - if( arg0.getSource() == keyStoreType ) { - + this.resetKeyStore(); } else if( arg0.getSource() == openKeyStoreButton ) { - + this.resetKeyStore(); this.openKeyStore(); } else if( arg0.getSource() == chooseFileButton ) { - + this.resetKeyStore(); int returnVal = fileChooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { @@ -178,10 +178,10 @@ public void actionPerformed(ActionEvent arg0) { } else if( arg0.getSource() == keyEntry ) { this.selectKeyEntry(); - } + } if( keyStore != null && keyEntry != null ) { this.notifyChange(); } - } + } } diff --git a/src/main/java/de/usd/cstchef/operations/signature/RsaSignature.java b/src/main/java/de/usd/cstchef/operations/signature/RsaSignature.java new file mode 100644 index 0000000..af9b959 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/signature/RsaSignature.java @@ -0,0 +1,69 @@ +package de.usd.cstchef.operations.signature; + +import java.security.Signature; + +import javax.swing.JComboBox; + +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "RSA Signature", category = OperationCategory.SIGNATURE, description = "Create an RSA signature") +public class RsaSignature extends KeystoreOperation { + + private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" }; + + protected JComboBox algos; + protected JComboBox inputMode; + protected JComboBox outputMode; + + public RsaSignature() { + super(); + this.createMyUI(); + } + + protected byte[] perform(byte[] input) throws Exception { + + if( !this.keyAvailable.isSelected() ) + throw new IllegalArgumentException("No private key available."); + + String algo = (String)algos.getSelectedItem(); + Signature signature = Signature.getInstance(algo); + + String selectedInputMode = (String)inputMode.getSelectedItem(); + String selectedOutputMode = (String)outputMode.getSelectedItem(); + + if( selectedInputMode.equals("Hex") ) + input = Hex.decode(input); + if( selectedInputMode.equals("Base64") ) + input = Base64.decode(input); + + signature.initSign(this.selectedEntry.getPrivateKey()); + signature.update(input); + byte[] result = signature.sign(); + + if( selectedOutputMode.equals("Hex") ) + result = Hex.encode(result); + if( selectedOutputMode.equals("Base64") ) + result = Base64.encode(result); + + return result; + } + + public void createMyUI() { + + super.createMyUI(); + SignatureUtils utils = SignatureUtils.getInstance(); + + this.algos = new JComboBox<>(utils.getRsaAlgos()); + this.addUIElement("Padding", this.algos); + + this.inputMode = new JComboBox<>(inOutModes); + this.addUIElement("Input", this.inputMode); + + this.outputMode = new JComboBox<>(inOutModes); + this.addUIElement("Output", this.outputMode); + } +} diff --git a/src/main/java/de/usd/cstchef/operations/signature/SignatureUtils.java b/src/main/java/de/usd/cstchef/operations/signature/SignatureUtils.java new file mode 100644 index 0000000..f474b2b --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/signature/SignatureUtils.java @@ -0,0 +1,42 @@ +package de.usd.cstchef.operations.signature; + +import java.security.Provider; +import java.security.Provider.Service; +import java.security.Security; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class SignatureUtils { + + private static SignatureUtils instance; + + private List algos; + + private SignatureUtils() { + algos = new ArrayList();; + getSignatureInfos(); + } + + private void getSignatureInfos() { + for (Provider provider : Security.getProviders()) + for (Service service : provider.getServices()) + if (service.getType().equals("Signature")) + algos.add(service.getAlgorithm()); + } + + public static SignatureUtils getInstance() { + if (instance == null) { + instance = new SignatureUtils(); + } + return instance; + } + + public String[] getAlgos() { + return algos.toArray(new String[0]); + } + public String[] getRsaAlgos() { + List rsaAlgos = algos.stream().filter(p -> p.contains("RSA")).collect(Collectors.toList()); + return rsaAlgos.toArray(new String[0]); + } +} diff --git a/src/de/usd/cstchef/operations/signature/SoapMultiSignature.java b/src/main/java/de/usd/cstchef/operations/signature/SoapMultiSignature.java similarity index 79% rename from src/de/usd/cstchef/operations/signature/SoapMultiSignature.java rename to src/main/java/de/usd/cstchef/operations/signature/SoapMultiSignature.java index 5fd344d..93c7818 100644 --- a/src/de/usd/cstchef/operations/signature/SoapMultiSignature.java +++ b/src/main/java/de/usd/cstchef/operations/signature/SoapMultiSignature.java @@ -53,26 +53,26 @@ public class SoapMultiSignature extends KeystoreOperation { public SoapMultiSignature() { super(); this.digestMethods.put("sha1", DigestMethod.SHA1); - this.digestMethods.put("sha256", DigestMethod.SHA256); - this.digestMethods.put("sha512", DigestMethod.SHA512); - this.signatureMethods.put("rsa-sha1", SignatureMethod.RSA_SHA1); + this.digestMethods.put("sha256", DigestMethod.SHA256); + this.digestMethods.put("sha512", DigestMethod.SHA512); + this.signatureMethods.put("rsa-sha1", SignatureMethod.RSA_SHA1); this.createMyUI(); } protected HashMap digestMethods = new HashMap(); - protected HashMap signatureMethods = new HashMap(); + protected HashMap signatureMethods = new HashMap(); //"rsa-sha256", SignatureMethod.RSA_SHA256, //"rsa-sha512", SignatureMethod.RSA_SHA512 protected String[] availDigestMethods = new String[] {"sha1", "sha256", "sha512"}; protected String[] availSignatureMethods = new String[] {"rsa-sha1"};//, "rsa-sha256", "rsa-sha512"}; - protected String[] includeKeyInfos = new String[] { "true", "false" }; - protected JComboBox includeKeyInfo; - protected JComboBox signatureMethod; - protected JComboBox digestMethod; - protected JButton addReferenceButton; - protected FormatTextField idIdentifier; - protected ArrayList referenceFields = new ArrayList(); + protected String[] includeKeyInfos = new String[] { "true", "false" }; + protected JComboBox includeKeyInfo; + protected JComboBox signatureMethod; + protected JComboBox digestMethod; + protected JButton addReferenceButton; + protected FormatTextField idIdentifier; + protected ArrayList referenceFields = new ArrayList(); protected JCheckBox certificate; protected JCheckBox subject; protected JCheckBox issuer; @@ -121,7 +121,7 @@ private KeyInfo getKeyInfo(XMLSignatureFactory fac, PrivateKeyEntry keyEntry) th List x509Content = new ArrayList(); if( this.subject.isSelected() ) { x509Content.add(cert.getSubjectX500Principal().getName()); - } + } if( this.serialIssuer.isSelected() ) { x509Content.add(keyInfoFac.newX509IssuerSerial(cert.getIssuerX500Principal().getName(),cert.getSerialNumber())); } @@ -139,7 +139,7 @@ private KeyInfo getKeyInfo(XMLSignatureFactory fac, PrivateKeyEntry keyEntry) th } - protected byte[] perform(byte[] input) throws Exception { + protected byte[] perform(byte[] input) throws Exception { String signMethod = (String)signatureMethod.getSelectedItem(); PrivateKeyEntry keyEntry = this.selectedEntry; @@ -158,7 +158,7 @@ protected byte[] perform(byte[] input) throws Exception { } catch( Exception e ) { throw new IllegalArgumentException("Provided Id identifier seems to be invalid."); } - DOMSignContext dsc = new DOMSignContext (keyEntry.getPrivateKey(), doc.getDocumentElement()); + DOMSignContext dsc = new DOMSignContext (keyEntry.getPrivateKey(), doc.getDocumentElement()); signature.sign(dsc); DOMSource source = new DOMSource(doc); @@ -168,52 +168,52 @@ protected byte[] perform(byte[] input) throws Exception { Transformer transformer = transformerFactory.newTransformer(); transformer.transform(source, result); return bos.toByteArray(); - } + } - public void createMyUI() { + public void createMyUI() { super.createMyUI(); - this.includeKeyInfo = new JComboBox<>(this.includeKeyInfos); - this.includeKeyInfo.addActionListener(this); - this.addUIElement("IncludeKeyInfo", this.includeKeyInfo); - + this.includeKeyInfo = new JComboBox<>(this.includeKeyInfos); + this.includeKeyInfo.addActionListener(this); + this.addUIElement("IncludeKeyInfo", this.includeKeyInfo); + this.certificate = new JCheckBox("Include Certificate"); this.certificate.setSelected(false); - this.certificate.addActionListener(this); - this.addUIElement(null, this.certificate, "checkbox1"); + this.certificate.addActionListener(this); + this.addUIElement(null, this.certificate, "checkbox1"); this.subject = new JCheckBox("Include Subject"); this.subject.setSelected(false); - this.subject.addActionListener(this); - this.addUIElement(null, this.subject, "checkbox2"); + this.subject.addActionListener(this); + this.addUIElement(null, this.subject, "checkbox2"); this.issuer = new JCheckBox("Include Issuer"); this.issuer.setSelected(false); - this.issuer.addActionListener(this); - this.addUIElement(null, this.issuer, "checkbox3"); + this.issuer.addActionListener(this); + this.addUIElement(null, this.issuer, "checkbox3"); this.serialIssuer = new JCheckBox("Include Issuer"); this.serialIssuer.setSelected(false); - this.serialIssuer.addActionListener(this); - this.addUIElement(null, this.serialIssuer, "checkbox4"); - - this.digestMethod = new JComboBox(this.availDigestMethods); - this.digestMethod.addActionListener(this); - this.addUIElement("DigestMethod", this.digestMethod); - - this.signatureMethod = new JComboBox(this.availSignatureMethods); - this.signatureMethod.addActionListener(this); - this.addUIElement("SignatureMethod", this.signatureMethod); - - this.idIdentifier = new FormatTextField(); - this.addUIElement("Identifier", this.idIdentifier); - - addReferenceButton = new JButton("Add Reference"); - addReferenceButton.addActionListener(this); - this.addUIElement(null, addReferenceButton, false, "button1"); - } - - public void actionPerformed(ActionEvent arg0) { + this.serialIssuer.addActionListener(this); + this.addUIElement(null, this.serialIssuer, "checkbox4"); + + this.digestMethod = new JComboBox(this.availDigestMethods); + this.digestMethod.addActionListener(this); + this.addUIElement("DigestMethod", this.digestMethod); + + this.signatureMethod = new JComboBox(this.availSignatureMethods); + this.signatureMethod.addActionListener(this); + this.addUIElement("SignatureMethod", this.signatureMethod); + + this.idIdentifier = new FormatTextField(); + this.addUIElement("Identifier", this.idIdentifier); + + addReferenceButton = new JButton("Add Reference"); + addReferenceButton.addActionListener(this); + this.addUIElement(null, addReferenceButton, false, "button1"); + } + + public void actionPerformed(ActionEvent arg0) { if( arg0.getSource() == addReferenceButton ) { FormatTextField tmpRef = new FormatTextField(); this.addUIElement("Reference", tmpRef); @@ -233,5 +233,5 @@ public void actionPerformed(ActionEvent arg0) { } } super.actionPerformed(arg0); - } + } } diff --git a/src/de/usd/cstchef/operations/signature/XmlFullSignature.java b/src/main/java/de/usd/cstchef/operations/signature/XmlFullSignature.java similarity index 88% rename from src/de/usd/cstchef/operations/signature/XmlFullSignature.java rename to src/main/java/de/usd/cstchef/operations/signature/XmlFullSignature.java index ee18316..7f9071f 100644 --- a/src/de/usd/cstchef/operations/signature/XmlFullSignature.java +++ b/src/main/java/de/usd/cstchef/operations/signature/XmlFullSignature.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; @@ -21,9 +22,11 @@ public XmlFullSignature() { super(); } - protected byte[] perform(byte[] input) throws Exception { + protected byte[] perform(byte[] input) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); + dbf.setXIncludeAware(false); + dbf.setExpandEntityReferences(false); Document doc = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(input)); this.createSignature(doc); @@ -35,6 +38,6 @@ protected byte[] perform(byte[] input) throws Exception { Transformer transformer = transformerFactory.newTransformer(); transformer.transform(source, result); return bos.toByteArray(); - } + } } diff --git a/src/de/usd/cstchef/operations/signature/XmlMultiSignature.java b/src/main/java/de/usd/cstchef/operations/signature/XmlMultiSignature.java similarity index 90% rename from src/de/usd/cstchef/operations/signature/XmlMultiSignature.java rename to src/main/java/de/usd/cstchef/operations/signature/XmlMultiSignature.java index 445c166..79bd83a 100644 --- a/src/de/usd/cstchef/operations/signature/XmlMultiSignature.java +++ b/src/main/java/de/usd/cstchef/operations/signature/XmlMultiSignature.java @@ -22,9 +22,11 @@ public XmlMultiSignature() { this.addIdSelectors(); } - protected byte[] perform(byte[] input) throws Exception { + protected byte[] perform(byte[] input) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); + dbf.setXIncludeAware(false); + dbf.setExpandEntityReferences(false); Document doc = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(input)); this.createSignature(doc); @@ -36,6 +38,6 @@ protected byte[] perform(byte[] input) throws Exception { Transformer transformer = transformerFactory.newTransformer(); transformer.transform(source, result); return bos.toByteArray(); - } + } } diff --git a/src/de/usd/cstchef/operations/signature/XmlSignature.java b/src/main/java/de/usd/cstchef/operations/signature/XmlSignature.java similarity index 76% rename from src/de/usd/cstchef/operations/signature/XmlSignature.java rename to src/main/java/de/usd/cstchef/operations/signature/XmlSignature.java index f8fcb62..c25fb68 100644 --- a/src/de/usd/cstchef/operations/signature/XmlSignature.java +++ b/src/main/java/de/usd/cstchef/operations/signature/XmlSignature.java @@ -42,36 +42,36 @@ public abstract class XmlSignature extends KeystoreOperation { private boolean multiSignature = false; private XMLSignatureFactory signatureFac; private HashMap digestMethods = new HashMap(); - private HashMap signatureMethods = new HashMap(); + private HashMap signatureMethods = new HashMap(); //"rsa-sha256", SignatureMethod.RSA_SHA256, //"rsa-sha512", SignatureMethod.RSA_SHA512 private String[] availDigestMethods = new String[] {"sha1", "sha256", "sha512"}; private String[] availSignatureMethods = new String[] {"rsa-sha1"};//, "rsa-sha256", "rsa-sha512"}; - protected JComboBox signatureMethod; - protected JComboBox digestMethod; + protected JComboBox signatureMethod; + protected JComboBox digestMethod; - protected JButton addReferenceButton; - protected JButton removeReferenceButton; - protected ArrayList referenceFields = new ArrayList(); - - protected JComboBox includeKeyInfo; + protected JButton addReferenceButton; + protected JButton removeReferenceButton; + protected ArrayList referenceFields = new ArrayList(); + + protected JComboBox includeKeyInfo; protected JCheckBox certificate; protected JCheckBox subject; protected JCheckBox issuer; protected JCheckBox serialIssuer; - protected FormatTextField idIdentifier; + protected FormatTextField idIdentifier; - public XmlSignature() { - super(); - this.digestMethods.put("sha1", DigestMethod.SHA1); - this.digestMethods.put("sha256", DigestMethod.SHA256); - this.digestMethods.put("sha512", DigestMethod.SHA512); - this.signatureMethods.put("rsa-sha1", SignatureMethod.RSA_SHA1); + public XmlSignature() { + super(); + this.digestMethods.put("sha1", DigestMethod.SHA1); + this.digestMethods.put("sha256", DigestMethod.SHA256); + this.digestMethods.put("sha512", DigestMethod.SHA512); + this.signatureMethods.put("rsa-sha1", SignatureMethod.RSA_SHA1); this.signatureFac = XMLSignatureFactory.getInstance("DOM"); this.createMyUI(); - } + } protected ArrayList getReferences() throws Exception { String digMethod = (String) digestMethod.getSelectedItem(); @@ -117,7 +117,7 @@ protected KeyInfo getKeyInfo() throws Exception { List x509Content = new ArrayList(); if( this.subject.isSelected() ) { x509Content.add(cert.getSubjectX500Principal().getName()); - } + } if( this.serialIssuer.isSelected() ) { x509Content.add(keyInfoFac.newX509IssuerSerial(cert.getIssuerX500Principal().getName(),cert.getSerialNumber())); } @@ -132,7 +132,7 @@ protected KeyInfo getKeyInfo() throws Exception { } return (KeyInfo)null; } - + protected void createSignature(Document document) throws Exception { String signMethod = (String)signatureMethod.getSelectedItem(); @@ -145,7 +145,7 @@ protected void createSignature(Document document) throws Exception { KeyInfo keyInfo = this.getKeyInfo(); XMLSignature signature = signatureFac.newXMLSignature(signatureInfo, keyInfo); - DOMSignContext dsc = new DOMSignContext (keyEntry.getPrivateKey(), document.getDocumentElement()); + DOMSignContext dsc = new DOMSignContext (keyEntry.getPrivateKey(), document.getDocumentElement()); signature.sign(dsc); } @@ -153,52 +153,52 @@ protected void createSignature(Document document) throws Exception { protected void addIdSelectors() { this.multiSignature = true; - this.idIdentifier = new FormatTextField(); - this.addUIElement("Identifier", this.idIdentifier); + this.idIdentifier = new FormatTextField(); + this.addUIElement("Identifier", this.idIdentifier); - addReferenceButton = new JButton("Add Reference"); - addReferenceButton.addActionListener(this); - this.addUIElement(null, addReferenceButton, false, "button1"); + addReferenceButton = new JButton("Add Reference"); + addReferenceButton.addActionListener(this); + this.addUIElement(null, addReferenceButton, false, "button1"); } - public void createMyUI() { + public void createMyUI() { super.createMyUI(); - this.includeKeyInfo = new JComboBox<>(new String[]{ "true", "false" }); - this.includeKeyInfo.addActionListener(this); - this.addUIElement("IncludeKeyInfo", this.includeKeyInfo); - + this.includeKeyInfo = new JComboBox<>(new String[]{ "true", "false" }); + this.includeKeyInfo.addActionListener(this); + this.addUIElement("IncludeKeyInfo", this.includeKeyInfo); + this.certificate = new JCheckBox("Include Certificate"); this.certificate.setSelected(false); - this.certificate.addActionListener(this); - this.addUIElement(null, this.certificate, "checkbox1"); + this.certificate.addActionListener(this); + this.addUIElement(null, this.certificate, "checkbox1"); this.subject = new JCheckBox("Include Subject"); this.subject.setSelected(false); - this.subject.addActionListener(this); - this.addUIElement(null, this.subject, "checkbox2"); + this.subject.addActionListener(this); + this.addUIElement(null, this.subject, "checkbox2"); this.issuer = new JCheckBox("Include Issuer"); this.issuer.setSelected(false); - this.issuer.addActionListener(this); - this.addUIElement(null, this.issuer, "checkbox3"); + this.issuer.addActionListener(this); + this.addUIElement(null, this.issuer, "checkbox3"); this.serialIssuer = new JCheckBox("Include Issuer"); this.serialIssuer.setSelected(false); - this.serialIssuer.addActionListener(this); - this.addUIElement(null, this.serialIssuer, "checkbox4"); - - this.digestMethod = new JComboBox(this.availDigestMethods); - this.digestMethod.addActionListener(this); - this.addUIElement("DigestMethod", this.digestMethod); - - this.signatureMethod = new JComboBox(this.availSignatureMethods); - this.signatureMethod.addActionListener(this); - this.addUIElement("SignatureMethod", this.signatureMethod); - } - - public void actionPerformed(ActionEvent arg0) { + this.serialIssuer.addActionListener(this); + this.addUIElement(null, this.serialIssuer, "checkbox4"); + + this.digestMethod = new JComboBox(this.availDigestMethods); + this.digestMethod.addActionListener(this); + this.addUIElement("DigestMethod", this.digestMethod); + + this.signatureMethod = new JComboBox(this.availSignatureMethods); + this.signatureMethod.addActionListener(this); + this.addUIElement("SignatureMethod", this.signatureMethod); + } + + public void actionPerformed(ActionEvent arg0) { if( arg0.getSource() == addReferenceButton ) { FormatTextField tmpRef = new FormatTextField(); this.addUIElement("Reference", tmpRef); @@ -218,5 +218,5 @@ public void actionPerformed(ActionEvent arg0) { } } super.actionPerformed(arg0); - } + } } diff --git a/src/de/usd/cstchef/operations/string/Length.java b/src/main/java/de/usd/cstchef/operations/string/Length.java similarity index 72% rename from src/de/usd/cstchef/operations/string/Length.java rename to src/main/java/de/usd/cstchef/operations/string/Length.java index 0aeaa52..77c41cf 100644 --- a/src/de/usd/cstchef/operations/string/Length.java +++ b/src/main/java/de/usd/cstchef/operations/string/Length.java @@ -7,9 +7,9 @@ @OperationInfos(name = "Length", category = OperationCategory.STRING, description = "Returns the length of the input.") public class Length extends Operation { - @Override - protected byte[] perform(byte[] input) throws Exception { - return String.valueOf(input.length).getBytes(); - } + @Override + protected byte[] perform(byte[] input) throws Exception { + return String.valueOf(input.length).getBytes(); + } } \ No newline at end of file diff --git a/src/main/java/de/usd/cstchef/operations/string/Lowercase.java b/src/main/java/de/usd/cstchef/operations/string/Lowercase.java new file mode 100644 index 0000000..1973b46 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/string/Lowercase.java @@ -0,0 +1,28 @@ +package de.usd.cstchef.operations.string; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "Lowercase", category = OperationCategory.STRING, description = "Change string to lowercase.") +public class Lowercase extends Operation { + + @Override + protected byte[] perform(byte[] input) throws Exception { + try { + if(input != null) { + String inputStr = new String(input); + return inputStr.toLowerCase().getBytes(); + } + else { + return "".getBytes(); + } + + } catch (Exception e) { + return input; + } + } +} diff --git a/src/main/java/de/usd/cstchef/operations/string/Prefix.java b/src/main/java/de/usd/cstchef/operations/string/Prefix.java new file mode 100644 index 0000000..108307f --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/string/Prefix.java @@ -0,0 +1,30 @@ +package de.usd.cstchef.operations.string; + +import java.io.ByteArrayOutputStream; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.FormatTextField; + +@OperationInfos(name = "Prefix", category = OperationCategory.STRING, description = "Adds a prefix.") +public class Prefix extends Operation { + + private FormatTextField prefixTxt; + + @Override + protected byte[] perform(byte[] input) throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(prefixTxt.getText()); + out.write(input); + + return out.toByteArray(); + } + + @Override + public void createUI() { + this.prefixTxt = new FormatTextField(); + this.addUIElement("Prefix", this.prefixTxt); + } + +} \ No newline at end of file diff --git a/src/main/java/de/usd/cstchef/operations/string/Replace.java b/src/main/java/de/usd/cstchef/operations/string/Replace.java new file mode 100644 index 0000000..d328f74 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/string/Replace.java @@ -0,0 +1,64 @@ +package de.usd.cstchef.operations.string; + +import javax.swing.JCheckBox; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.VariableTextArea; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "Replace", category = OperationCategory.STRING, description = "Uses a regular expression to replace all occurences. Has side effect on binary content due to String Encoding.") +public class Replace extends Operation { + + private JCheckBox checkbox; + private VariableTextField exptTxt; + private VariableTextArea replacementTxt; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] result = null; + if( checkbox.isSelected() ) { + String inputStr = new String(input); + result = inputStr.replaceAll(exptTxt.getText(), replacementTxt.getText()).getBytes(); + } else { + IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = cbs.getHelpers(); + + int start = helpers.indexOf(input, exptTxt.getBytes(), true, 0, input.length); + + if(start < 0) + return input; + + byte[] replaced = exptTxt.getBytes(); + byte[] replacement = replacementTxt.getBytes(); + + byte[] newRequest = new byte[input.length + replacement.length - replaced.length]; + System.arraycopy(input, 0, newRequest, 0, start); + System.arraycopy(replacement, 0, newRequest, start, replacement.length); + System.arraycopy(input, start + replaced.length, newRequest, start + replacement.length, input.length - replaced.length - start); + + result = newRequest; + } + + return result; + } + + @Override + public void createUI() { + this.exptTxt = new VariableTextField(); + this.addUIElement("Expr", this.exptTxt); + + this.checkbox = new JCheckBox("Regex"); + this.checkbox.setSelected(false); + this.addUIElement(null, this.checkbox, "checkbox1"); + + this.replacementTxt = new VariableTextArea(); + this.addUIElement("Value", this.replacementTxt); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/string/Reverse.java b/src/main/java/de/usd/cstchef/operations/string/Reverse.java new file mode 100644 index 0000000..00b9e6c --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/string/Reverse.java @@ -0,0 +1,17 @@ +package de.usd.cstchef.operations.string; + +import org.bouncycastle.util.Arrays; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "Reverse", category = OperationCategory.STRING, description = "Returns the reversed input.") +public class Reverse extends Operation { + + @Override + protected byte[] perform(byte[] input) throws Exception { + return Arrays.reverse(input); + } + +} \ No newline at end of file diff --git a/src/main/java/de/usd/cstchef/operations/string/SplitAndSelect.java b/src/main/java/de/usd/cstchef/operations/string/SplitAndSelect.java new file mode 100644 index 0000000..deafc48 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/string/SplitAndSelect.java @@ -0,0 +1,67 @@ +package de.usd.cstchef.operations.string; + +import org.bouncycastle.util.Arrays; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.VariableTextField; + +@OperationInfos(name = "Split and Select", category = OperationCategory.STRING, description = "Split input and select one item.") +public class SplitAndSelect extends Operation { + + private VariableTextField item; + private VariableTextField delim; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] delimmiter = delim.getBytes(); + + int itemNumber = 0; + try { + String itemValue = item.getText(); + itemNumber = Integer.valueOf(itemValue); + } catch(Exception e) { + return input; + } + + if( itemNumber < 0 ) + return input; + + IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = cbs.getHelpers(); + int length = input.length; + + int start = 0; + int offset = 0; + int counter = 0; + while( counter < itemNumber ) { + offset = helpers.indexOf(input, delimmiter, false, start, length); + if( offset >= 0 ) { + start = offset + delimmiter.length; + counter++; + } else { + break; + } + } + + int end = helpers.indexOf(input, delimmiter, false, start, length); + if( end < 0 ) + end = length; + + byte[] result = Arrays.copyOfRange(input, start, end); + return result; + } + + @Override + public void createUI() { + this.delim = new VariableTextField(); + this.addUIElement("Delimmiter", this.delim); + this.item = new VariableTextField(); + this.addUIElement("Item number", this.item); + } +} diff --git a/src/de/usd/cstchef/operations/string/StaticString.java b/src/main/java/de/usd/cstchef/operations/string/StaticString.java similarity index 57% rename from src/de/usd/cstchef/operations/string/StaticString.java rename to src/main/java/de/usd/cstchef/operations/string/StaticString.java index a958894..5da6d7c 100644 --- a/src/de/usd/cstchef/operations/string/StaticString.java +++ b/src/main/java/de/usd/cstchef/operations/string/StaticString.java @@ -8,17 +8,17 @@ @OperationInfos(name = "Static string", category = OperationCategory.STRING, description = "Returns the defined string.") public class StaticString extends Operation { - private VariableTextArea stringTxt; + private VariableTextArea stringTxt; - @Override - protected byte[] perform(byte[] input) throws Exception { - return this.stringTxt.getBytes(); - } + @Override + protected byte[] perform(byte[] input) throws Exception { + return this.stringTxt.getBytes(); + } - @Override - public void createUI() { - this.stringTxt = new VariableTextArea(); - this.addUIElement("Value", this.stringTxt); - } + @Override + public void createUI() { + this.stringTxt = new VariableTextArea(); + this.addUIElement("Value", this.stringTxt); + } } diff --git a/src/main/java/de/usd/cstchef/operations/string/Substring.java b/src/main/java/de/usd/cstchef/operations/string/Substring.java new file mode 100644 index 0000000..3980751 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/string/Substring.java @@ -0,0 +1,43 @@ +package de.usd.cstchef.operations.string; + +import javax.swing.JSpinner; + +import org.bouncycastle.util.Arrays; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "Substring", category = OperationCategory.STRING, description = "Extracts a substring.") +public class Substring extends Operation { + + private JSpinner startSpinner; + private JSpinner endSpinner; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + int start = (int) startSpinner.getValue(); + int end = (int) endSpinner.getValue(); + + if( start < 0 ) + start = input.length + start; + if( end < 0 ) + end = input.length + end; + if( end > input.length ) + end = input.length + 1; + + byte[] slice = Arrays.copyOfRange(input, start, end); + return slice; + } + + @Override + public void createUI() { + this.startSpinner = new JSpinner(); + this.addUIElement("Start", this.startSpinner); + + this.endSpinner = new JSpinner(); + this.addUIElement("End", this.endSpinner); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/string/Suffix.java b/src/main/java/de/usd/cstchef/operations/string/Suffix.java new file mode 100644 index 0000000..69fea04 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/string/Suffix.java @@ -0,0 +1,30 @@ +package de.usd.cstchef.operations.string; + +import java.io.ByteArrayOutputStream; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.view.ui.FormatTextField; + +@OperationInfos(name = "Suffix", category = OperationCategory.STRING, description = "Adds a suffix.") +public class Suffix extends Operation { + + private FormatTextField suffixTxt; + + @Override + protected byte[] perform(byte[] input) throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(input); + out.write(suffixTxt.getText()); + + return out.toByteArray(); + } + + @Override + public void createUI() { + this.suffixTxt = new FormatTextField (); + this.addUIElement("Suffix", this.suffixTxt); + } + +} \ No newline at end of file diff --git a/src/main/java/de/usd/cstchef/operations/string/Uppercase.java b/src/main/java/de/usd/cstchef/operations/string/Uppercase.java new file mode 100644 index 0000000..962912c --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/string/Uppercase.java @@ -0,0 +1,27 @@ +package de.usd.cstchef.operations.string; + +import burp.BurpUtils; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "Uppercase", category = OperationCategory.STRING, description = "Change string to uppercase.") +public class Uppercase extends Operation { + + @Override + protected byte[] perform(byte[] input) throws Exception { + try { + if(input != null) { + String inputStr = new String(input); + return inputStr.toUpperCase().getBytes(); + } + else { + return "".getBytes(); + } + } catch (Exception e) { + return input; + } + } +} diff --git a/src/main/java/de/usd/cstchef/operations/utils/GetVariable.java b/src/main/java/de/usd/cstchef/operations/utils/GetVariable.java new file mode 100644 index 0000000..66580c0 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/utils/GetVariable.java @@ -0,0 +1,31 @@ +package de.usd.cstchef.operations.utils; + +import javax.swing.JTextField; + +import de.usd.cstchef.VariableStore; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "Get Variable", category = OperationCategory.UTILS, description = "Retrives a stored variable.") +public class GetVariable extends Operation { + + private JTextField varNameTxt; + private JTextField defaultTxt; + + @Override + protected byte[] perform(byte[] input) throws Exception { + String varName = this.varNameTxt.getText().trim(); + byte[] var = VariableStore.getInstance().getVariable(varName); + return var == null ? this.defaultTxt.getText().getBytes() : var; + } + + public void createUI() { + this.varNameTxt = new JTextField(); + this.addUIElement("Variable name", this.varNameTxt); + + this.defaultTxt = new JTextField(); + this.addUIElement("Default value", this.defaultTxt); + } + +} diff --git a/src/de/usd/cstchef/operations/utils/NoOperation.java b/src/main/java/de/usd/cstchef/operations/utils/NoOperation.java similarity index 77% rename from src/de/usd/cstchef/operations/utils/NoOperation.java rename to src/main/java/de/usd/cstchef/operations/utils/NoOperation.java index bfc8e27..e67a63e 100644 --- a/src/de/usd/cstchef/operations/utils/NoOperation.java +++ b/src/main/java/de/usd/cstchef/operations/utils/NoOperation.java @@ -7,9 +7,9 @@ @OperationInfos(name = "No Operation", category = OperationCategory.UTILS, description = "Does nothing :)") public class NoOperation extends Operation { - @Override - protected byte[] perform(byte[] input) throws Exception { - return input; - } - + @Override + protected byte[] perform(byte[] input) throws Exception { + return input; + } + } diff --git a/src/main/java/de/usd/cstchef/operations/utils/RandomNumber.java b/src/main/java/de/usd/cstchef/operations/utils/RandomNumber.java new file mode 100644 index 0000000..d54c557 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/utils/RandomNumber.java @@ -0,0 +1,112 @@ +package de.usd.cstchef.operations.utils; + +import java.security.SecureRandom; +import java.text.NumberFormat; + +import javax.swing.JSeparator; +import javax.swing.JTextField; +import javax.swing.SwingConstants; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "Random Number", category = OperationCategory.UTILS, description = "Generate a random number.") +public class RandomNumber extends Operation { + + // input fields for minimum/maximum + private JTextField textFieldMinimum; + private JTextField textFieldMaximum; + + // input fields for formatting + private JTextField textFieldFormatMinIntDigits; + private JTextField textFieldFormatMaxIntDigits; + private JTextField textFieldFormatMinFracDigits; + private JTextField textFieldFormatMaxFracDigits; + + private final static SecureRandom secRand = new SecureRandom(); + private static NumberFormat numberFormatter = NumberFormat.getInstance(); + + /** + * Helper to parse Integer from String and set default if it fails + * @param numberStr A string representing a number + * @param defaultValue default value if parsing fails + * @return + */ + private int parseInt(String numberStr, int defaultValue) { + try { + int intValue = Integer.valueOf(numberStr); + return intValue; + }catch (Exception e) { + return defaultValue; + } + } + + @Override + protected byte[] perform(byte[] input) throws Exception { + + // get Bounds from user input + int boundMin = parseInt(this.textFieldMinimum.getText(), 0); + int boundMax = parseInt(this.textFieldMaximum.getText(), Integer.MAX_VALUE); + + // prepare formatter + int minIntDigits = parseInt(this.textFieldFormatMinIntDigits.getText(), 1); + numberFormatter.setMinimumIntegerDigits(minIntDigits); + + int maxIntDigits = parseInt(this.textFieldFormatMaxIntDigits.getText(), 99); + numberFormatter.setMaximumIntegerDigits(maxIntDigits); + + int minFracDigits = parseInt(this.textFieldFormatMinFracDigits.getText(), 0); + numberFormatter.setMinimumFractionDigits(minFracDigits); + + int maxFracDigits = parseInt(this.textFieldFormatMaxFracDigits.getText(), 0); + numberFormatter.setMaximumFractionDigits(maxFracDigits); + + numberFormatter.setGroupingUsed(false); + + // generate random numbers and format them + if(maxFracDigits == 0) { + // use int mode + int randomValue = secRand.nextInt(boundMax - boundMin + 1) + boundMin; + return numberFormatter.format(randomValue).getBytes(); + } else { + // use double mode + double randomValue = boundMin + (boundMax - boundMin) * secRand.nextDouble(); + return numberFormatter.format(randomValue).getBytes(); + } + } + + public void createUI() { + + // fields for min/max + this.textFieldMinimum = new JTextField(); + this.textFieldMinimum.setText("0"); + this.addUIElement("Minimum Number", this.textFieldMinimum); + + this.textFieldMaximum = new JTextField(); + this.textFieldMaximum.setText("9999"); + this.addUIElement("Maximum Number", this.textFieldMaximum); + + // use a separator + JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL); + this.addUIElement(null, separator); + + // fields for formatting: Integer digits + this.textFieldFormatMinIntDigits = new JTextField(); + this.textFieldFormatMinIntDigits.setText("1"); + this.addUIElement("Min integer digits", this.textFieldFormatMinIntDigits); + + this.textFieldFormatMaxIntDigits = new JTextField(); + this.textFieldFormatMaxIntDigits.setText("99"); + this.addUIElement("Max integer digits", this.textFieldFormatMaxIntDigits); + + // fields for formatting: fraction digits + this.textFieldFormatMinFracDigits = new JTextField(); + this.textFieldFormatMinFracDigits.setText("0"); + this.addUIElement("Min fraction digits", this.textFieldFormatMinFracDigits); + + this.textFieldFormatMaxFracDigits = new JTextField(); + this.textFieldFormatMaxFracDigits.setText("0"); + this.addUIElement("Max fraction digits", this.textFieldFormatMaxFracDigits); + } +} diff --git a/src/main/java/de/usd/cstchef/operations/utils/RandomUUID.java b/src/main/java/de/usd/cstchef/operations/utils/RandomUUID.java new file mode 100644 index 0000000..7418932 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/utils/RandomUUID.java @@ -0,0 +1,18 @@ +package de.usd.cstchef.operations.utils; + +import java.util.UUID; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; + +@OperationInfos(name = "Random UUID", category = OperationCategory.UTILS, description = "Generate a random UUID.") +public class RandomUUID extends Operation { + + @Override + protected byte[] perform(byte[] input) throws Exception { + final String uuid = UUID.randomUUID().toString(); + return uuid.getBytes(); + } + +} diff --git a/src/main/java/de/usd/cstchef/operations/utils/SetIfEmpty.java b/src/main/java/de/usd/cstchef/operations/utils/SetIfEmpty.java new file mode 100644 index 0000000..ab856af --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/utils/SetIfEmpty.java @@ -0,0 +1,46 @@ +package de.usd.cstchef.operations.utils; + +import javax.swing.JCheckBox; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.view.ui.FormatTextField; + +@OperationInfos(name = "Set if Empty", category = OperationCategory.UTILS, description = "Sets a value if the input is empty.") +public class SetIfEmpty extends Operation { + + private FormatTextField value; + private JCheckBox checkbox; + + @Override + protected byte[] perform(byte[] input) throws Exception { + + byte[] valueToSet = value.getText(); + if( input.length == 0 ) { + return valueToSet; + } + + if( !checkbox.isSelected() ) + return input; + + int i = 0; + while( i < input.length ) { + if( input[i] != 32 ) { + return input; + } + i++; + } + + return valueToSet; + } + + public void createUI() { + this.value = new FormatTextField(); + this.addUIElement("Value to set", this.value); + + this.checkbox = new JCheckBox("Space is empty"); + this.checkbox.setSelected(false); + this.addUIElement(null, this.checkbox, "checkbox1"); + } +} diff --git a/src/main/java/de/usd/cstchef/operations/utils/StoreVariable.java b/src/main/java/de/usd/cstchef/operations/utils/StoreVariable.java new file mode 100644 index 0000000..3fabda9 --- /dev/null +++ b/src/main/java/de/usd/cstchef/operations/utils/StoreVariable.java @@ -0,0 +1,43 @@ +package de.usd.cstchef.operations.utils; + +import javax.swing.JTextField; + +import de.usd.cstchef.VariableStore; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +@OperationInfos(name = "Store Variable", category = OperationCategory.UTILS, description = "Stores variables to be retrieved later.") +public class StoreVariable extends Operation { + + private JTextField varNameTxt; + private String oldVarName; + + @Override + protected byte[] perform(byte[] input) throws Exception { + String newVarName = this.varNameTxt.getText().trim(); + VariableStore store = VariableStore.getInstance(); + // remove old variable from hashmap + if (!newVarName.equals(oldVarName)) { + store.removeVariable(this.oldVarName); + this.oldVarName = newVarName; + } + + if (!newVarName.isEmpty()) { + store.setVariable(newVarName, input); + } + + return input; + } + + public void createUI() { + this.varNameTxt = new JTextField(); + this.addUIElement("Variable name", this.varNameTxt); + } + + @Override + public void onRemove() { + VariableStore.getInstance().removeVariable(this.oldVarName); + } + +} diff --git a/src/main/java/de/usd/cstchef/view/AddOperationMouseAdapter.java b/src/main/java/de/usd/cstchef/view/AddOperationMouseAdapter.java new file mode 100644 index 0000000..53d8440 --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/AddOperationMouseAdapter.java @@ -0,0 +1,32 @@ +package de.usd.cstchef.view; + +import java.awt.Container; +import javax.swing.JTree; +import javax.swing.tree.TreePath; + +import de.usd.cstchef.operations.Operation; + +public class AddOperationMouseAdapter extends OperationMouseAdapter { + + + public AddOperationMouseAdapter(JTree source, Container target) { + super(source, target); + } + + @Override + protected Operation getDraggedOperation(int x, int y) { + TreePath draggedPath = ((JTree) this.source).getClosestPathForLocation(x, y); + if (draggedPath != null) { + Object node = draggedPath.getLastPathComponent(); + if (node.getClass().equals(OperationTreeNode.class)) { + Class cls = ((OperationTreeNode) node).getOperationClass(); + try { + return cls.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + } + } + } + return null; + } + +} diff --git a/src/main/java/de/usd/cstchef/view/BurpEditorWrapper.java b/src/main/java/de/usd/cstchef/view/BurpEditorWrapper.java new file mode 100644 index 0000000..b5fd02f --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/BurpEditorWrapper.java @@ -0,0 +1,100 @@ +package de.usd.cstchef.view; + +import java.awt.Component; +import java.util.Arrays; + +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import burp.BurpUtils; +import burp.IMessageEditor; +import burp.IMessageEditorController; + +public class BurpEditorWrapper implements IMessageEditor, DocumentListener { + + private JTextArea fallbackArea; + private IMessageEditor burpEditor; + public boolean fallbackMode; + boolean isModified; + byte[] lastContent; + + public BurpEditorWrapper(IMessageEditorController controller, boolean editable) { + if (BurpUtils.inBurp()) { + this.burpEditor = BurpUtils.getInstance().getCallbacks().createMessageEditor(controller, editable); + fallbackMode = false; + } else { + this.fallbackArea = new JTextArea(); + this.fallbackArea.getDocument().addDocumentListener(this); + fallbackMode = true; + } + } + + @Override + public Component getComponent() { + if (fallbackMode) { + JScrollPane inputScrollPane = new JScrollPane(fallbackArea); + return inputScrollPane; + } + return burpEditor.getComponent(); + } + + @Override + public byte[] getMessage() { + byte[] result; + result = fallbackMode ? fallbackArea.getText().getBytes() : burpEditor.getMessage(); + return result == null ? new byte[0] : result; + } + + @Override + public byte[] getSelectedData() { + return null; + } + + @Override + public int[] getSelectionBounds() { + return null; + } + + @Override + public boolean isMessageModified() { + if (fallbackMode) { + boolean state = this.isModified; + this.isModified = false; + return state; + } + // TODO: a little hack here + if (!Arrays.equals(lastContent, getMessage())) { + lastContent = getMessage(); + return true; + } + return false; + } + + @Override + public void setMessage(byte[] arg0, boolean arg1) { + if (fallbackMode) { + fallbackArea.setText(new String(arg0)); + } else { + this.lastContent = arg0; + burpEditor.setMessage(arg0, arg1); //TODO fix second parameter + } + } + + @Override + public void changedUpdate(DocumentEvent e) { + this.isModified = true; + } + + @Override + public void insertUpdate(DocumentEvent e) { + this.isModified = true; + } + + @Override + public void removeUpdate(DocumentEvent e) { + this.isModified = true; + } + +} diff --git a/src/main/java/de/usd/cstchef/view/FormatTab.java b/src/main/java/de/usd/cstchef/view/FormatTab.java new file mode 100644 index 0000000..5fee0cb --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/FormatTab.java @@ -0,0 +1,70 @@ +package de.usd.cstchef.view; + +import java.awt.Component; + +import burp.BurpUtils; +import burp.IMessageEditorTab; +import burp.ITextEditor; +import burp.Logger; + +public class FormatTab implements IMessageEditorTab { + private ITextEditor txtInput; + private boolean editable; + private RecipePanel responseFormatRecipePanel; + private RecipePanel requestFormatRecipePanel; + private byte[] currentMessage; + + public FormatTab(RecipePanel requestFormatRecipePanel, RecipePanel responseFormatRecipePanel, boolean editable) { + this.editable = editable; + this.responseFormatRecipePanel = responseFormatRecipePanel; + this.requestFormatRecipePanel = requestFormatRecipePanel; + txtInput = BurpUtils.getInstance().getCallbacks().createTextEditor(); + txtInput.setEditable(editable); + } + + @Override + public String getTabCaption() { + return "CSTC"; + } + + @Override + public Component getUiComponent() { + return txtInput.getComponent(); + } + + @Override + public boolean isEnabled(byte[] content, boolean isRequest) { + return true; + } + + @Override + public void setMessage(byte[] content, boolean isRequest) { + currentMessage = content; + + if (content == null) { + txtInput.setText("Nothing here".getBytes()); + txtInput.setEditable(false); + return; + } + RecipePanel recipe = isRequest ? this.requestFormatRecipePanel : this.responseFormatRecipePanel; + Logger.getInstance().log("baking new stuff"); + byte[] result = recipe.bake(content); + this.txtInput.setText(result); + } + + @Override + public byte[] getMessage() { + return currentMessage; + } + + @Override + public boolean isModified() { + return txtInput.isTextModified(); + } + + @Override + public byte[] getSelectedData() { + return txtInput.getSelectedText(); + } + +} \ No newline at end of file diff --git a/src/main/java/de/usd/cstchef/view/LayoutPanel.java b/src/main/java/de/usd/cstchef/view/LayoutPanel.java new file mode 100644 index 0000000..d2f87cc --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/LayoutPanel.java @@ -0,0 +1,48 @@ +package de.usd.cstchef.view; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Font; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.UIManager; + +public class LayoutPanel extends JPanel { + + private Box headerBox; + + public LayoutPanel() { + this("No tile"); + } + + public LayoutPanel(String title) { + super(); + this.setLayout(new BorderLayout(0, 0)); + + this.headerBox = Box.createHorizontalBox(); + this.headerBox.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + this.headerBox.setOpaque(true); + this.headerBox.setBackground(UIManager.getColor("Panel.background")); + + JLabel titleLbl = new JLabel(title); + titleLbl.setAlignmentX(Component.LEFT_ALIGNMENT); + + Font f = titleLbl.getFont(); + titleLbl.setFont(f.deriveFont(f.getStyle() | Font.BOLD)); + + this.headerBox.add(titleLbl); + this.headerBox.add(Box.createHorizontalGlue()); + + this.add(headerBox, BorderLayout.PAGE_START); + } + + public void addActionComponent(JComponent comp) { + comp.setAlignmentX(Component.RIGHT_ALIGNMENT); + this.headerBox.add(comp); + this.headerBox.add(Box.createHorizontalStrut(10)); + } +} diff --git a/src/main/java/de/usd/cstchef/view/MoveOperationMouseAdapter.java b/src/main/java/de/usd/cstchef/view/MoveOperationMouseAdapter.java new file mode 100644 index 0000000..02cac2b --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/MoveOperationMouseAdapter.java @@ -0,0 +1,22 @@ +package de.usd.cstchef.view; + +import java.awt.Component; +import java.awt.Container; + +import de.usd.cstchef.operations.Operation; + +public class MoveOperationMouseAdapter extends OperationMouseAdapter { + + public MoveOperationMouseAdapter(RecipeStepPanel source, Container target) { + super(source.getOperationsPanel(), target); + } + + @Override + protected Operation getDraggedOperation(int x, int y) { + Component comp = this.source.getComponentAt(x, y); + comp.getParent().remove(comp); + + return comp instanceof Operation ? (Operation) comp : null; + } + +} diff --git a/src/main/java/de/usd/cstchef/view/OperationMouseAdapter.java b/src/main/java/de/usd/cstchef/view/OperationMouseAdapter.java new file mode 100644 index 0000000..920ddd9 --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/OperationMouseAdapter.java @@ -0,0 +1,243 @@ +package de.usd.cstchef.view; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.dnd.DragSource; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.Window.Type; +import java.util.Objects; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JWindow; +import javax.swing.SwingUtilities; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; + +/* + * Based on: + * https://stackoverflow.com/questions/27245283/java-drag-and-drop-to-change-the-order-of-panels + */ +public abstract class OperationMouseAdapter extends MouseAdapter { + + private static final Rectangle R1 = new Rectangle(); + private static final Rectangle R2 = new Rectangle(); + + private static Rectangle prevRect; + + private final JWindow window = new JWindow(); + private Container panelPreview; + private JLabel windowPreviewLbl; + private JLabel panelPreviewLbl; + + private Point startPt; + private Point dragOffset; + private final int gestureMotionThreshold = DragSource.getDragThreshold(); + + protected Container source; + protected Container target; + private RecipeStepPanel currentTargetPanel; + + private Operation draggedOperation; + + public OperationMouseAdapter(Container source, Container target) { + super(); + this.source = source; + this.target = target; + window.setSize(300, 35); + window.setLocationRelativeTo(null); + window.setBackground(new Color(0, true)); + window.setVisible(false); + window.setType(Type.POPUP); + + Container windowPreview = createPreview("My Preview"); + windowPreviewLbl = (JLabel) windowPreview.getComponent(0); + window.add(windowPreview); + panelPreview = createPreview("My Preview"); + panelPreviewLbl = (JLabel) panelPreview.getComponent(0); + + dragOffset = new Point(window.getWidth() / 3, window.getHeight() / 2); + } + + private Container createPreview(String title) { + Box previewBox = Box.createHorizontalBox(); + previewBox.setOpaque(true); + previewBox.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + previewBox.setBackground(new Color(127, 237, 247, 255)); + + JLabel previewLbl = new JLabel(title); + previewLbl.setForeground(new Color(58, 135, 173)); + + previewBox.add(previewLbl); + return previewBox; + } + + private void startDragging(Point pt) { + OperationInfos opInfos = this.draggedOperation.getClass().getAnnotation(OperationInfos.class); + if (opInfos == null) { + return; + } + + String name = opInfos.name(); + windowPreviewLbl.setText(name); + panelPreviewLbl.setText(name); + + updateWindowLocation(pt, this.source); + window.setVisible(true); + } + + private void updateWindowLocation(Point pt, Container parent) { + Point p = new Point(pt.x - dragOffset.x, pt.y - dragOffset.y); + SwingUtilities.convertPointToScreen(p, parent); + window.setLocation(p); + } + + private int getTargetIndex(Rectangle r, Point pt, int i, boolean previewIndexSmaller) { + int ht2 = (int) (0.5 + r.height * 0.5); + R1.setBounds(r.x, r.y, r.width, ht2); + R2.setBounds(r.x, r.y + ht2, r.width, ht2); + if (R1.contains(pt)) { + prevRect = R1; + return previewIndexSmaller ? i - 1 : i - 1 > 0 ? i : 0; + } else if (R2.contains(pt)) { + prevRect = R2; + return i; + } + return -1; + } + + private void addComponent(RecipeStepPanel line, Component comp, int idx) { + line.removeComponent(comp); + line.addComponent(comp, idx); + } + + @Override + public void mousePressed(MouseEvent e) { + this.startPt = e.getPoint(); + } + + protected abstract Operation getDraggedOperation(int x, int y); + + @Override + public void mouseDragged(MouseEvent e) { + Point pt = e.getPoint(); + JComponent parent = (JComponent) e.getComponent(); + + // not yet dragging and motion > threshold + if (this.draggedOperation == null && startPt != null) { + double a = Math.pow(pt.x - startPt.x, 2); + double b = Math.pow(pt.y - startPt.y, 2); + if (Math.sqrt(a + b) > gestureMotionThreshold) { + this.draggedOperation = this.getDraggedOperation(startPt.x, startPt.y); + if (this.draggedOperation != null) { + startDragging(pt); + } + } + return; + } + + // dragging, but no component was created + if (!window.isVisible() || draggedOperation == null) { + return; + } + + pt = SwingUtilities.convertPoint(parent, e.getPoint(), this.target); + updateWindowLocation(pt, this.target); + + Component targetLine = this.target.getComponentAt(pt); + + // changed the target, remove the old preview + if (currentTargetPanel != null) { + if (targetLine == null || !targetLine.equals(currentTargetPanel)) { + this.currentTargetPanel.removeComponent(panelPreview); + this.currentTargetPanel = null; + } + } + + // we have no valid target + if (targetLine == null || !(targetLine instanceof RecipeStepPanel)) { + return; + } + + RecipeStepPanel targetPanel = (RecipeStepPanel) this.target.getComponentAt(pt); + this.currentTargetPanel = targetPanel; + + JPanel operationsPanel = currentTargetPanel.getOperationsPanel(); + pt = SwingUtilities.convertPoint(this.target, pt, operationsPanel); + + if (prevRect != null && prevRect.contains(pt)) { + return; + } + + boolean gotPreview = false; + for (int i = 0; i < operationsPanel.getComponentCount(); i++) { + Component comp = operationsPanel.getComponent(i); + Rectangle r = comp.getBounds(); + // inside our gap, do nothing + if (Objects.equals(comp, panelPreview)) { + if (r.contains(pt)) { + return; + } else { + gotPreview = true; + continue; + } + } + + int tgt; + if (!(comp instanceof Operation)) { //this is the dummy panel + int count = operationsPanel.getComponentCount(); + tgt = count > 1 ? operationsPanel.getComponentCount() - 2 : 0; + } else { + tgt = getTargetIndex(r, pt, i, gotPreview); + } + + if (tgt >= 0) { + addComponent(currentTargetPanel, panelPreview, tgt); + return; + } + } + } + + @Override + public void mouseReleased(MouseEvent e) { + startPt = null; + + // no dragging + if (!window.isVisible() || draggedOperation == null) { + return; + } + int addIndex = -1; + + // get the index of the preview element + if (currentTargetPanel != null) { + JPanel operationsPanel = this.currentTargetPanel.getOperationsPanel(); + for (int i = 0; i < operationsPanel.getComponentCount(); i++) { + Component comp = operationsPanel.getComponent(i); + if (comp.equals(this.panelPreview)) { + addIndex = i; + break; + } + } + // remove preview from panel + currentTargetPanel.removeComponent(this.panelPreview); + } + + if (addIndex != -1) { + currentTargetPanel.addComponent(this.draggedOperation, addIndex); + } + + this.draggedOperation = null; + prevRect = null; + this.startPt = null; + this.window.setVisible(false); + this.currentTargetPanel = null; + } +} diff --git a/src/main/java/de/usd/cstchef/view/OperationTreeNode.java b/src/main/java/de/usd/cstchef/view/OperationTreeNode.java new file mode 100644 index 0000000..a51cf4b --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/OperationTreeNode.java @@ -0,0 +1,35 @@ +package de.usd.cstchef.view; + +import javax.swing.tree.DefaultMutableTreeNode; + +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.Operation.OperationInfos; + +public class OperationTreeNode extends DefaultMutableTreeNode { + + private String name; + private String toolTipText; + private Class operationClass; + + public OperationTreeNode(Class operationClass) { + super(); + OperationInfos infos = operationClass.getAnnotation(OperationInfos.class); + this.name = infos.name(); + this.toolTipText = infos.description(); + + this.operationClass = operationClass; + } + + public String getToolTipText() { + return this.toolTipText; + } + + public Class getOperationClass() { + return operationClass; + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/src/main/java/de/usd/cstchef/view/OperationsTree.java b/src/main/java/de/usd/cstchef/view/OperationsTree.java new file mode 100644 index 0000000..5824705 --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/OperationsTree.java @@ -0,0 +1,160 @@ +package de.usd.cstchef.view; + +import java.awt.event.MouseEvent; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; + +import javax.swing.ImageIcon; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import burp.Logger; +import de.usd.cstchef.Utils; +import de.usd.cstchef.operations.Operation; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.Operation.OperationInfos; + +public class OperationsTree extends JTree { + + private DefaultTreeModel model; + private static ImageIcon nodeIcon = new ImageIcon(Operation.class.getResource("/operation.png")); + private static ImageIcon openIcon = new ImageIcon(Operation.class.getResource("/folder_open.png")); + private static ImageIcon closedIcon = new ImageIcon(Operation.class.getResource("/folder_closed.png")); + + public OperationsTree() { + super(); + + this.model = (DefaultTreeModel) this.getModel(); + this.model.setRoot(this.createTree()); + this.setToolTipText(""); + DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) this.getCellRenderer(); + renderer.setLeafIcon(nodeIcon); + renderer.setClosedIcon(closedIcon); + renderer.setOpenIcon(openIcon); + } + + @Override + public String getToolTipText(MouseEvent evt) { + if (getRowForLocation(evt.getX(), evt.getY()) == -1) { + return null; + } + + TreePath curPath = getPathForLocation(evt.getX(), evt.getY()); + Object node = curPath.getLastPathComponent(); + + if (node.getClass().equals(OperationTreeNode.class)) { + return ((OperationTreeNode) node).getToolTipText(); + } else if (node.getClass().equals(DefaultMutableTreeNode.class)) { + return null; + } + + return ""; + } + + public void search(String text) { + DefaultMutableTreeNode root = this.createTree(); + this.model.setRoot(root); + + if (text.trim().equals("")) { + return; + } + + ArrayList nodesToRemove = new ArrayList<>(); + Enumeration e = root.breadthFirstEnumeration(); + while (e.hasMoreElements()) { + DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) e.nextElement(); + if (!nextNode.toString().toLowerCase().contains(text.toLowerCase())) { + if (nextNode.getChildCount() == 0) { + nodesToRemove.add(nextNode); + } + } + } + + for (DefaultMutableTreeNode node : nodesToRemove) { + this.removeNode(node); + } + + nodesToRemove.clear(); + for (int i = 0; i < root.getChildCount(); i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i); + if (node.getChildCount() == 0) { + nodesToRemove.add(node); + } + } + + for (DefaultMutableTreeNode node : nodesToRemove) { + this.removeNode(node); + } + + this.expandAll(new TreePath(root)); + } + + private void removeNode(TreeNode selNode) { + if (selNode == null) { + return; + } + + MutableTreeNode parent = (MutableTreeNode) (selNode.getParent()); + if (parent == null) { + return; + } + + if (selNode.getChildCount() == 0) { + this.model.removeNodeFromParent((MutableTreeNode) selNode); + } + } + + private DefaultMutableTreeNode createTree() { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + + // add all categories + HashMap categoryNodes = new HashMap<>(); + for (OperationCategory category : OperationCategory.values()) { + DefaultMutableTreeNode categoryNode = new DefaultMutableTreeNode(category.toString()); + root.add(categoryNode); + categoryNodes.put(category, categoryNode); + } + + // TODO add operations to categories - reflections do not work in burp :( + Class[] operations = Utils.getOperations(); + for (Class operation : operations) { + OperationInfos operationInfos = operation.getAnnotation(OperationInfos.class); + if (operationInfos == null) { + if (!Modifier.isAbstract(operation.getModifiers())) { + Logger.getInstance().err("Found a operation without annotaion: " + operation); + } + continue; + } + + OperationCategory category = operationInfos.category(); + DefaultMutableTreeNode parent = categoryNodes.get(category); + + OperationTreeNode newOperationNode = new OperationTreeNode(operation); + parent.add(newOperationNode); + } + + return root; + } + + private void expandAll(TreePath path) { + TreeNode node = (TreeNode) path.getLastPathComponent(); + + if (node.getChildCount() >= 0) { + Enumeration enumeration = node.children(); + while (enumeration.hasMoreElements()) { + TreeNode n = (TreeNode) enumeration.nextElement(); + TreePath p = path.pathByAddingChild(n); + + expandAll(p); + } + } + this.expandPath(path); + } +} diff --git a/src/main/java/de/usd/cstchef/view/PopupVariableMenu.java b/src/main/java/de/usd/cstchef/view/PopupVariableMenu.java new file mode 100644 index 0000000..86ce84b --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/PopupVariableMenu.java @@ -0,0 +1,65 @@ +package de.usd.cstchef.view; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.HashMap; +import java.util.SortedMap; +import java.util.TreeMap; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import javax.swing.text.JTextComponent; + +public class PopupVariableMenu extends JPopupMenu implements ActionListener, PopupMenuListener { + + private JTextComponent parent; + private static SortedMap variableMap; + + public PopupVariableMenu(JTextComponent parent) { + super(); + this.parent = parent; + this.addPopupMenuListener(this); + + } + + public void refreshMenu() { + this.removeAll(); + + for (String key : variableMap.keySet()) { + JMenuItem item = new JMenuItem(key); + item.addActionListener(this); + this.add(item); + } + } + + public static void refresh(HashMap variables) { + if (variables == null) { + variableMap = new TreeMap(); + } else { + variableMap = new TreeMap(variables); + } + } + + @Override + public void actionPerformed(ActionEvent arg0) { + parent.setText(parent.getText() + "$" + arg0.getActionCommand()); + } + + @Override + public void popupMenuCanceled(PopupMenuEvent arg0) { + // not needed + } + + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent arg0) { + // not needed + } + + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent arg0) { + this.refreshMenu(); + } + +} diff --git a/src/main/java/de/usd/cstchef/view/RecipePanel.java b/src/main/java/de/usd/cstchef/view/RecipePanel.java new file mode 100644 index 0000000..315f146 --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/RecipePanel.java @@ -0,0 +1,563 @@ +package de.usd.cstchef.view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import burp.BurpUtils; +import burp.CstcMessageEditorController; +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IHttpRequestResponse; +import burp.IParameter; +import burp.IRequestInfo; +import burp.Logger; +import de.usd.cstchef.VariableStore; +import de.usd.cstchef.operations.Operation; + +public class RecipePanel extends JPanel implements ChangeListener { + + private static Logger logger = Logger.getInstance(); + + private int operationSteps = 10; + private boolean autoBake = true; + private boolean isRequest = true; + private int bakeThreshold = 400; + private String recipeName; + private int filterMask; + + private BurpEditorWrapper inputText; + private BurpEditorWrapper outputText; + + private JPanel operationLines; + private RequestFilterDialog requestFilterDialog; + + private CstcMessageEditorController controllerOrig; + private CstcMessageEditorController controllerMod; + + private Timer bakeTimer; + + public RecipePanel(String recipeName, boolean isRequest) { + + this.recipeName = recipeName; + this.isRequest = isRequest; + + ToolTipManager tooltipManager = ToolTipManager.sharedInstance(); + tooltipManager.setInitialDelay(0); + this.setLayout(new GridLayout(0, 1)); + + JSplitPane inOut = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + + controllerOrig = new CstcMessageEditorController(); + controllerMod = new CstcMessageEditorController(); + + // create input panel + JPanel inputPanel = new LayoutPanel("Input"); + inputText = new BurpEditorWrapper(controllerOrig, true); + inputPanel.add(inputText.getComponent()); + + // create output panel + JPanel outputPanel = new LayoutPanel("Output"); + outputText = new BurpEditorWrapper(controllerMod, false); + outputPanel.add(outputText.getComponent()); + + JPanel searchTreePanel = new JPanel(); + searchTreePanel.setLayout(new BorderLayout()); + JTextField searchText = new JTextField(); + searchTreePanel.add(searchText, BorderLayout.PAGE_START); + + OperationsTree operationsTree = new OperationsTree(); + operationsTree.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + operationsTree.setRootVisible(false); + searchTreePanel.add(new JScrollPane(operationsTree)); + searchText.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void removeUpdate(DocumentEvent e) { + operationsTree.search(searchText.getText()); + } + + @Override + public void insertUpdate(DocumentEvent e) { + operationsTree.search(searchText.getText()); + } + + @Override + public void changedUpdate(DocumentEvent e) { + operationsTree.search(searchText.getText()); + } + }); + + // create operations panel + JPanel operationsPanel = new LayoutPanel("Operations"); + operationsPanel.add(searchTreePanel); + operationsPanel.setBackground(Color.WHITE); + inOut.setTopComponent(inputPanel); + inOut.setBottomComponent(outputPanel); + inOut.setResizeWeight(0.5); + + // create active operations (middle) panel + LayoutPanel activeOperationsPanel = new LayoutPanel("Recipe"); + + // add action items + JButton filters = new JButton("Filter"); + this.requestFilterDialog = new RequestFilterDialog(); + activeOperationsPanel.addActionComponent(filters); + filters.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + int result = JOptionPane.showConfirmDialog(null, requestFilterDialog, "Request Filter", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); + if (result == JOptionPane.OK_OPTION) { + filterMask = requestFilterDialog.getFilterMask(); + } + } + }); + + JButton bakeButton = new JButton("Bake"); + activeOperationsPanel.addActionComponent(bakeButton); + bakeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + bake(false); + } + }); + + JButton saveButton = new JButton("Save"); + activeOperationsPanel.addActionComponent(saveButton); + saveButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + try { + JFileChooser fc = new JFileChooser(); + int returnVal = fc.showSaveDialog(RecipePanel.this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + save(file); + } + } catch (IOException e) { + JOptionPane.showMessageDialog(null, "The file could not be saved."); + } + } + }); + + JButton loadButton = new JButton("Load"); + activeOperationsPanel.addActionComponent(loadButton); + loadButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + try { + JFileChooser fc = new JFileChooser(); + int returnVal = fc.showOpenDialog(RecipePanel.this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + String jsonState = new String(Files.readAllBytes(Paths.get(file.getPath()))); + restoreState(jsonState); + } + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException e) { + JOptionPane.showMessageDialog(null, "The provided file could not be loaded."); + } + } + }); + + JCheckBox bakeCheckBox = new JCheckBox("Auto bake"); + bakeCheckBox.setSelected(this.autoBake); + activeOperationsPanel.addActionComponent(bakeCheckBox); + bakeCheckBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + autoBake = bakeCheckBox.isSelected(); + bake(false); + } + }); + + JButton variablesButton = new JButton("Variables"); + activeOperationsPanel.addActionComponent(variablesButton); + variablesButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + VariablesWindow vw = VariablesWindow.getInstance(); + vw.refresh(VariableStore.getInstance().getVariables()); + vw.setVisible(true); + } + }); + + JButton clearButton = new JButton("Clear"); + activeOperationsPanel.addActionComponent(clearButton); + clearButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + clear(); + } + }); + + operationLines = new JPanel(); + operationLines.setLayout(new GridBagLayout()); + + // add dummy panel + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridheight = GridBagConstraints.REMAINDER; + gbc.weightx = 1; + gbc.weighty = 1; + JPanel dummyPanel = new JPanel(); + dummyPanel.setBackground(Color.YELLOW); + + GridBagConstraints co = new GridBagConstraints(); + co.gridheight = GridBagConstraints.REMAINDER; + co.weighty = 1; + co.fill = GridBagConstraints.VERTICAL; + + operationLines.add(dummyPanel, gbc); // this is the magic!11!! + + for (int i = operationSteps; i > 0; i--) { + RecipeStepPanel opPanel = new RecipeStepPanel(String.valueOf(i), this); + operationLines.add(opPanel, co, 0); + + JPanel panel = opPanel.getOperationsPanel(); + MoveOperationMouseAdapter moma = new MoveOperationMouseAdapter(opPanel, operationLines); + panel.addMouseListener(moma ); + panel.addMouseMotionListener(moma ); + } + + JScrollPane activeOperationsScrollPane = new JScrollPane(operationLines, JScrollPane.VERTICAL_SCROLLBAR_NEVER, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + activeOperationsPanel.add(activeOperationsScrollPane); + + JSplitPane opsInOut = new JSplitPane(); + opsInOut.setResizeWeight(0.5); + + opsInOut.setLeftComponent(activeOperationsPanel); + opsInOut.setRightComponent(inOut); + + JSplitPane opSplit = new JSplitPane(); + opSplit.setRightComponent(opsInOut); + opSplit.setLeftComponent(operationsPanel); + opSplit.setResizeWeight(0.1); + + this.add(opSplit); + + AddOperationMouseAdapter dma = new AddOperationMouseAdapter(operationsTree, operationLines); + operationsTree.addMouseListener(dma); + operationsTree.addMouseMotionListener(dma); + + loadRecipeFromBurp(); + startAutoBakeTimer(); + } + + private void loadRecipeFromBurp() { + logger.log("[" + this.recipeName + "] Autoloading..."); + boolean inBurp = BurpUtils.inBurp(); + //Check if we run inside a burp + if (inBurp) { + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + String jsonState = callbacks.loadExtensionSetting("cstc_" + this.recipeName); + if (jsonState != null && jsonState != "") { + try { + logger.log("[" + this.recipeName + "] Restoring state."); + //We remove the setting and set it again to be safe in an error case + callbacks.saveExtensionSetting("cstc_" + this.recipeName, ""); + restoreState(jsonState); + callbacks.saveExtensionSetting("cstc_" + this.recipeName, jsonState); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException e) { + Logger.getInstance().err("There was an error restoring the state of RecipePanel " + this.recipeName); + } + } + } + else { + logger.log("[" + this.recipeName + "] Autoloading aborted. Not running inside Burp."); + } + } + + private void autoSaveToBurp() { + boolean inBurp = BurpUtils.inBurp(); + //Check if we run inside a burp + if (inBurp) { + try { + String jsonState = getStateAsJSON(); + BurpUtils.getInstance().getCallbacks().saveExtensionSetting("cstc_" + this.recipeName, jsonState); + } catch (IOException e) { + Logger.getInstance().err("There was an error persisting the current state of the recipe panel."); + } + } + } + + public void setInput(IHttpRequestResponse requestResponse) { + if( isRequest ) + this.inputText.setMessage(requestResponse.getRequest(), true); + else { + byte[] responseBytes = requestResponse.getResponse(); + if( responseBytes == null ) + responseBytes = "Your request has no server response yet :(".getBytes(); + this.inputText.setMessage(responseBytes, false); + } + + this.controllerOrig.setHttpRequestResponse(requestResponse); + this.controllerMod.setHttpRequestResponse(requestResponse); + + this.bake(false); + } + + private void restoreState(String jsonState) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { + // TODO do we want to remove all existing operations before loading here? + this.clear(); // Yes! + ObjectMapper mapper = new ObjectMapper(); + JsonNode stepNodes = mapper.readTree(jsonState); + if (!stepNodes.isArray()) { + throw new IOException("wrong data format"); + } + + for (int step = 0; step < stepNodes.size(); step++) { + JsonNode operationNodes = stepNodes.get(step); + if (!operationNodes.isArray()) { + throw new IOException("wrong data format"); + } + + for (int i = 0; i < operationNodes.size(); i++) { + JsonNode operationNode = operationNodes.get(i); + String operation = operationNode.get("operation").asText(); + Map parameters = mapper.convertValue(operationNode.get("parameters"), Map.class); + Class cls = (Class) Class.forName(operation); + // check if it is an operation + Operation op = cls.newInstance(); + op.load(parameters); + op.setDisabled(!operationNode.get("is_enabled").asBoolean()); + RecipeStepPanel panel = (RecipeStepPanel) this.operationLines.getComponent(step); + panel.addComponent(op, i); + } + } + } + + private String getStateAsJSON() throws IOException { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode stepsNode = mapper.createArrayNode(); + + for (int step = 0; step < this.operationSteps; step++) { + ArrayNode operationsNode = mapper.createArrayNode(); + + RecipeStepPanel stepPanel = (RecipeStepPanel) this.operationLines.getComponent(step); + List operations = stepPanel.getOperations(); + for (Operation op : operations) { + ObjectNode operationNode = mapper.createObjectNode(); + operationNode.put("operation", op.getClass().getName()); + operationsNode.add(operationNode); + operationNode.putPOJO("parameters", op.getState()); + operationNode.putPOJO("is_enabled", !op.isDisabled()); + } + stepsNode.add(operationsNode); + } + return mapper.writeValueAsString(stepsNode); + } + + private void save(File file) throws IOException { + FileWriter fw = new FileWriter(file); + fw.write(getStateAsJSON()); + fw.close(); + } + + private byte[] doBake(byte[] input) { + if (input == null || input.length == 0) { + return new byte[0]; + } + byte[] result = input.clone(); + byte[] intermediateResult = input; + boolean outputChanged; + VariableStore store = VariableStore.getInstance(); + out: for (int j = 0; j < this.operationLines.getComponentCount(); j++) { + + Component operationLine = this.operationLines.getComponent(j); + if (!(operationLine instanceof RecipeStepPanel)) { + continue; + } + + String stepVariableName = String.format("%s_step%d", this.recipeName, (j + 1)); + store.removeVariable(stepVariableName); + + intermediateResult = input; + outputChanged = false; + + List operationList = ((RecipeStepPanel)operationLine).getOperations(); + for(int i = 0; i < operationList.size(); i++) { + + Operation op = operationList.get(i); + if (op.isDisabled()) { + continue; + } + + intermediateResult = op.performOperation(intermediateResult); + outputChanged = true; + + if (op.isBreakpoint()) { + result = intermediateResult; + store.setVariable(stepVariableName, intermediateResult); + break out; + } + + i += op.getOperationSkip(); + j += op.getLaneSkip(); + } + + if (outputChanged) { + result = intermediateResult; + store.setVariable(stepVariableName, intermediateResult); + } + } + + if (BurpUtils.inBurp()) { + IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks(); + IExtensionHelpers helpers = callbacks.getHelpers(); + + IRequestInfo info; + try { + info = helpers.analyzeRequest(result); + } catch( IllegalArgumentException e ) { + // In this case there is no valid HTTP request and no Content-Length update is requried. + return result; + } + + List headers = info.getHeaders(); + int offset = info.getBodyOffset(); + + if( result.length == offset ) { + // In this case there is no body and we do not need to update the content length header. + return result; + } + + for(String header : headers) { + if(header.startsWith("Content-Length:")) { + // To update the content-length header, we just add a dummy parameter and remove it right away. + // Burps extension helpers will care about updating the length without any string transformations. + IParameter dummy = helpers.buildParameter("dummy", "dummy", IParameter.PARAM_BODY); + result = helpers.addParameter(result, dummy); + result = helpers.removeParameter(result, dummy); + break; + } + } + return result; + + } else { + return result; + } + } + + private void bake(boolean spamProtection) { + if (this.bakeTimer != null) { + this.bakeTimer.cancel(); + } + this.bakeTimer = new Timer(this.recipeName); + TimerTask tt = new TimerTask() { + @Override + public void run() { + byte[] result = doBake(inputText.getMessage()); + HashMap variables = VariableStore.getInstance().getVariables(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if( isRequest) { + outputText.setMessage(result, true); + controllerMod.setRequest(result); + } else { + outputText.setMessage(result, false); + controllerMod.setResponse(result); + } + VariablesWindow vw = VariablesWindow.getInstance(); + if (vw.isVisible()) { + vw.refresh(variables); + } + PopupVariableMenu.refresh(variables); + } + }); + autoSaveToBurp(); + } + }; + int threshold = spamProtection ? this.bakeThreshold : 0; + this.bakeTimer.schedule(tt, threshold); + } + + public byte[] bake(byte[] input) { + VariableStore store = VariableStore.getInstance(); + try { + store.lock(); + return this.doBake(input); + } finally { + store.unlock(); + } + } + + private void startAutoBakeTimer() { + TimerTask repeatedTask = new TimerTask() { + public void run() { + if (inputText.isMessageModified()) { + logger.log("autobaking"); + autoBake(); + } + } + }; + Timer timer = new Timer("Timer"); + long delay = 1000L; + long period = 1000L; + timer.scheduleAtFixedRate(repeatedTask, delay, period); + } + + private void autoBake() { + if (!this.autoBake) { + return; + } + VariableStore store = VariableStore.getInstance(); + try { + store.lock(); + this.bake(true); + } finally { + store.unlock(); + } + } + + private void clear() { + for (int step = 0; step < this.operationSteps; step++) { + RecipeStepPanel stepPanel = (RecipeStepPanel) this.operationLines.getComponent(step); + stepPanel.clearOperations(); + } + } + + @Override + public void stateChanged(ChangeEvent e) { + this.autoBake(); + } + + public boolean shouldProcess(int tool) { + return (this.filterMask & tool) != 0; + } +} diff --git a/src/main/java/de/usd/cstchef/view/RecipeStepPanel.java b/src/main/java/de/usd/cstchef/view/RecipeStepPanel.java new file mode 100644 index 0000000..89b79da --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/RecipeStepPanel.java @@ -0,0 +1,127 @@ +package de.usd.cstchef.view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.MatteBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import de.usd.cstchef.operations.*; + +public class RecipeStepPanel extends JPanel { + + private JPanel operationsLine; + private GridBagConstraints addContraints; + private ChangeListener changeListener; + + public RecipeStepPanel(String title, ChangeListener changelistener) { + this.changeListener = changelistener; + this.setLayout(new BorderLayout()); + this.setPreferredSize(new Dimension(300, 0)); + + // header + Box headerBox = Box.createHorizontalBox(); + // add borders + Border margin = BorderFactory.createEmptyBorder(10, 10, 10, 10); + MatteBorder lineBorder = new MatteBorder(0, 0, 2, 0, Color.DARK_GRAY); + CompoundBorder border = new CompoundBorder(lineBorder, margin); + headerBox.setBorder(border); + + JTextField contentTextField = new JTextField(); + contentTextField.setBorder(null); + contentTextField.setBackground(new Color(0, 0, 0, 0)); + contentTextField.setText(title); + headerBox.add(contentTextField); + + this.add(headerBox, BorderLayout.NORTH); + + // body + operationsLine = new JPanel(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.gridheight = GridBagConstraints.REMAINDER; + gbc.weightx = 1; + gbc.weighty = 1; + gbc.fill = GridBagConstraints.BOTH; + + JPanel dummyPanel = new JPanel(); + operationsLine.add(dummyPanel, gbc); + + this.addContraints = new GridBagConstraints(); + this.addContraints.gridwidth = GridBagConstraints.REMAINDER; + this.addContraints.weightx = 1; + this.addContraints.fill = GridBagConstraints.HORIZONTAL; + + JScrollPane scrollPane = new JScrollPane(operationsLine); + scrollPane.setBorder(new MatteBorder(0, 2, 0, 0, Color.DARK_GRAY)); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.getVerticalScrollBar().setUnitIncrement(16); + + this.add(scrollPane, BorderLayout.CENTER); + } + + public void addComponent(Component comp, int index) { + operationsLine.add(comp, addContraints, index); + operationsLine.revalidate(); + operationsLine.repaint(); + if (comp instanceof Operation) { + ((Operation) comp).setChangeListener(this.changeListener); + this.changeListener.stateChanged(new ChangeEvent(this)); + } + } + + public void removeComponent(Component comp) { + operationsLine.remove(comp); + operationsLine.revalidate(); + operationsLine.repaint(); + this.changeListener.stateChanged(new ChangeEvent(this)); + } + + public JPanel getOperationsPanel() { + return this.operationsLine; + } + + public List getOperations() { + List result = new ArrayList<>(); + + for (int i = 0; i < this.operationsLine.getComponentCount(); i++) { + Component op = this.operationsLine.getComponent(i); + if (!(op instanceof Operation)) { + continue; + } + + result.add((Operation) op); + } + return result; + } + + public void clearOperations() { + Component[] operations = this.operationsLine.getComponents(); + for (int i = 0; i < operations.length; i++) { + Component op = operations[i]; + if (!(op instanceof Operation)) { + continue; + } + operationsLine.remove(op); + } + operationsLine.revalidate(); + operationsLine.repaint(); + this.changeListener.stateChanged(new ChangeEvent(this)); + } +} diff --git a/src/main/java/de/usd/cstchef/view/RequestFilterDialog.java b/src/main/java/de/usd/cstchef/view/RequestFilterDialog.java new file mode 100644 index 0000000..1a8c6bb --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/RequestFilterDialog.java @@ -0,0 +1,82 @@ +package de.usd.cstchef.view; + +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import burp.IBurpExtenderCallbacks; + +public class RequestFilterDialog extends JPanel { + private LinkedHashMap filterSettings; + + public RequestFilterDialog() { + this.filterSettings = new LinkedHashMap<>(); + this.filterSettings.put(new Filter("Proxy", IBurpExtenderCallbacks.TOOL_PROXY), false); + this.filterSettings.put(new Filter("Repeater", IBurpExtenderCallbacks.TOOL_REPEATER), false); + this.filterSettings.put(new Filter("Spider", IBurpExtenderCallbacks.TOOL_SPIDER), false); + this.filterSettings.put(new Filter("Scanner", IBurpExtenderCallbacks.TOOL_SCANNER), false); + this.filterSettings.put(new Filter("Intruder", IBurpExtenderCallbacks.TOOL_INTRUDER), false); + this.filterSettings.put(new Filter("Extender", IBurpExtenderCallbacks.TOOL_EXTENDER), false); + + this.setLayout(new GridLayout(0, 2)); + + for (Map.Entry entry : this.filterSettings.entrySet()) { + Filter filter = entry.getKey(); + boolean selected = entry.getValue(); + this.add(new JLabel(filter.getName() + ": ")); + + JCheckBox box = new JCheckBox(); + box.setSelected(selected); + box.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + filterSettings.put(filter, box.isSelected()); + } + }); + this.add(box); + } + } + + public int getFilterMask() { + int filterMask = 0; + for (Map.Entry entry : this.filterSettings.entrySet()) { + Filter filter = entry.getKey(); + boolean selected = entry.getValue(); + if (selected) { + filterMask |= filter.getValue(); + } + } + return filterMask; + } + + class Filter { + private String name; + private int value; + + public Filter(String name, int value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + } +} diff --git a/src/main/java/de/usd/cstchef/view/VariablesWindow.java b/src/main/java/de/usd/cstchef/view/VariablesWindow.java new file mode 100644 index 0000000..b977237 --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/VariablesWindow.java @@ -0,0 +1,103 @@ +package de.usd.cstchef.view; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagLayout; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.HashMap; +import java.util.SortedMap; +import java.util.TreeMap; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; + +public class VariablesWindow extends JFrame { + + private static VariablesWindow instance; + + public static VariablesWindow getInstance() { + if (VariablesWindow.instance == null) { + VariablesWindow.instance = new VariablesWindow(); + } + return VariablesWindow.instance; + } + + private JLabel emptyLbl; + private JTable table; + + private VariablesWindow() { + super("Variables"); + this.setSize(new Dimension(600, 480)); + + DefaultTableModel model = new DefaultTableModel(new String[] { "Variable Name", "Content" }, 0); + this.table = new JTable(model) { + public boolean isCellEditable(int row, int column) { + return false; + }; + }; + + this.addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + if (table.getModel().getRowCount() == 0) { + setColumnWidth(new Dimension()); + } + } + }); + + this.table.setLayout(new GridBagLayout()); + this.table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + this.table.getColumnModel().getColumn(0).setPreferredWidth(200); + this.table.getColumnModel().getColumn(1).setCellRenderer(new WordWrapCellRenderer()); + this.table.getTableHeader().setReorderingAllowed(false); + this.table.getTableHeader().setResizingAllowed(false); + this.table.setFillsViewportHeight(true); + ((DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.LEFT); + + this.emptyLbl = new JLabel("no variables defined"); + this.table.add(this.emptyLbl); + + JScrollPane scrollPane = new JScrollPane(this.table); + this.add(scrollPane); + } + + public void refresh(HashMap variables) { + DefaultTableModel model = (DefaultTableModel) this.table.getModel(); + model.setRowCount(0); + this.emptyLbl.setVisible(variables.isEmpty()); + SortedMap sortedMap = new TreeMap(variables); + + for (String key : sortedMap.keySet()) { + model.addRow(new String[] { key, new String(sortedMap.get(key)) }); + } + } + + private void setColumnWidth(Dimension preferredSize) { + TableColumn contentColumn = this.table.getColumnModel().getColumn(1); + int parentWidth = this.table.getParent().getWidth(); + int width = Integer.max(preferredSize.width + WordWrapCellRenderer.MARGIN, parentWidth - this.table.getColumnModel().getColumn(0).getWidth()); + contentColumn.setPreferredWidth(width); + } + + class WordWrapCellRenderer extends JTextArea implements TableCellRenderer { + private static final int MARGIN = 20; + + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Dimension preferredSize = getPreferredSize(); + setText(value.toString()); + setSize(preferredSize.width, getPreferredSize().height); + if (table.getRowHeight(row) != getPreferredSize().height) { + table.setRowHeight(row, getPreferredSize().height); + } + setColumnWidth(preferredSize); + return this; + } + } +} diff --git a/src/main/java/de/usd/cstchef/view/View.java b/src/main/java/de/usd/cstchef/view/View.java new file mode 100644 index 0000000..5a9f8b8 --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/View.java @@ -0,0 +1,57 @@ +package de.usd.cstchef.view; + +import java.awt.BorderLayout; +import java.security.Security; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.WindowConstants; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +public class View extends JPanel { + + private RecipePanel incomingRecipePanel; + private RecipePanel outgoingRecipePanel; + private RecipePanel formatRecipePanel; + + public View() { + Security.addProvider(new BouncyCastleProvider()); + + this.setLayout(new BorderLayout()); + JTabbedPane tabbedPane = new JTabbedPane(); + + incomingRecipePanel = new RecipePanel("Incomming", false); + outgoingRecipePanel = new RecipePanel("Outgoing", true); + formatRecipePanel = new RecipePanel("Formatting", true); + + tabbedPane.addTab("Outgoing Requests", null, outgoingRecipePanel, "Outgoing requests from the browser, the repeater or another tool."); + tabbedPane.addTab("Incoming Responses", null, incomingRecipePanel, "Responses from the server."); + tabbedPane.addTab("Formating", null, formatRecipePanel, "Formating for messages."); + this.add(tabbedPane); + } + + public RecipePanel getIncomingRecipePanel() { + return this.incomingRecipePanel; + } + + public RecipePanel getOutgoingRecipePanel() { + return this.outgoingRecipePanel; + } + + public RecipePanel getFormatRecipePanel() { + return this.formatRecipePanel; + } + + public static void main(String[] args) { + JFrame frame = new JFrame("CSTC"); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + View view = new View(); + + frame.setContentPane(view); + frame.setSize(800, 600); + frame.setVisible(true); +// frame.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH); + } +} diff --git a/src/main/java/de/usd/cstchef/view/ui/FormatTextField.java b/src/main/java/de/usd/cstchef/view/ui/FormatTextField.java new file mode 100644 index 0000000..9eea88c --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/ui/FormatTextField.java @@ -0,0 +1,90 @@ +package de.usd.cstchef.view.ui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.UnsupportedEncodingException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.Box; +import javax.swing.JComboBox; +import javax.swing.JPanel; +import javax.swing.event.DocumentListener; +import org.bouncycastle.util.encoders.Hex; + +public class FormatTextField extends JPanel implements ActionListener { + + public VariableTextField txtField; + private JComboBox formatBox; + private DocumentListener docListener; + + public FormatTextField() { + this.setLayout(new BorderLayout()); + this.setBackground(new Color(0, 0, 0, 0)); + this.txtField = new VariableTextField(); + this.formatBox = new JComboBox<>(new String[] {"Raw", "UTF-8", "Hex", "Latin1", "Base64"}); + this.formatBox.addActionListener(this); + + Box box = Box.createHorizontalBox(); + box.add(formatBox); + box.add(Box.createHorizontalStrut(10)); + box.add(txtField); + + this.add(box); + } + + public Map getValues() { + Map values = new HashMap<>(); + values.put("text", this.txtField.getText()); + values.put("encoding", this.formatBox.getSelectedItem().toString()); + return values; + } + + public void setValues(Map values) { + String text = values.get("text"); + this.txtField.setText(text); + Object encoding = values.get("encoding"); + this.formatBox.setSelectedItem(encoding); + } + + public byte[] getText() throws UnsupportedEncodingException { + + byte[] raw = this.txtField.getBytes(); + byte[] result = null; + + switch ((String) this.formatBox.getSelectedItem()) { + case "Raw": + result = raw; + break; + case "Hex": + result = Hex.decode(raw); + break; + case "Base64": + result = Base64.getDecoder().decode(raw); + break; + case "Latin1": + result = this.txtField.getText().getBytes("ISO-8859-1"); + break; + case "UTF-8": + result = this.txtField.getText().getBytes("UTF-8"); + break; + } + return result; + } + + public void addDocumentListener(DocumentListener listener) { + this.docListener = listener; + this.txtField.getDocument().addDocumentListener(listener); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (this.docListener != null) { + this.docListener.changedUpdate(null); + } + } + +} diff --git a/src/main/java/de/usd/cstchef/view/ui/VariableTextArea.java b/src/main/java/de/usd/cstchef/view/ui/VariableTextArea.java new file mode 100644 index 0000000..891ffcb --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/ui/VariableTextArea.java @@ -0,0 +1,44 @@ +package de.usd.cstchef.view.ui; + +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.event.DocumentListener; + +import de.usd.cstchef.Utils; +import de.usd.cstchef.view.PopupVariableMenu; + + +public class VariableTextArea extends JScrollPane { + + private JTextArea txtArea; + + public VariableTextArea() { + this.txtArea = new JTextArea(); + this.setViewportView(this.txtArea); + this.txtArea.setRows(5); + this.txtArea.setComponentPopupMenu(new PopupVariableMenu(this.txtArea)); + } + + public String getText() { + String text = this.txtArea.getText(); + return Utils.replaceVariables(text); + } + + public byte[] getBytes() { + byte[] bytes = this.txtArea.getText().getBytes(); + return Utils.replaceVariablesByte(bytes); + } + + public void setText(String text) { + this.txtArea.setText(text); + } + + public String getRawText() { + return this.txtArea.getText(); + } + + public void addDocumentListener(DocumentListener notifyChangeListener) { + this.txtArea.getDocument().addDocumentListener(notifyChangeListener); + } + +} diff --git a/src/main/java/de/usd/cstchef/view/ui/VariableTextField.java b/src/main/java/de/usd/cstchef/view/ui/VariableTextField.java new file mode 100644 index 0000000..7df0a47 --- /dev/null +++ b/src/main/java/de/usd/cstchef/view/ui/VariableTextField.java @@ -0,0 +1,30 @@ +package de.usd.cstchef.view.ui; + +import javax.swing.JTextField; + +import de.usd.cstchef.Utils; +import de.usd.cstchef.view.PopupVariableMenu; + +public class VariableTextField extends JTextField { + + public VariableTextField() { + super(); + this.setComponentPopupMenu(new PopupVariableMenu(this)); + } + + @Override + public String getText() { + String text = super.getText(); + return Utils.replaceVariables(text); + } + + public byte[] getBytes() { + byte[] bytes = super.getText().getBytes(); + return Utils.replaceVariablesByte(bytes); + } + + public String getRawText() { + return super.getText(); + } + +} diff --git a/src/test/java/de/usd/cstcchecf/operations/AdditionTest.java b/src/test/java/de/usd/cstcchecf/operations/AdditionTest.java new file mode 100644 index 0000000..506b2ba --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/AdditionTest.java @@ -0,0 +1,60 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.Addition; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class AdditionTest extends Addition +{ + private String number; + private boolean isFloat; + + protected double getNumber() + { + return Double.valueOf(number); + } + + protected boolean isFloat() + { + return isFloat; + } + + @Test + public void SimpleAdditionTest() throws Exception + { + number = "10"; + isFloat = false; + + String testValue = "22"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("32"); + } + + @Test + public void AdditionFloatTest() throws Exception + { + number = "2.2"; + isFloat = true; + + String testValue = "2.2"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("4.4"); + } + + @Test + public void AdditionFloatRoundTest() throws Exception + { + number = "2.2"; + isFloat = false; + + String testValue = "2.2"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("4"); + } +} \ No newline at end of file diff --git a/src/test/java/de/usd/cstcchecf/operations/DivideListTest.java b/src/test/java/de/usd/cstcchecf/operations/DivideListTest.java new file mode 100644 index 0000000..8731f7b --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/DivideListTest.java @@ -0,0 +1,78 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.Delimiter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.DivideList; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class DivideListTest extends DivideList +{ + private String delimiter; + private boolean isFloat; + + protected Delimiter getDelimiter() throws IllegalArgumentException + { + Delimiter delim = Delimiter.getByName(delimiter); + + if( delim == null ) + throw new IllegalArgumentException("Invalid delimiter."); + + return delim; + } + + protected boolean isFloat() + { + return isFloat; + } + + @Test + public void CommaDivideTest() throws Exception + { + delimiter = "Comma"; + isFloat = false; + + String testValue = "8,2,4"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("1"); + } + + @Test + public void CommaDivideFloatTest() throws Exception + { + delimiter = "Comma"; + isFloat = true; + + String testValue = "8,2,4,2"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("0.5"); + } + + @Test + public void SpaceDivideTest() throws Exception + { + delimiter = "Space"; + isFloat = false; + + String testValue = "8 2 4 0.5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("2"); + } + + @Test + public void SpaceDivideFloatTest() throws Exception + { + delimiter = "Space"; + isFloat = true; + + String testValue = "8 2 4 4 0.5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("0.5"); + } +} \ No newline at end of file diff --git a/src/test/java/de/usd/cstcchecf/operations/DivideTest.java b/src/test/java/de/usd/cstcchecf/operations/DivideTest.java new file mode 100644 index 0000000..6759619 --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/DivideTest.java @@ -0,0 +1,56 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.Divide; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class DivideTest extends Divide +{ + private String number; + private boolean isFloat; + private boolean isReverse; + + protected double getNumber() + { + return Double.valueOf(number); + } + + protected boolean isFloat() + { + return isFloat; + } + + protected boolean isReverse() + { + return isReverse; + } + + @Test + public void SimpleDivideTest() throws Exception + { + number = "2"; + isFloat = false; + isReverse = false; + + String testValue = "4"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("2"); + } + + @Test + public void ReverseDivideTest() throws Exception + { + number = "2"; + isFloat = true; + isReverse = true; + + String testValue = "4"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("0.5"); + } +} \ No newline at end of file diff --git a/src/test/java/de/usd/cstcchecf/operations/MeanTest.java b/src/test/java/de/usd/cstcchecf/operations/MeanTest.java new file mode 100644 index 0000000..f7f2a49 --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/MeanTest.java @@ -0,0 +1,78 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.Delimiter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.Mean; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class MeanTest extends Mean +{ + private String delimiter; + private boolean isFloat; + + protected Delimiter getDelimiter() throws IllegalArgumentException + { + Delimiter delim = Delimiter.getByName(delimiter); + + if( delim == null ) + throw new IllegalArgumentException("Invalid delimiter."); + + return delim; + } + + protected boolean isFloat() + { + return isFloat; + } + + @Test + public void CommaMeanTest() throws Exception + { + delimiter = "Comma"; + isFloat = false; + + String testValue = "8,2,5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("5"); + } + + @Test + public void CommaMeanFloatTest() throws Exception + { + delimiter = "Comma"; + isFloat = true; + + String testValue = "0.2,0.3,0.4,0.1"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("0.25"); + } + + @Test + public void SpaceMeanTest() throws Exception + { + delimiter = "Space"; + isFloat = false; + + String testValue = "8 2 5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("5"); + } + + @Test + public void SpaceDivideFloatTest() throws Exception + { + delimiter = "Space"; + isFloat = true; + + String testValue = "0.2 0.3 0.4 0.1"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("0.25"); + } +} \ No newline at end of file diff --git a/src/test/java/de/usd/cstcchecf/operations/MedianTest.java b/src/test/java/de/usd/cstcchecf/operations/MedianTest.java new file mode 100644 index 0000000..59bca42 --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/MedianTest.java @@ -0,0 +1,54 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.Delimiter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.Median; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class MedianTest extends Median +{ + private String delimiter; + private boolean isFloat; + + protected Delimiter getDelimiter() throws IllegalArgumentException + { + Delimiter delim = Delimiter.getByName(delimiter); + + if( delim == null ) + throw new IllegalArgumentException("Invalid delimiter."); + + return delim; + } + + protected boolean isFloat() + { + return isFloat; + } + + @Test + public void CommaMedianTest() throws Exception + { + delimiter = "Comma"; + isFloat = false; + + String testValue = "1,2,3,4,5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("3"); + } + + @Test + public void CommaMedianFloatTest() throws Exception + { + delimiter = "Comma"; + isFloat = true; + + String testValue = "1,2,3.5,4,5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("3.5"); + } +} \ No newline at end of file diff --git a/src/test/java/de/usd/cstcchecf/operations/MultiplyListTest.java b/src/test/java/de/usd/cstcchecf/operations/MultiplyListTest.java new file mode 100644 index 0000000..860fb68 --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/MultiplyListTest.java @@ -0,0 +1,79 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.Delimiter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.MultiplyList; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class MultiplyListTest extends MultiplyList +{ + private String delimiter; + private boolean isFloat; + + protected Delimiter getDelimiter() throws IllegalArgumentException + { + Delimiter delim = Delimiter.getByName(delimiter); + + if( delim == null ) + throw new IllegalArgumentException("Invalid delimiter."); + + return delim; + } + + protected boolean isFloat() + { + return isFloat; + } + + @Test + public void CommaMultiplyTest() throws Exception + { + delimiter = "Comma"; + isFloat = false; + + String testValue = "1,2,3,4,5,6"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("720"); + } + + @Test + public void CommaMultiplyFloatTest() throws Exception + { + delimiter = "Comma"; + isFloat = true; + + String testValue = "3,0.5,0.5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("0.75"); + } + + @Test + public void SpaceMultiplyTest() throws Exception + { + delimiter = "Space"; + isFloat = false; + + String testValue = "1 2 3 4 5 6"; + byte[] result = perform(testValue.getBytes()); + + System.out.println(new String(result)); + assert new String(result).equals("720"); + } + + @Test + public void SpaceMultiplyFloatTest() throws Exception + { + delimiter = "Space"; + isFloat = true; + + String testValue = "3 0.5 0.5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("0.75"); + } +} \ No newline at end of file diff --git a/src/test/java/de/usd/cstcchecf/operations/MultiplyTest.java b/src/test/java/de/usd/cstcchecf/operations/MultiplyTest.java new file mode 100644 index 0000000..066df18 --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/MultiplyTest.java @@ -0,0 +1,60 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.Multiply; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class MultiplyTest extends Multiply +{ + private String number; + private boolean isFloat; + + protected double getNumber() + { + return Double.valueOf(number); + } + + protected boolean isFloat() + { + return isFloat; + } + + @Test + public void SimpleMultiplyTest() throws Exception + { + number = "10"; + isFloat = false; + + String testValue = "22"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("220"); + } + + @Test + public void MultiplyFloatTest() throws Exception + { + number = "2.2"; + isFloat = true; + + String testValue = "2.2"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).startsWith("4.84"); + } + + @Test + public void MultiplyRoundTest() throws Exception + { + number = "2.2"; + isFloat = false; + + String testValue = "2.2"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("5"); + } +} \ No newline at end of file diff --git a/src/test/java/de/usd/cstcchecf/operations/SubtractionTest.java b/src/test/java/de/usd/cstcchecf/operations/SubtractionTest.java new file mode 100644 index 0000000..533a13b --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/SubtractionTest.java @@ -0,0 +1,62 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.Addition; +import de.usd.cstchef.operations.arithmetic.Subtraction; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class SubtractionTest extends Subtraction +{ + private String number; + private boolean isFloat; + + protected double getNumber() + { + return Double.valueOf(number); + } + + protected boolean isFloat() + { + return isFloat; + } + + @Test + public void SimpleSubtraction() throws Exception + { + number = "10"; + isFloat = false; + + String testValue = "22"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("12"); + } + + @Test + public void SubtractionFloatTest() throws Exception + { + number = "2.1"; + isFloat = true; + + String testValue = "2.2"; + byte[] result = perform(testValue.getBytes()); + + System.out.println(new String(result)); + assert new String(result).startsWith("0.1"); + } + + @Test + public void SubractionRoundTest() throws Exception + { + number = "2.2"; + isFloat = false; + + String testValue = "2.8"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("1"); + } +} \ No newline at end of file diff --git a/src/test/java/de/usd/cstcchecf/operations/SumTest.java b/src/test/java/de/usd/cstcchecf/operations/SumTest.java new file mode 100644 index 0000000..69f5357 --- /dev/null +++ b/src/test/java/de/usd/cstcchecf/operations/SumTest.java @@ -0,0 +1,78 @@ +package de.usd.cstcchecf.operations; + +import org.junit.Test; + +import de.usd.cstchef.Delimiter; +import de.usd.cstchef.operations.Operation.OperationInfos; +import de.usd.cstchef.operations.OperationCategory; +import de.usd.cstchef.operations.arithmetic.Sum; + +@OperationInfos(name = "Test", category = OperationCategory.ARITHMETIC, description = "Test class") +public class SumTest extends Sum +{ + private String delimiter; + private boolean isFloat; + + protected Delimiter getDelimiter() throws IllegalArgumentException + { + Delimiter delim = Delimiter.getByName(delimiter); + + if( delim == null ) + throw new IllegalArgumentException("Invalid delimiter."); + + return delim; + } + + protected boolean isFloat() + { + return isFloat; + } + + @Test + public void CommaSumTest() throws Exception + { + delimiter = "Comma"; + isFloat = false; + + String testValue = "1,2,3,4,5,6"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("21"); + } + + @Test + public void CommaSumFloatTest() throws Exception + { + delimiter = "Comma"; + isFloat = true; + + String testValue = "1,2,3,4,5,6"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("21.0"); + } + + @Test + public void SpacesumTest() throws Exception + { + delimiter = "Space"; + isFloat = false; + + String testValue = "1.0 2.1 3.2 4.3 5.4 6.5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("23"); + } + + @Test + public void SpacesumFloatTest() throws Exception + { + delimiter = "Space"; + isFloat = true; + + String testValue = "1.0 2.1 3.2 4.3 5.4 6.5"; + byte[] result = perform(testValue.getBytes()); + + assert new String(result).equals("22.5"); + } +} \ No newline at end of file