Bypass client-side generated HTTP security headers

Every now and then when doing a security test on a web application I have to deal with client-side generated HTTP headers that are there for security reasons. These headers can cause problems during a security test. Fortunately they can easily be bypassed using Burp Suite.

HTTP "security" header

Let me explain the concept of a HTTP security header using a header with the name Auth-code, that is being added by the web browser itself (i.e. think about JavaScript running in the browser). The header value which is calculated involves the contents of the HTTP request message. This can be as simple as calculating a hash over the body within a HTTP POST request message. 

The web application will check the value of the Auth-code every time a HTTP request is received. If the value received does not match the expected result, the web application will deny the HTTP request and most likely send back an error message to the web browser. E.g.: "Invalid input provided".

False sense of security

These kind of security mechanisms does not add any real security to the web application. An adversary has full control on what happens on the client (i.e. web browser) and therefore what will be send to the web application. Because a header such as Auth-code is calculated and added by the client itself, an adversary also has the ability to make sure the Auth-code always has the correct value.

Security checks should always be performed on the web application server and not be fully depended on code that is running within the browser.

Example of exploitation

Imagine having a web application that relies for an important part of its security on a custom header called Auth-code. The value for the header is calculated and added to the HTTP request using JavaScript by the client itself. 

This web application has a webpage that shows user personal details such as name, address, email, etc. When accessing this webpage a user ID is provided within the parameter UserID, contained within the body of the HTTP request. Manipulating the user ID (e.g. by means of a proxy) will result in an error at the web application. After all the provided Auth-code will not match up with the expected value.

All we have to do to bypass the security check in the above case is making sure the Auth-code we sent will always match the content of the body within the HTTP request. Every time we manipulate a parameter this will require re-calculating the value for the Auth-code. Of course we first need to know how this value is being calculated and under which circumstances it is being used. Knowing that, we can make sure to always include the correct value.

When doing a security test it can be quite cumbersome if re-calculating the Auth-code value has to be done manually. Or simply not possible when you want to take advantage of the active scanner within Burp. We need a way that we can automate this process. We can achieve this by writing our own extension for Burp Suite.

How to bypass using Burp Suite

Burp Suite allows expanding its functionality with extensions. Those can be written in Java, Python or Ruby. I choose to write it in Python. This extension will make sure that for every HTTP request being send the custom security header (e.g. Auth-code) will match the expected value. It will work for all requests being send through Burp Suite: Repeater, Intruder, Active scanner, etc.

Burp extension

On my GitHub page you will find a Burp extension that serves as a template for bypassing a custom security header. Within the Python code I have added comments that should help you in customising the code to fit the web application you are testing.

https://github.com/marcusbakker/Burp-Suite-Extensions

Hunting with JA3

Within this blog post I will explain how JA3 can be used in Threat Hunting. I will discuss a relative simple hunt on a possible way to identify malicious PowerShell using JA3 and a more advanced hunt that involves the use of Darktrace and JA3.

What is JA3?

Introduction

JA3 is a method to fingerprint a SSL/TLS client connection based on fields in the Client Hello message from the SSL/TLS handshake. The following fields within the Client Hello message are used: SSL/TLS Version, Accepted Ciphers, List of Extensions, Elliptic Curves, and Elliptic Curve Formats. The end result being a MD5 hash serving as the purpose for the fingerprint. Because the SSL/TLS handshake is sent in clear text we can use it to fingerprint any client application using the information within the Client Hello message.

 At this moment JA3 is being supported by:

  • Bro
  • Darktrace
  • MISP
  • Moloch
  • NGiNX
  • RedSocks
  • Trisul NSM
  • Python script that accepts a PCAP file (you can find this one on the GitHub page of JA3) 

For more detailed info on JA3 see: https://github.com/salesforce/ja3

Uniqueness of the fingerprint

It is not uncommon to see that a particular JA3 hash is also being used by another type of application. For example: applications written in Java tends to result in the same JA3. You will also notice, depending on the Windows version, when looking at PowerShell that the same JA3 hash is also being used by the Windows Background Intelligence Transfer Service (BITS).

It is important to take collisions into account when performing investigations based on JA3 (please note I am not talking on hash collisions here). Still, JA3 can be very powerful when used for Threat Hunting and Incident Response.

Hunting for malicious PowerShell using JA3

What is PowerShell being used for

Why hunt for PowerShell? PowerShell is quite popular under adversaries for performing malicious activities. It is also very popular by system admins, but with of course a different end goal in mind. Commonly adversaries use PowerShell for:

  • Downloaders to facilitate the second stage of infection by downloading additional malicious code such as a backdoor.
  • Running backdoors that are written in PowerShell (e.g. PowerShell Empire).
  • Post-exploitation toolkits such as PowerSploit.

