VDB

TS-2024-005

TS-2024-005 PUBLISHED CVSS 8.600000381469727 HIGH

Description: Insufficient inbound packet filtering in subnet routers and exit nodes What happened? In Tailscale versions earlier than 1.66.0, exit nodes, subnet routers, and app connectors, could allow inbound connections to other tailnet nodes from their local area network (LAN). This vulnerability only affects Linux exit nodes, subnet routers, and app connectors in tailnets where ACLs allow "src": "*", such as with default ACLs. Tailscale version 1.66.0 fixes the vulnerability. Additionally, a server-side update changes the interpretation of "src": "*" to mitigate the issue specifically for exit nodes. Special thanks to Hakan Ergan for reporting a similar concern that led us to discover this vulnerability. Who was affected? This affected the following nodes using Tailscale version 1.65 or earlier: Exit nodes on Linux Subnet routers on Linux App connectors on Linux Regular nodes on all platforms connecting to the above nodes Tailnets with custom ACLs that do not use "src": "*" or any other value that includes external IPs were not affected. We are not aware of any active exploitation of this vulnerability. What was the impact? Devices outside of the tailnet, but on the same LAN as an exit node, subnet router, or app connector could connect to ports on tailnet nodes that are allowed by ACLs. What do I need to do? Upgrade the following nodes to 1.66.0 or later: Subnet routers on Linux App connectors on Linux Regular nodes on all platforms that use exit nodes shared from other tailnets or Mullvad exit nodes We recommend enabling auto-updates and updating all nodes to the latest version, but it is not required to mitigate this vulnerability. A server-side change mitigated this vulnerability for other types of affected nodes. Technical details Below, we refer to exit nodes, subnet routers, and app connectors as packet-forwarding nodes, because the details apply to all of them. Specific types of packet-forwarding nodes are mentioned explicitly where their behavior is different. Before 1.66.0, packets between regular nodes and destination hosts behind packet-forwarding nodes were filtered based on source/destination IP as specified in tailnet ACLs. Specifying "src": "*" in ACLs is equivalent to "src": ["0.0.0.0/0", "::/0"], meaning any IP address. This allowed source IPs outside of the tailnet to send packets to tailnet nodes via a packet-forwarding node. This could be abused by malicious LAN hosts to connect into the tailnet using a known tailnet node IP. The attack only works on a LAN because: it relies on next-hop routing, which only works in a LAN destination IPs are in the subnet router's approved range, or in the CGNAT range 100.64.0.0/10, which are not routable over the Internet. Attacks Here are several attack scenarios. Packet-forwarding node on an untrusted LAN. A malicious host 10.0.0.1 on the same LAN as the packet-forwarding node 10.0.0.2 could craft packets with destination IP of a tailnet node 100.64.0.1 (using a command like ip route add 100.64.0.1/32 via 10.0.0.2 dev eth0) and send them to the packet-forwarding node. The packet-forwarding node would accept them and forward them to the victim node. The victim node would see a packet from 10.0.0.1 and accept it if the tailnet ACLs allow this source IP. This scenario is very similar to a legitimate use-case of site-to-site networking, where two subnets are bridged using Tailscale subnet routers and the flag --snat-subnet-routes=false. Malicious shared exit node A malicious exit node 100.64.0.4 from tailnet A could craft packets with destination IP of tailnet B node 100.64.0.3 and any source IP other than 100.64.0.4. Due to the built-in quarantining of shared nodes, packets from 100.64.0.4 are rejected. Mitigations We implemented 3 separate mitigations for these attacks. Redefine "src": "*" in ACLs While * is a convenient shorthand in ACLs, Tailscale users almost never need to allow connections from any IP. In most cases users intend * as "all other nodes in my tailnet". As a mitigation for this vulnerability, we redefined * in src section of ACLs to include: all tailnet nodes all IPs from approved subnet routes The inclusion of IPs from approved subnet routes is needed for the site-to-site networking setup. For users that need the old semantics of * we added a new autogroup:danger-all, which matches the old definition of *. Stateful packet filtering on packet-forwarding nodes On Linux packet-forwarding nodes we added stateful packet filtering. This means that these nodes keep track of forwarded connections and only allow return packets for existing outbound connections. Inbound packets that don't belong to an existing connection are dropped. Because routing is implemented differently on non-Linux platforms, this mitigation is only necessary on Linux. Stateful filtering is enabled by default, except for existing subnet routers that set --snat-subnet-routes=false. You can disable stateful filtering using tailscale up --stateful-filtering=false. Client-side quarantining of shared nodes Quarantining of shared nodes was implemented by a packet filter sent from the Tailscale control plane. This packet filter instructs nodes to drop any inbound connections from the source IP of the shared node. To prevent malicious shared exit nodes from crafting packets with different source IPs, additional client-side quarantining logic was added. The 1.66.0 and later clients reject all inbound connections from quarantined nodes, regardless of their source IP. This is similar to how the "shields up" mode works within the tailnet.

Risk Scores

CVSS 4.0
8.600000381469727
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Affected Products

VendorProductVersions
alpinetailscale0, 0, 0

Timeline

  • May 8, 2024 CVE Published

References

Open in Interactive Console →
$ Console Community · 100/wk Open console ›