So far so good. We now have an authentication layer in our network, so what’s next? Well … nothing. 802.1X in its original form only adds authentication to the otherwise unprotected network. There are extensions to it, but all of them are optional and not considered here. See for more information: “Possible mitigations scenarios in which the NAC Pi doesn’t work”.
Reasons to bypass MAC filtering and 802.1X NAC
The most obvious reason to bypass network protections for an attacker of any kind is, surprise, surprise, gaining access to the network. An attacker being allowed at the switch port often means that they may obtain a network IP address via DHCP, which allows him to communicate with all devices on his LAN segment and often also beyond it. This opens many doors for attacks like ARP spoofing, packet sniffing, denial of service and so on – which applies to all reachable devices in the network.
But there is more. An assumption is made especially in 802.1X-secured networks which is not made in unprotected networks: The clients in the network can be trusted, as they have authenticated themselves cryptographically, right? Well yes, but this statement is only true until some adversary bypasses this authentication. This would allow the attacker to spy on and act like a trusted client within the trusted network. Additionally, being physically “on the wire” between the supplicant and the authenticator might even allow for advanced techniques like relaying attacks, for example using the tool ntlmrelayx (https://github.com/fortra/impacket/blob/master/examples/ntlmrelayx.py).
A little bit of theory and why NAC bypasses are possible
But how exactly can we bypass the 802.1X NAC authentication process? Breaking it cryptographically is not a reasonable option due to state-of-the-art cryptography being used (at least most of the time). The other option is to bypass it physically by letting the supplicant do its authentication and somehow using the link in its already authenticated state.
There is a tool that does exactly this: Sitting in between a supplicant and an authenticator with the goal to let the supplicant authenticate itself and then injecting traffic into the authenticated link to effectively bypass 802.1X. The tool is called silentbridge and can be found on GitHub (https://github.com/s0lst1c3/silentbridge). It is meant to be run on a Linux device and creates a transparent Linux network bridge connecting supplicant, authenticator, and a side-channel interface (from where the traffic is injected).
In theory, we then just wait for the supplicant to authenticate itself to the network over the transparent bridge by forwarding the supplicant’s EAPOL frames to the authenticator. For security reasons, this is prevented by default in standard Linux network bridges (actually to prevent exactly attacks like this). In earlier versions of the Linux kernel, it was necessary to apply a kernel patch to reactivate EAPOL forwarding; today this can be done via the virtual sys file system. With the bridge configured to forward EAPOL frames, the attacker only needs to wait for the supplicant to complete the authentication process.
Port-based NAC effectively uses the MAC address to identify the supplicant, meaning that all packets originating from this address are allowed to pass the NAC, which is also true for MAC filtering. The link state is also monitored to enforce reauthentication in the event of a link termination. So, the only thing we need to do now is to use IP- and MAC-based source NAT to rewrite the source address of all packets originating from our silentbridge device or its side-channel interface to match the supplicant. However, port-based NAC is strict enough that even a single packet with the wrong MAC address on an authorized port immediately closes the port again. We must therefore always ensure that packets are only sent once this NATing is fully set up. This is called “start dark” in silentbridge terminology and has the drawback that once the rogue device is introduced onto the link, the connection is interrupted for some seconds. Consequently, we need to make sure that the supplicant can reauthenticate itself in order to keep the link in an authenticated state.
The cool thing about this is that the actual technical implementation of the authentication process is completely irrelevant for this approach, as we do not intervene in it directly. We simply let the supplicant do its thing. We’ve tested the authentication protocols “PEAP-MSCHAPv2” and “EAP-TLS” from 802.1X-2004 as well as networks that aren’t using 802.1X at all but might use MAC filtering. This means that this procedure is applicable to both all variants of 802.1X-2004 and MAC filtering. Nice!
All these things and a few more to keep the bridge invisible in the network are done by silentbridge. But we are still missing some vital information: In order to perform the source NAT, silentbridge needs to know which source address to use to overwrite the ones from of the outgoing packets. Consequently, we must determine the IP and MAC address of the supplicant. Silentbridge also sets static ARP entries to reach the switch, on which the authenticator runs, and the networks gateway so our own packets can be routed correctly. This is done manually in order to stay silent in the “start dark” stage. The authenticator ARP entry is required for EAPOL packets since they must reach the switch directly on layer 2. This means, we also need to acquire the MAC addresses of our authenticator and gateway before starting the actual attack.
Finding these is a simple but time-consuming process if done manually, especially if you think of a red-teaming scenario, where you don’t have all the time in the world to spin up Wireshark first. We need a better approach for this…
Sticking it all together: Genesis of the NAC Pi
Ok, so we now have some knowledge of MAC filtering, 802.1x and a tool to bypass them, but we still need the required network information. Now, where do we start? We build a hardware appliance for it!
We have chosen the Raspberry Pi 4 B for this purpose. It’s small, can be powered with USB-C and is more than capable to handle packet bridging. We use USB-Ethernet adapters to add more physical interfaces to the Raspberry Pi. Software-wise, we have developed multiple scripts that instrument silentbridge to perform the 802.1X bypass fully automated by doing the following steps:
- Detecting connected devices to confirm that bridging and injection via the side-channel interface is possible.
- Creating the transparent bridge with silentbridge without adding the side-channel yet.
- Preventing locally generated packets from leaving the NAC Pi (“start dark”) but leaving the bridging intact.
- Running a tcpdump on the bridge to collect the supplicant IP and MAC address as well as the switch and gateway MAC address (this is not as easy as it sounds).
- Adding the side-channel to the bridge and applying all iptables and arptables rules required for the source NAT.
- “Lifting the radio silence” created by the “start dark” action in step 3.
This eventually leads to the fact that we can now inject traffic onto the authenticated link via the side-channel and from the NAC Pi itself by impersonating the authenticated supplicant!