System administrators use it for:

  • Automating system administration activities.
  • Far less common, compared to adversaries, for downloading files from the internet.  

Why hunt for PowerShell?

The above stated examples of adversary activities being performed using PowerShell make it very interesting from a security monitoring perspective to know when PowerShell communicates to the internet.

Why use JA3 and what to take into account

Other methods exist besides Invoke-WebRequest for communicating over the internet using PowerShell. I will use this one as an example.

When using the PowerShell cmdlet Invoke-WebRequest for communicating over the internet a User-Agent is sent containing PowerShell: "Mozilla/5.0 (Windows NT; Windows NT 6.3; en-US) WindowsPowerShell/4.0". However, this can easily be changed by providing a custom User-Agent to let the traffic look more normal (-UserAgent "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"). That is why relying on the User-Agent is not good enough. Modifying the User-Agent is actively being done by malware.

A far more reliable way of identifying PowerShell that communicates to the internet is to have a look at its JA3 hash values. Yes, we have more than one single JA3 hash for PowerShell:

  • The JA3 hash can differ between PowerShell versions. For example:
    • Windows 7 PowerShell 5.0: 05af1f5ca1b87cc9cc9b25185115607d
    • Windows 7 PowerShell 6.0: 36f7277af969a6947a61ae0b815907a1
  • Differences in Windows versions:
    • Windows Server 2016 PowerShell 5.1: 235a856727c14dba889ddee0a38dd2f2
    • Windows 10 PowerShell 5.1: 54328bd36c14bd82ddaa0c04b25ed9ad
  • There is a way of modifying the TLS version being send in the TLS Client Hello message and thereby having a different JA3 (-SslProtocol parameter in PowerShell v6 for Invoke-WebRequest).
  • When no domain name is involved with setting up the TLS connection, the Server Name Indication (SNI) extension is missing, hence a different JA3 hash.
  • Other methods of communicating to the internet using PowerShell can result in another JA3 hash value (e.g. when Windows BITS is used it can differ depending on the Windows version).

As stated before, there can always be collisions with other client applications which have the same JA3 hash as being used for PowerShell. All should be taken into account when doing proper Threat Hunting.

The hunt

Once we know which JA3 hashes can be seen in your environment, you can start hunting for interesting events. Expect to have collisions and therefore a way of picking out the notable events. A tactic here is to use stacking and look at the bottom of the stacked domain names (i.e. the domain names that occur least frequent). From their pivot to the associated URLs to spot possible malicious traffic. It will also help to enrich the events with the domain registration date and first start with looking at the youngest domain names. And you can add the date of first occurrence for the domain name within your IT Infrastructure to fist check the relative new domain names. Of course, all depends on the capabilities of your tools. Be creative here to see what works best within your environment.

JA3 hunting with Darktrace

Darktrace allows us to perform more advanced hunting with JA3 by employing some very useful metrics. They can be simple like the type of traffic (e.g. HTTPS) and more advanced like the rarity of a domain name within your environment. Metrics are used within Darktrace to build models. A model will have a set of conditions that need to be met before it triggers. In the terms of Darktrace a triggered model is called a model breach.

Hunting hypothesis -> Model

I will explain for one particular JA3 metric within Darktrace how this can be used with the following hunting hypothesis:

An adversary infects a victim's endpoint with a backdoor that starts communicating over HTTPS to a command and control (C2) server by sending beacons on regular or irregular intervals.

For this hypothesis the following characteristics are notable:

  • We hope, and we can somewhat assume, that the backdoor will have JA3 hash which is not frequently seen within our IT infrastructure.
  • Communications to the C2 server's destination are rare within your environment. When not dealing with domain fronting for which the domain is not frequently being accessed by other systems within your environment.
  • The backdoor sends beacons to stay in contact with its C2 server.

You can take the above characteristics to create a model. With this model we combine several weak indicators to increase our chances in detecting C2 channels. The important Darktrace metrics for this model are:

  • "Unusual JA3 hash": for example you can set this to 90% only to look at rare JA3 hashes within your whole environment.
  • "Rare external endpoint": you can do something similar for this metric by only taking into account the rare destinations (IP or domain) within your environment.
  • "Beaconing score": this metric also expects a percentage. The higher the percentage the more regular the beaconing is occurring.

