Verder naar navigatie Doorgaan naar hoofdinhoud Ga naar de voettekst

StreamDivert: Relaying (specific) network connections

10 september 2020

door Jelle Vergeer

Author: Jelle Vergeer

The first part of this blog will be the story of how this tool found it’s way into existence, the problems we faced and the thought process followed. The second part will be a more technical deep dive into the tool itself, how to use it, and how it works.

Storytime

About 1½ years ago I was involved in an awesome Red Team-like project. The project boiled down to the following:

We were able to compromise a server in the DMZ region of a client’s network by exploiting a flaw in the authentication mechanism of the software that was used to manage that machine (awesome!). This machine hosted the server part of another piece of software. This piece of software basically listened on a specific port and clients connected to it – basic client-server model. We were not able to directly reach or compromise other interesting hosts in the network. We had a closer look at that service running on the machine, dumped the network traffic, and inspected it. We came to the conclusion there were actual high-value systems in the client’s network connecting to this service. So what now? I started to reverse engineer the software and came to the conclusion that the server could send commands to clients which the client executed. Unfortunately the server did not have any UI component (it was just a service), or anything else for us to send our own custom commands to clients. We furthermore had the restriction that we couldn’t stop or halt the service. Stopping the service meant all the clients would get disconnected and this would actually cause quite an outage resulting in us being detected. So.. to sum up:

  • We compromised a server, which hosts a server component to which clients connect
  • Some of these clients are interesting, and in scope of the client’s network
  • The server software can send commands to clients which clients execute (code execution)
  • The server has no UI
  • We can’t kill or restart the service

What now? Brainstorming resulted in the following:

  • Inject a DLL into the server to send custom commands to a specific set of clients.
  • Inject a DLL into the server and hook socket functions, and do some logic there?
  • Research if there is any Windows Firewall functionality to redirect specific incoming connections
  • Look into the Windows Filtering Platform (WFP) and write a (kernel) driver to hook specific connections

The first two options quickly fell of, we were too scared of messing up the injected DLL and actually crashing the server. The Windows Firewall did not seem to have any capabilities regarding redirecting specific connections from a source IP. Due to some restrictions on the ports used, the netsh redirect trick would not work for us. This left us with researching a network driver, and the discovery of an awesome opensource project: WinDivert (Thanks to DiabloHorn for the inspiration). WinDivert is basically a userland library that communicates with a kernel driver to intercept network packets, sends them to the userland application, processes and modifies the packet, and re-injects the packet into the network stack. This sounds promising! We can develop a standalone userland application that depends on a well-written and tested driver to modify and re-inject packets. If our userland application crashes, no harm is done, and the network traffic continues with the normal flow. From there on, a new tool was born: StreamDivert

StreamDivert

StreamDivert is a tool to man-in-the-middle or relay in and outgoing network connections on a system. It has the ability to, for example, relay all incoming SMB connections to port 445 to another server, or only relay specific incoming SMB connections from a specific set of source IPs to another server. Summed up, StreamDivert is able to:

  • Relay all incoming connections to a specific port to another destination
  • Relay incoming connections from a specific source IP to a port to another destination
  • Relay incoming connections to a SOCKS(4a/5) server
  • Relay all outgoing connections to a specific port to another destination
  • Relay outgoing connections to a specific IP and port to another destination
  • Handle TCP, UDP and ICMP traffic over IPv4 and IPv6

Schematic inbound and outbound relaying looks like the following:

This image has an empty alt attribute; its file name is streamdivert-5.png
Relaying of incoming connections
Relaying of outgoing connections

Note that StreamDivert does this by leveraging the capabilities of an awesome open source library and kernel driver called WinDivert. Because packets are captured at kernel level, transported to the userland application (StreamDivert), modified, and re-injected in the kernel network stack we are able to relay network connections, regardless if there is anything actually  listening on the local destination port.

The following image demonstrates the relay process where incoming SMB connections are redirected to another machine, which is capturing the authentication hashes.

Example of an SMB connection being diverted and relayed to another server.

StreamDivert source code is open-source on GitHub and its binary releases can be downloaded here.

Detection

StreamDivert (or similar tooling modifying network packets using the WinDivert driver) can be detected based on the following event log entries:

This image has an empty alt attribute; its file name is windivert_evt_1-2.png
This image has an empty alt attribute; its file name is windivert_evt_2-1.png