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