Decoder Improved Burp Suite Plugin Release, Part 2

Summary

In the previous blog post, we walked through the primary benefits of using Decoder Improved over the Burp Suite’s built-in decoder. This blog post will focus on adding new functionality to Decoder Improved by walking through implementing new trivial text modifiers and modes. At the end of this blog post, the reader will have a solid understanding of how Decoder Improved modifies text and how one can add their own text modifiers.

Extending Decoder Improved

Decoder Improved has an easy-to-use object-oriented interface for adding new UI modes and extending existing ones (e.g. encode, decode, hash). The basic process involves creating a new class that inherits from either ModificationMode, if creating a new mode, or ByteModifier, if creating a new data modifier for an existing mode. In either case, one implements the modifyBytes method to update data passed through the source pane. After creating the new class, it should be registered directly by modifying the respective container class implementation. For example, if extending an existing mode, an instance of the new class should be added to the respective ArrayList (e.g. encoders for EncodeMode). If adding a new mode, an instance of the new class should be passed in an additional call to the addMode method within the ModificationModeManager constructor.

Extending Existing Modes

Let’s go through a contrived example for developing a new encoder that returns "bar" if the input is "foo" or throws an exception for all other input.

FooBarEncoder.java

    package trust.nccgroup.decoderimproved;

    public class FooBarEncoder extends ByteModifier {
        public FooBarEncoder() {
            super("FooBar");
        }

        // If the input = 'foo', return 'bar', otherwise throw a ModificationException
        public byte[] modifyBytes(byte[] input) throws  ModificationException{
            // All input strings are UTF-8
            if (new String(input).equals("foo")) {
                return "bar".getBytes();
            } else {
                throw new ModificationException("Invalid Input, Input is not foo");
            }
        }
    }

As shown above, implementing a new encoder is straightforward. First, we created a new FooBarEncoder extending the parent class ByteModifier. Within the constructor definition, we call super, passing "FooBar" as the sole argument to set the combo box display name. Then, we implemented the modifyBytes method, which throws a ModificationException and returns a byte[]. A ModificationException should only be thrown if the input fails to pass any data-specific validation checks. Afterwards, we finish implementing the method body by converting the input byte[] into a String, comparing the String against "foo", and returning a "byte[]" containing “bar” if the comparison is correct or throwing an exception otherwise.

EncodeMode.java

    public EncodeMode() {
        // "super" contains the name that will appear in the mode selection combobox
        super("Encode as...");

        // All encoders are managed within this arraylist, new encoders must be added here to appear
        encoders = new ArrayList<>();
        encoders.add(new PlaintextEncoder());
        encoders.add(new URLEncoder());
        encoders.add(new URLSpecialCharEncoder());
        encoders.add(new HTMLEncoder());
        encoders.add(new HTMLSpecialCharEncoder());
        encoders.add(new Base64Encoder());
        encoders.add(new ASCIIHexEncoder());
        encoders.add(new GZIPEncoder());
        encoders.add(new FooBarEncoder());
        ...
    }

To add the FooBarEncoder to the Encoders combo box, a new FooBarEncoder should be added to the encoders ArrayList.

Adding New Modes

Creating new modes is slightly more involved than extending existing modes, as modes must manage their own swing components; however, the rest of the process is similarly simple. Let’s go through another contrived example where we develop a new mode that replaces the input with data from a text box.

TextReplaceMode.java

    package trust.nccgroup.decoderimproved;

    import javax.swing.*;
    import java.awt.*;

    public class TextReplaceMode extends ModificationMode {
        // Swing components
        private JLabel replaceLabel;
        private JTextField replaceTextField;
        private JPanel replaceBoxPanel;
        private JPanel comboBoxPanel;

        public TextReplaceMode() {
            // The name to appear in the combo box
            super("Replace");

            // The replacement text field and label
            replaceLabel = new JLabel("Replace: ");
            replaceTextField = new JTextField();

            // Need to make a JPanel to contain the textfield and label
            replaceBoxPanel = new JPanel();
            replaceBoxPanel.setLayout(new BoxLayout(replaceBoxPanel, BoxLayout.LINE_AXIS));
            replaceBoxPanel.setMaximumSize(new Dimension(180, 25));
            replaceBoxPanel.setMinimumSize(new Dimension(180, 25));
            replaceBoxPanel.setPreferredSize(new Dimension(180, 25));

            // Add the label and the text field
            replaceBoxPanel.add(replaceLabel);
            replaceBoxPanel.add(replaceTextField);

            // Need a second JPanel to contain the first to keep the sizing correct.
            comboBoxPanel = new JPanel();
            comboBoxPanel.setLayout(new BoxLayout(comboBoxPanel, BoxLayout.PAGE_AXIS));
            comboBoxPanel.setMaximumSize(new Dimension(180, 20));
            comboBoxPanel.setMinimumSize(new Dimension(180, 20));
            comboBoxPanel.setPreferredSize(new Dimension(180, 20));
            comboBoxPanel.add(replaceBoxPanel);

            // UI is a JPanel defined within ModificationMode that is used to draw the UI
            ui.add(comboBoxPanel);
        }

        // modifyBytes is called whenever the text is updated and returns the modified input
        // Which in this case is just the text of replaceTextField
        public byte[] modifyBytes(byte[] input) {
            return replaceTextField.getText().getBytes();
        }
    }

First, we create a new class that extends ModificationMode, the parent class that all new modes must inherit from. In the constructor, we call super with the name to appear in the master mode selector, and then initialize the swing components that will draw the mode user interface. After configuring the relevant swing components, we add them to ui, a JPanel defined in the parent class that manages each mode’s user interface. After this, we implement the modifyBytes functions that perform the actual data modification. In this example, our modifyBytes implementation method simply returns the text from a text field as a byte array.

ModificationModeManager.java

    public class ModificationModeManager {
        ...
        public ModificationModeManager() {
            ...

            addMode(new EncodeMode());
            addMode(new DecodeMode());
            addMode(new HashMode());
            addMode(new BaseConvertMode());
            addMode(new FindAndReplaceMode());
            addMode(new TextReplaceMode());
            ...
        }

        private void addMode(ModificationMode mode) {
            modes.add(mode);
            modeComboBox.addItem(mode.getName());
            modeUI.add(mode.getUI(), mode.getName());
            if (modes.size() == 1) {
                layoutManager.show(modeUI, mode.getName());
            }
        }
        ...
    }

To register the new mode in Decoder Improved, we invoke the addMode method with a new instance of TextReplaceMode as part of the ModificationModeManager constructor.

Conclusion

In conclusion, Decoder Improved is a Burp Suite plugin that improves on Burp Suite’s built-in decoder and provides users with the ability to adapt the plugin to suit any custom data manipulation needs. This plugin provides a comprehensive superset of functionality and allows users to improve their ability to manipulate data within Burp Suite. Decoder Improved is available for download at https://github.com/nccgroup/Decoder-Improved.

Published date:  03 October 2017

Written by:  Justin Moore

Filter By Service

Filter By Date