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