In part one, we discussed the architecture of web conferencing applications, with a specific focus on Zoom’s architecture to support web conferencing at a massive global scale. Part two will discuss the approach we developed to support tunneling traffic through Zoom and Microsoft Teams using the TURN protocol.
Let’s start with a quick recap of what we discussed in part one and then move into the options we considered for tunneling traffic through web conferencing infrastructure. Next, we will discuss how WebRTC works internally and how we leverage it to tunnel traffic through TURN servers. Finally, we will conclude with a brief tutorial around the usage of our TURNt utility and provide links to detailed documentation that explains the usage of the tool in more depth.
Note: Please know that while in this post we reference things such as “Obtaining TURN Credentials from Zoom,” we are not exploiting any vulnerabilities in these applications. These applications are designed to use TURN credentials to egress out of environments with more restrictive firewall or NAT configurations.
Ideas for Emulating or Tunneling Traffic Through Zoom
At this point, we have a good understanding of how Zoom and other web conferencing applications function. We want to begin diving deeper into different methods we could use to tunnel traffic through trusted domains associated with these applications. The diagram below summarizes what we discussed previously in terms of the various components of the Zoom application infrastructure from the Multi-Media Router (MMR) to the Zone Controller and the Real-time Web Gateway. This diagram leaves out some other components of Zoom such as the XMPP infrastructure used for implementing Zoom chat functionality and the HTTP Tunneling infrastructure that we saw references to previously.
Emulating Zoom Multi-Media Router (MMR) Servers
One of our ideas during this research was to investigate whether it would be possible to generate traffic that closely mimics legitimate Zoom meetings—not just in packet structure but also in flow behavior and timing. To explore this, we reverse-engineered the Zoom meeting protocol, captured live traffic, and reviewed previous research on Zoom’s network patterns.
We hoped Zoom’s MMR servers would be hosted on Amazon EC2 IP ranges, simplifying efforts to spoof legitimate infrastructure in a controlled environment. The idea was to return the exact same TLS certificate observed during legitimate Zoom sessions—identical in structure, signature, and metadata—while secretly substituting in a different public/private key pair embedded in the client.
This would allow the handshake to proceed normally from the client’s perspective, even though the cryptographic material behind the certificate was different. At the network level, the handshake would be indistinguishable from that of a real MMR server since no observer without a legitimate private key could detect the substitution.
However, this technique breaks down in environments where outbound traffic is intercepted by a TLS-inspecting web proxy, which would terminate the connection and issue a replacement certificate, thereby exposing the spoofing attempt.
In our testing, we observed that the majority of MMR servers were not hosted behind EC2 infrastructure but instead resided within IP space controlled by Zoom-owned autonomous systems (ASNs) — making spoofing attempts based on cloud-hosted infrastructure more difficult in practice (see Figure 2).
Routing Traffic Through TURN Infrastructure Provided by Zoom
We focused much of our analysis on reverse-engineering the Zoom web client since we figured it would be easier to reverse-engineer minified JavaScript code than statically linked C++ code. During our investigation of the web client, we observed that it would be provided with TURN server credentials when attempting to establish a connection with the MMR server. The web client uses these credentials in environments with egress restrictions that prevent outbound UDP connections (see Figure 3).
Traversal Using Relays around NAT (TURN) is a protocol used for traversing networks and bypassing egress restrictions within firewalls. Typically, TURN is leveraged alongside the WebRTC protocol in order to bypass egress restrictions or restrictions imposed by NAT gateways on peer-to-peer communications. While these credentials are typically meant to be used to establish a connection with a backend MMR server there are actually no controls in place to stop us from setting up a paired connection between two attacker-controlled nodes such as a compromised endpoint and an attacker-controlled backend server running a SOCKS proxy for tunneling into a network. We observed that generally these credentials were valid for two to three days before expiring.
Routing Traffic Through Legitimate Zoom MMR Servers
Outside of emulating MMR servers, we also considered the possibility of reverse-engineering the Zoom meeting protocol so that we could smuggle our malicious traffic within the RTP video streams sent by the client through the MMR servers. Fundamentally, the MMR servers act as forwarding units to connect the various meeting participants. Meeting participants can request the video stream for a specific user or even stop receiving video streams in environments where available bandwidth is constrained.
Forwarding traffic through MMR servers would be ideal for a variety of reasons. For example, while the TURN servers provided by Zoom only seemed to be functional over 443/TCP using the TLS protocol, the packets sent through the MMR servers leverage the UDP protocol, which doesn’t suffer from the same performance issues such as head-of-line blocking that we have when smuggling traffic through TCP-based communications channels. Furthermore, Zoom supports end-to-end encryption, meaning if we can create the proper packet format, the MMR server has no way of modifying the media stream or even telling that we aren’t sending real RTP traffic through the server.
Selecting an Approach
After careful consideration of the three proposed solutions—emulating an MMR server, tunneling traffic through TURN servers with WebRTC, or reverse-engineering the Zoom client and MMR server code—we ultimately settled on tunneling traffic through the Zoom-hosted TURN servers.
We decided on this approach for several reasons. The first is that it allows us to tunnel traffic through highly trusted Zoom subdomains such as turnsg01.cloud.zoom.us and other *.cloud.zoom.us subdomains, depending on your localization. Typically, the TURN server subdomain is allocated based on geographic proximity.
Furthermore, we liked this approach since it allows for the most platform flexibility. After implementing the tool for tunneling through TURN servers, we would be able to quickly target a new provider, reverse engineer their web client implementation, and obtain TURN credentials, which we could then plug into our tooling to tunnel traffic through a new provider. Additionally, providers such as Zoom typically recommend excluding their domains from TLS inspection and adding their IPs and domains to split-tunneling rules to avoid saturating corporate VPN appliances.
This approach is in direct contrast to others, which would generally be significantly more dependent on the specific target provider and wouldn’t be portable across multiple services. However, this approach isn’t without its downsides. The first is that we are tunneling traffic over a TCP connection, which is less than ideal in many scenarios when leveraging a connection stream to tunnel traffic. Furthermore, if we wanted to do full VPN tunneling over this type of connection and not just SOCKS tunneling, we would rather quickly run into the TCP meltdown problem. Generally speaking, when it comes to tunneling traffic, a UDP-based communication tunnel is better than a TCP-based tunnel in just about every scenario if stealth or evasion is not a consideration.
Another issue with this approach is that it may fail in an environment where all traffic must egress through an HTTP proxy with TLS inspection enabled. However, it would likely still work if they followed Zoom’s advice of disabling TLS inspection on *.zoom.us domains. Additionally, in environments where outbound UDP traffic is allowed it might look suspicious if there was a significant amount of traffic egressing to Zoom over TCP using TURNS when other clients are defaulting to the UDP-based transport mechanism.
Understanding the WebRTC Protocol
At this point, we have TURN server credentials and need to establish a connection between two systems—say, an attacker system hosted in AWS and a remote implant running on a compromised employee workstation. These systems can communicate via the TURN proxy, but the process requires explicit coordination between both endpoints. Each must have access to the TURN credentials and participate in the negotiation process to set up the connection.
Thankfully, WebRTC makes this task more approachable. Although it’s often associated with peer-to-peer audio and video communications, WebRTC is a flexible, albeit complex, collection of protocols designed for real-time, encrypted, and NAT-traversing connections—including those that rely on TURN.
You’ve probably encountered WebRTC indirectly: it powers communications for every major web conferencing provider, forms the backbone of Discord’s voice chat, and is even known in the offensive security community as a mechanism that can leak real IP addresses of VPN users.
From a practical standpoint, WebRTC is best understood as a protocol suite that facilitates real-time communication. It’s capable of supporting everything from video conferencing to chat, file-transfer, and even interactive sessions like browser-based SSH or RDP. In the next section, we’ll unpack the individual protocols that comprise this suite—including those that give us reliable ordered (or unordered) messaging with timeouts, strong encryption, and perfect forward secrecy—making it an incredibly powerful addition to our offensive tooling arsenal.
What are the Core Protocols Used by WebRTC?
At this point, we know we want to use WebRTC as a mechanism to establish a TURN connection between two peers routed through a trusted zoom.us subdomain. In this section, we want to understand a little bit more about WebRTC and the capabilities it provides. As mentioned previously, the best description of WebRTC is likely as a suite of protocols that facilitates real-time communication. This suite is made up of several lower-layer protocols such as:
- SCTP (RFC 4960): Stream Control Transmission Protocol, used for message-oriented communication.
- SRTP (RFC 3711): Secure Real-time Transport Protocol, providing encryption and message authentication for RTP streams.
- DTLS (RFC 6347): Datagram Transport Layer Security, enabling secure communication over UDP.
- ICE (RFC 8445): Interactive Connectivity Establishment, a technique for NAT traversal.
TURN (RFC 8656): Traversal Using Relays around NAT, allowing relayed media delivery when direct peer-to-peer is not possible.
STUN (RFC 8489): Session Traversal Utilities for NAT, used for NAT discovery and connectivity checks. - SDP (RFC 8866): Session Description Protocol, used to describe multimedia communication sessions.
Implementing the Tunneling Capability
Now that we have a basic understanding of the various protocols that make up WebRTC we can begin with writing our implementation to leverage these TURN credentials as a transport for proxying traffic through a victim system connected to an attacker-system. The tool will consist of two components, a controller and a relay. The controller will run on the attackers system and run a SOCKS proxy server which can be leveraged for tunneling traffic through a victim system as well as local and remote port-forwarding. The relay will be run on the victim system and be responsible for supporting proxying with the controller and supporting remote port-forwarding.
From a development perspective, we decided to leverage Go with the Pion WebRTC library. Pion is an incredibly useful library that leverages a pure Go implementation of the WebRTC protocol making it incredibly easy to build and use without managing complex CGO related dependencies. Sean DuBois, the creator of the Pion WebRTC library, gave an excellent presentation discussing its features in 2018 which is available on YouTube. We chose to leverage Go for this project since it supports rapid development of concurrent network applications with quick and efficient development iterations while accepting the trade-off of larger file sizes.
The tool is meant to be leveraged alongside a long-term C2 implant for short-term bursts of high-frequency low-latency communications. This means it’s not really designed for usage with implants such as Nighthawk or Cobalt Strike for persistence and long-term command and control. Instead, it’s meant to be launched from these types of implants temporarily to support actions such as SOCKS proxying, hidden VNC, data exfiltration, or other shorter-term durations that require faster transfer-speeds.
Using SCTP to Reduce Head-of-Line Blocking Related Performance Problems
SCTP’s multi-streaming and flow control mechanisms make it particularly well-suited for SOCKS proxying, especially in scenarios requiring multiplexing over a shared transport such as a single shared TCP connection stream. A key challenge in proxying multiple connections using SOCKS over a single TCP stream is head-of-line blocking can introduce performance issues where a large file download can degrade or even completely block other requests from completing.
SCTP does provide some assistance here as our user-mode SCTP implementation works by tunneling traffic through a shared underlying TLS-encrypted TLS connection using the TURN protocol. We leverage a separate SCTP DataChannel per-connection which allows us to take advantage of SCTP’s native flow-control capabilities which helps with multiplexing multiple connections over a single underlying transport.
Head-of-line blocking is somewhat compounded by the fact that most residential connections (that aren’t fiber optic connections) are generally configured asymmetrically with a bias towards faster download speeds. Unfortunately, this difference between the supported download and upload speeds on a victim system can result in large-file downloads completing quickly on the victim side, but significantly backlogging the shared TCP connection stream with the attacker.
Our user-mode SCTP implementation can immediately buffer incoming data from the TCP connection as soon as it is received, without requiring the client application to manually call read() on the network stack. This approach improves performance by reducing processing delays, ensuring efficient data retrieval, and optimizing bandwidth usage within the communication channel. By handling buffering in user mode, we minimize unnecessary blocking and allow for more responsive multiplexing across SCTP DataChannels.
Implementing Encryption and Perfect Forward Secrecy
WebRTC provides us with some other unique advantages as it leverages DTLS as an encrypted transport layer on top of other protocols such as SRTP and SCTP. DTLS provides several useful encryption primitives such as perfect-forward secrecy (PFS). DTLS within WebRTC leverages the SDP protocol to exchange fingerprints which means it’s not possible for out-of-the-box inspection proxies to MITM the DTLS connection established as part of a WebRTC connection. When WebRTC is leveraged alongside TURNS there is an outer TLS layer and an inner DTLS layer.
The outer TLS layer can be inspected by proxies without causing issues as they aren’t aware of the inner DTLS layer. There might be issues with this where a proxy strictly enforces HTTP as the underlying protocol within the TLS tunnel, but generally this means we can egress while also encapsulating our traffic in a legitimate protocol that isn’t inspectable by security appliances (this depends on how the proxy is configured). Additionally, DTLS helps obscure the nature of SOCKS proxying within WebRTC traffic, making detection more difficult. This approach enhances operational security by providing encrypted, resilient communication while reducing operational risk.
Implementing Local and Remote Port-Forwarding
TURNt also supports local and remote port-forwarding in addition to SOCKS proxying capabilities. Remote port-forwarding allows the operator to bind to a port on the relay running on a remote victim system. This then forwards a connection through the controller to an attacker-controlled system.
Remote port-forwarding assigns a unique GUID to each remote port-forward tunnel which prevents the relay from connecting to arbitrary internal attacker systems through the controller component which could present a security vulnerability. Local port-forwarding is much simpler as it just needs to connect through the existing SOCKS proxying functionality and bind to a port on the attacker system running the controller.
Reducing Large Binary Sizes in the Implant Component
One of our concerns with our choice of leveraging Go for development was the binary size and potential difficulties with leveraging this capability through our C2 channels such as NightHawk. Fortunately, we were able to drastically reduce the overall binary size through adjusting compiler flags and leveraging UPX for compressing the compiled sections of the binary. We don’t recommend leveraging the UPX compressed binary when operating from disk due to detection risks, but it is useful when running the implant from in-memory.
Adding Microsoft Teams Support
After adding support for Zoom we were able to quickly identify a mechanism to pull TURN credentials from Microsoft Teams. We’ve incorporated this into our TURNt utility (discussed in the next section) which automates the process of obtaining these credentials for proxying purposes (see Figure 5).
Using the TURNt Utility for Rapid Covert Tunneling
Now that we have discussed our selected approach of leveraging TURN servers for proxying in a generic manner across Microsoft Teams and Zoom we will provide a brief demo of the TURNt utility within this post. For full documentation please see the README which includes more detailed documentation and links to detailed playbooks for specific actions such as tunneling RDP traffic and using the tool with NightHawk.
Setting Up the Controller
The tool is straightforward to use. Assuming we have a config.yaml file containing TURN credentials such as using the turnt-credentials utility obtained in Adding Microsoft Teams Support in the previous section of the article, we can simply run the turnt-control utility with the -config option as shown in Figure 6. This utility would be run on the operator’s machine.
Starting the Relay
After running the controller we can copy and paste the offer values generated by the utility into the relay utility. Next, we can copy the answer generated by the relay utility and paste it back into the controller utility to begin the process of creating a WebRTC connection through the TURN server (see Figure 7). This utility would be run on the victim’s machine.
Connecting through the SOCKS Proxy
At this point, we have a SOCKS proxy running on the operator machine and we can use curl as a simple test utility to verify the proxy is working properly (see Figure 8).
Connecting through the SOCKS Proxy
To complement this release, we’ve put together a demo video that showcases TURNt in action. The video walks through several key features, including SOCKS proxying, as well as both local and remote port forwarding. For full technical details, installation instructions, and comprehensible usage documentation, please refer to the README and supporting documentation available in the TURNt repository.
In the demonstration, we highlight practical use cases—such as downloading a 100MB test file via TURNt and performing remote port forwarding through a sample relay running on a cloud-hosted virtual machine. Remote port forwarding can be especially useful for scenarios like executing NTLM relaying attacks through a compromised host. Meanwhile, local port forwarding is ideal for working with desktop applications that lack native SOCKS proxy support, such as Citrix or the SAP client.
Conclusion
In this post, we explored several strategies for tunneling traffic through trusted web conferencing infrastructure, ultimately settling on the use of TURN servers provided by Zoom and Microsoft Teams. We discussed the inner workings of the WebRTC protocol suite, the rationale behind our approach, and how our TURNt utility leverages TURN credentials to establish SOCKS proxies and support both local and remote port forwarding through commonly whitelisted domains. While not without limitations—such as TCP-based performance constraints and susceptibility to TLS inspection—this method provides a flexible, reusable way to tunnel traffic through high-trust infrastructure with minimal friction.