Trustwave Unveils New Offerings to Maximize Value of Microsoft Security Investments. Learn More

Trustwave Unveils New Offerings to Maximize Value of Microsoft Security Investments. Learn More

Services
Capture
Managed Detection & Response

Eliminate active threats with 24/7 threat detection, investigation, and response.

twi-managed-portal-color
Co-Managed SOC (SIEM)

Maximize your SIEM investment, stop alert fatigue, and enhance your team with hybrid security operations support.

twi-briefcase-color-svg
Advisory & Diagnostics

Advance your cybersecurity program and get expert guidance where you need it most.

tw-laptop-data
Penetration Testing

Test your physical locations and IT infrastructure to shore up weaknesses before exploitation.

twi-database-color-svg
Database Security

Prevent unauthorized access and exceed compliance requirements.

twi-email-color-svg
Email Security

Stop email threats others miss and secure your organization against the #1 ransomware attack vector.

tw-officer
Digital Forensics & Incident Response

Prepare for the inevitable with 24/7 global breach response in-region and available on-site.

tw-network
Firewall & Technology Management

Mitigate risk of a cyberattack with 24/7 incident and health monitoring and the latest threat intelligence.

Solutions
BY TOPIC
Offensive Security
Solutions to maximize your security ROI
Microsoft Exchange Server Attacks
Stay protected against emerging threats
Rapidly Secure New Environments
Security for rapid response situations
Securing the Cloud
Safely navigate and stay protected
Securing the IoT Landscape
Test, monitor and secure network objects
Why Trustwave
About Us
Awards and Accolades
Trustwave SpiderLabs Team
Trustwave Fusion Security Operations Platform
Trustwave Security Colony
Partners
Technology Alliance Partners
Key alliances who align and support our ecosystem of security offerings
Trustwave PartnerOne Program
Join forces with Trustwave to protect against the most advance cybersecurity threats
SpiderLabs Blog

JSON Crypto Helper a Ruby-based Burp Extension for JSON Encryption/Decryption - Part I

Burp Suite is one of my favorite tools when performing security assessments of web applications. Although it can handle almost all the basic situations by itself, corner case applications need some extra Burp customizations to maximize your assessment capabilities. For this purpose, Burp provides an extension API that enables you to extend its functionality. Extensions can be written in Java, Python or Ruby.

This is the first post in a three-part series about how to write a simple Ruby extension that helps deal with encrypted JSON messages (read part two here). You can download the complete extension code here. It was inspired by the JSON Decoder extension by Michal Melewski, which is available here.

Context

The last mobile application I tested used encrypted JSON messages to communicate with the server and any tampering or fuzzing was almost impossible. Requesting URLs in a browser looked like this:

12160_dcbdcc0b-c700-43bc-b547-2d50da3b9ffc

As you can see, only the value string was encrypted and encoded with base64:

{
"hello":"9DpW68SsC5nHi5PeyXEHEA==",
"test":{
"input1":"irTKsV484FzLRuH2A1r42Q==",
"input2":"fFAUsaRu8W47lfusAtzV88ewPj9etXuoPtbCUUMzQHs="
}
}

From a security perspective, the additional encryption step is not really efficient because the encryption/decryption is performed locally on the device; it is not difficult to retrieve all the information needed to decrypt the message directly from the application binary. And that's what I did. So, after reversing the binary (an iOS application), I managed to extract the following information (NOTE: the encryption key and the IV have been changed for demonstration purposes):

Encryption Key (hex digits): 0cc91185341d6a27c380e97fed30b4a1dcafd7f5044f09cc7fa6b3fa0df290b

IV (hex digits): abdad4a94d544b52f4782e2856f82874

Encryption Algorithm: AES 128bit CBC

You can verify this using OpenSSL from the terminal:

$ echo "9DpW68SsC5nHi5PeyXEHEA==" | openssl enc -aes-128-cbc -base64 -d -K a0cc91185341d6a27c380e97fed30b4a1dcafd7f5044f09cc7fa6b3fa0df290b -iv abdad4a94d544b52f4782e2856f82874
=> world!

So, now you have all you need to get rid of the encryption and use Burp the same way you do with unencrypted content. The end goal is to automatically decrypt the value anywhere in the Burp interface, automatically encrypt the value you want to send to the server (using the Repeater tool for example) and fuzz the JSON parameters with on-the-fly encryption (Intruder tool).

Setup the environment

Because we will use Ruby to implement the extension, you need to setup the environment with JRuby. The easiest way to do it is using RVM. Just install it using the RVM install guide and run the following commands in the directory you will create your Ruby extension:

$ rvm install jruby
$ rvm --ruby-version use jruby@burp --create