Adversary backdoors often have a configurable jitter to prevent sending a beacon exactly every X minutes. For example by introducing a variation of 40%. Resulting in the traffic to blend in with normal outgoing network traffic, and thereby harder to detect. Within Darktrace this is one of the factors that will result in a lower "Beaconing score" and therefore still detectable when combined with other metrics.

 

Happy hunting! 

Volatility: proxies and network traffic

When dealing with an incident it can often happen that your starting point is a suspicious IP. For example, because the IP is showing a suspicious beaconing traffic pattern (i.e. malware calling home to its C2 server for new instructions). One of the questions you will have is what is causing this traffic. It can really help your investigation when you know which process (or sometimes processes) are involved. However, answering this question is challenging when you have to deal with the following:

  • An IT infrastructure where a non-transparent proxy is used for all outgoing network traffic (this is the case in many enterprise networks).
  • No other sources, except a memory dump, are available to you where you could find this information.

In this blog post I will explain how you can solve this with Volatility and strings.

Lab Setup

I have created a small lab setup to simulate an infrastructure where communications to the internet need to go through a web proxy.

lab_setup.png

The host with IP 172.31.0.250 is the internal web proxy server. This server forwards the traffic to the gateway and sends back the result to the client. The endpoint with IP 172.31.16.50 is used to perform our memory forensics on.

Generating network traffic

To make it as realistic as possible, the endpoint 172.31.16.50 is used to setup multiple connections to hosts on the internet using different applications. One of these applications is connecting to IP 35.178.122.152. The intention is to identify which process is responsible for communicating with this IP.

The problem

The effect of a non-transparent proxy on network connections

The goal for this blog is not to explain in detail how a web proxy works. If you want to have more details about this topic, I can recommend reading the following blog post: https://parsiya.net/blog/2016-07-28-thick-client-proxying---part-6-how-https-proxies-work/.

When an endpoint wants to communicate to internet within a IT infrastructure that requires all internet traffic have to pass a proxy. It will ask the internal web proxy server to connect to the external host and send back the results.

Applications communicating to the internet over a non-transparent proxy are not directly communicating with the host on the internet, but ask the proxy to do that. That is why you will not see something like the following within your network connections:

In the above netstat output it is pretty easy to identify which process did setup a connection to which exact external IP and port (e.g. Chrome.exe communicates to the external IP 108.177.126.138 over port 443). However, when dealing with a non-transparent proxy you will see something completely different.

These are the same network connections using the same applications. But this time all external connections are going through a proxy. Therefore all external communications seems to be going to the internal host 172.31.0.250 (the internal proxy server) over port 8080:

The Volatility plugin netscan will show similar output from which it seems that all outgoing connections are to internal hosts 172.31.0.250:

Solving the problem

Let's have a look how to pinpoint a particular IP address to a process using Volatility and strings. Instead of strings you could also use another utility, as long as the output contains the decimal byte offset and its corresponding string.

Strings
You have to start off by locating all physical memory address locations of the IP 35.178.122.152 within your memory dump (remember that this was the IP related to the suspicious beaconing pattern). You can use Linux strings for this with 2 passes to include both ASCII and (little endian) Unicode strings (-el). You set the parameter -td strings to include the byte offset in decimal format for every string. You will later need this offset for Volatility. The output of strings is written to the file out-linux-strings:

linux-strings.png

With some luck it could be the case that grepping for your suspicious IP within the strings output, that you can already spot the source without the need to use Volatility. Take note that this will not always be the case. Just grepping for the IP or using Bulk extractor to search through your memory dump can be of much help to find out more.

From the file out-linux-strings you grep all the lines that have a match on the IP 35.178.122.152 and output it to another file search-strings:

grep_on_ip.png

Volatility
You will use the file search-strings as input for the Volatility plugin strings. This plugin expects as input a file in the form <decimal_offset>:<string>, or <decimal_offset> <string>. The plugin will output the corresponding process ID and virtual address where the string can be found within the memory dump. Write the output of Volatility to the file out-strings:

With some basic Linux tools you can create a list of involved processes and do a count on number of occurrences. You can clearly see that process with ID 3008 is having a major role with 116 hits regarding the communications to IP 35.178.122.152 (the entries with FREE can be ignored as it is related to free memory which is no longer associated with a process. It can however contain valuable information).

When using the Volatility plugin pslist you can also find the corresponding process name taskhostex.exe for PID 3008:

Mission accomplished!
Please tell me if you have another way to solve this problem that involves memory forensics.


Update

Andrew Case (Volatility Core Developer) replied with another way on how you can try to solve this using the Volatility plugin yarascan: https://twitter.com/attrc/status/975675012307935232