This will install JRuby (if you don't have it yet) and create the gemset burp. It also adds .ruby-version and .ruby-gemset files to tell RVM which ruby version and which gemset to use when entering the directory.

Then just run Burp like this:

JRUBY_HOME=$MY_RUBY_HOME java -XX:MaxPermSize=1G -Xmx1g -Xms1g -jar [burp_install_dir]/burpsuite_pro_v1.6.09.jar

It is important to setup the JRUBY_HOME environment variable to tell Burp where the JRuby environment is located.

IBurpExtender interface

The first thing to do is to implement the IBurpExtender interface with the method #registerExtenderCallbacks.

require 'java'
java_import 'burp.IBurpExtender'

class BurpExtender
include IBurpExtender

def registerExtenderCallbacks(callbacks)
callbacks.setExtensionName("JSON Crypto Helper")
end
end

This method is called when the extension is loaded; passing a callbacks instance that implements the IBurpExtenderCallbacks interface. This instance will be used to perform many actions, for example here, #setExtensionName is used to inform the extension name that will be displayed in Burp.

To load the extension you need first to configure Burp Suite Extender tool (Options tab) and specify the path where the JRuby jar is installed. If you're using RVM, it should be in your RVM project path, commonly installed here: $HOME/.rvm/rubies/jruby-x.x.x/lib/jruby.jar.

9488_5c103ad4-4b62-41bf-a1d2-73632f9df999

Then select Add in the Extensions tab, select the extension type Ruby and your .rb file. You should see your new extension showing up in the list:

11247_b02c681f-4bfb-44a5-8436-fbe691f36f19

Creating a Custom Tab

In order to interact with any Burp tools, you will need to create a specific tab that will display the decrypted JSON content. To do so, you need to implement the IMessageEditorTabFactory interface and register your extension with #registerMessageEditorTabFactory. Then you create a separate class that will take care of it (I called it JSONDecryptorTab) and instantiate it in the #createNewInstance method. Because you will use the callbacks a lot, it is a good idea to create an instance variable to easily access it inside JSONDecryptorTab instances.

require 'java'
java_import 'burp.IBurpExtender'
java_import 'burp.IMessageEditorTabFactory'

class BurpExtender
include IBurpExtender
include IMessageEditorTabFactory
attr_reader :callbacks

def registerExtenderCallbacks(callbacks)
@callbacks = callbacks
callbacks.setExtensionName("JSON Crypto Helper")
callbacks.registerMessageEditorTabFactory(self)
end

def createNewInstance(controller, editable)
JSONDecryptorTab.new(@callbacks, editable)
end
end

Let's see how the JSONDecryptorTab class looks like. First it needs to implement the IMessageEditorTab interface:

class JSONDecryptorTab
include IMessageEditorTab
...[SNIP]...

and the following methods:

  • #initialize: the constructor, which setups some instance variable:
def initialize(callbacks, editable)
# Burp Suite useful helpers:
@helper = callbacks.get_helpers()
# Create a Burp's plain text editor to use with this extension:
@txt_input = callbacks.create_text_editor()
# Indicates if the text editor is read-only or not:
@editable = editable
end
  • #getTabCaption: the tab name that will be displayed by Burp
def getTabCaption
return "JSON Crypto Helper"
end
  • #isEnabled: this method is invoked each time Burp displays a new message to check if the new custom tab should be displayed. It should return a Boolean (see below).
  • #setMessage: this method is invoked each time a new message is displayed in your custom tab. This method will take care of processing the message, decrypting the JSON and displaying it (see below).
  • #getMessage: this method is invoked each time you leave the custom tab. It returns an array of bytes that will be used by Burp (see below).
  • #isModified: this method is invoked after calling #getMessage and if the editor tab is editable (in the Repeater tool for example). It should return true if the message has been edited. You simply use the value returned by #text_modified? of the text editor object:
def isModified
return @txt_input.text_modified?
end
  • #getSelectedData: not in use, but still need to be defined.

Decrypting JSON

Burp invokes the #isEnabled method to know if the custom tab has to be displayed for a given message (request or response). In this method, you will simply analyze the content and check if it is a proper JSON:

def isEnabled(content, is_request)
return false if content.nil? or content.empty?
if is_request
info = @helper.analyze_request(content)
else
info = @helper.analyze_response(content)
end
return json?(info, is_request)
end

The method #json? uses the information already gathered by Burp:

def json?(info, is_request)
if is_request
return info.content_type == IRequestInfo::CONTENT_TYPE_JSON
end
return (info.stated_mime_type == "JSON" or info.inferred_mime_type == "JSON")
end

Don't forget to import the java interface for the constant CONTENT_TYPE_JSON:

java_import 'burp.IRequestInfo'

Now the tab should be displayed on every JSON request or response. Next step, you need to fill it with the decrypted JSON. The #setMessage method will take care of this:

def setMessage(content, is_request)
return if content.nil? or content.empty? or @txt_input.text_modified?
if is_request
info = @helper.analyze_request(content)
else
info = @helper.analyze_response(content)
end
headers = content[ 0..(info.get_body_offset - 1) ].to_s
body = content[ info.get_body_offset..-1 ].to_s
body = process_json(body, :decrypt) if json?(info, is_request)
@txt_input.text = (headers + body).to_java_bytes
@txt_input.editable = @editable
end

Basically, the method analyses the message content, extracts the body, processes it and fills the editor.

#process_json will take care of decrypting/encrypting the JSON message. First, it will parse the content using the JSON Ruby library, decrypt/encrypt it and finally generate a well formatted JSON using #pretty_generate from the same library:

def process_json(json, mode = :no_encryption)
message = ""
begin
json_tmp = JSON.parse(json)
if mode == :decrypt
json_tmp = decrypt_json(json_tmp)
elsif mode == :encrypt
json_tmp = encrypt_json(json_tmp)
end
message << JSON.pretty_generate(json_tmp)
rescue OpenSSL::Cipher::CipherError => e
# not encrypted, ignore and return the original message
puts "process_json: Cryptography error: #{e.message}"
message << json
rescue JSON::ParserError => e
puts "process_json: Parsing error: #{e.message}"
message << json
end
message
end

Note that in case of decryption/encryption or parsing errors, the method rolls-back to the unmodified JSON message.

Decryption and Encryption Routines

I created a separate module for all the cryptographic methods. You will need to include it in the JSONDecryptorTab class.

module EncryptionHelper
# Key and IV retrieved from the application binary
KEY = "\xa0\xcc\x91\x18\x53\x41\xd6\xa2\x7c\x38\x0e\x97\xfe\xd3\x0b\x4a\x1d\xca\xfd\x7f\x50\x44\xf0\x9c\xc7\xfa\x6b\x3f\xa0\xdf\x29\x0b"
IV = "\xab\xda\xd4\xa9\x4d\x54\x4b\x52\xf4\x78\x2e\x28\x56\xf8\x28\x74"
ALGO = "aes-128-cbc"

def encrypt text
cipher = OpenSSL::Cipher::Cipher.new(ALGO)
cipher.encrypt
cipher.key = KEY
cipher.iv = IV
ciphertext = cipher.update(text)
ciphertext << cipher.final
end

def decrypt ciphertext
cipher = OpenSSL::Cipher::Cipher.new(ALGO)
cipher.decrypt
cipher.key = KEY
cipher.iv = IV
text = cipher.update(ciphertext)
text << cipher.final
end

def encode_b64 text
[text].pack('m0')
end

def decode_b64 encoded_text
encoded_text.unpack('m')[0]
end

# This method will base64-decode and decrypt each value recursively
def decrypt_json(json)
json.each do |key, value|
if value.is_a?(Hash)
json[key] = decrypt_json(value)
else
value_tmp = decode_b64(value)
if value_tmp.empty?
json[key] = value
else
json[key] = decrypt(value_tmp)
end
end
end
json
end

# This method will encrypt and base64-encode each value recursively
def encrypt_json(json)
json.each do |key, value|
if value.is_a?(Hash)
json[key] = encrypt_json(value)
else
if value.empty?
json[key] = value
else
json[key] = encode_b64(encrypt(value))
end
end
end
json
end
end

Also, don't forget to require openssl and json in the file:

require "openssl"
require "json"

You are now able to decrypt JSON messages in the new custom tab, which is available in any tool. For example, in the Proxy tool:

12069_d7b32ff6-71ee-4ea1-8d13-3804449ee151

Parting Thoughts

With this first post we covered the basics of Burp Extender tool and learned how to write a simple ruby-based extension. We took an encrypted JSON as an example but this also works with any content you want to process before displaying. For example, it won't be too complicated to implement a parser for an in-house communication protocol used by the application.

In the next post I will explain how to automatically encrypt the JSON values using the Repeater tool. This will enable you to write or modify a plaintext JSON and send it encrypted to the remote server.

Stay tuned!

Latest SpiderLabs Blogs

Clockwork Blue: Automating Security Defenses with SOAR and AI

It’s impractical to operate security operations alone, using manual human processes. Finding opportunities to automate SecOps is an underlying foundation of Zero Trust and an essential architecture...

Read More

Professional Services Sector Under Attack - Trustwave SpiderLabs Report 2024

Recent research by Trustwave SpiderLabs, detailed in their newly published report "2024 Professional Services Threat Landscape: Trustwave Threat Intelligence Briefing and Mitigation Strategies,"...

Read More

Atlas Oil: The Consequences of a Ransomware Attack

Overview Atlas Oil, a major player in the oil and fuel distribution industry, fell victim to a ransomware attack orchestrated by the Black Basta group. This attack not only compromised sensitive...

Read More