Friday, April 15, 2011

TCP/IP Connection cutting on Linux Firewalls and Routers

Summary

Network security administrators sometimes need to be able to abort TCP/IP connections routed over their firewalls on demand. This would allow them to terminate connections such as SSH tunnels or VPNs left in place by employees over night, abort hacker attacks when they are detected, stop high bandwidth consuming downloads - etc. There are many potential applications.
This article describes how a Linux IPTables based firewall/router can be used to send the right combination of TCP/IP packets to both ends of a connection to cause them to abort the conversation. It describes the steps required to perform this task, and introduces a new open-source utility called "cutter" that automates the process.

Important Warning

The technique documented here, and the software referred to are designed for "legal" and "appropriate" use by network security administrators and the like. It has been written as part of a larger Linux firewall project, targetting at controlling traffic from peer-to-peer software such as Kazaa, iMesh and others into and out of a private network. It is not designed as a tool for malicious use and the author in no way sanctions such use.
Users of the software should be aware that it's actions are easily detectable using a number of readily available network monitoring tools, and it makes no attempt to disguise it's actions. Malicious use of "cutter" could result in a jail sentance in a number of countries around the world.
The author cannot be held responsible for inapropriate use of the documented technique or software (whether in it's original form, or modified).

Introduction

The use of linux systems as IP network firewalls and routers is becoming increasingly popular. The cheapness of the software and hardware combine with the flexibility and reliability of Linux's networking support to make such a solution highly attractive. It is often possible to deliver routing and fire walling facilities at a fraction of the cost associated with systems provided by industrial heavy-weights such as Cisco, Nortel and others.
For the knowledgeable, an out-of-the-box linux distribution such as "RedHat" has many of the features required to build highly personalized firewalls. For the less adventurous; there are cut-down distributions available that are designed specifically for this task. The UK based "SmoothWall" and it's clone "IPCop" are good examples of such an approach; they are highly optimized distributions that include a tiny subset of the software commonly installed by the likes of RedHat, but add a powerful web-based front end for the tasks of configuring and managing the system. These solutions are ideal for small office or home networks.
One advantage of using a Linux system in this way is the ease with which it can be extended or modified. Software can be downloaded from the Internet for free, compiled and installed onto the system to add features such as web proxying (Smoothwall and IPCop already have this), content filtering, anti-virus measures or any other feature you desire.
I have recently been working on a solution to the problems of peer-to-peer traffic filtering on a Linux firewall, and have had to develop a "connection cutter" as part of the system, and it is this tool that is described in this page.

What is a "TCP/IP connection cutter"?

Consider a "client workstation" system in a private network, connected to a server on the public Internet, as in the picture below. The connection passes through the firewall which has two network cards - one connected to each network.
The job of the firewall is typically to ensure the safety of the systems on the private network, and the security of any information held on them. It is common for firewalls to be set up to allow the hosts on the private network more or less unrestricted use of services on the public Internet while setting very tight limits on what private systems can be accessed from the outside world.
Firewalls often use a network address mapping technique ("NAT") in order to allow the private addresses to be hidden from the outside world. For example; when the user of the client at 10.0.0.2 accesses the server at 100.1.2.3, the messages that the server receives lead it to believe that it is being accessed by a host with address 200.4.5.6 - ie the public side of the firewall. The firewall "messes about with" (technical term!) the network traffic that passes through it in order to allow this little deception to work.



A TCP/IP connection cutter is a software tool that can be run on the firewall to forcibly abort the connection between the server and the client. This is done in a way that leaves both ends believing that it was the other that initiated the abort. Only a device that sits in the path of the connection (such as the firewall in our example) can do this.
The ability to abort a connection in this way can be useful to firewall administrators for any number of reasons. For example...
  • A firewall administrator identifies that a workstation on his network is using a service on the public network that should not be permitted. He can force the closure of the connection. This might be because of the network bandwidth being used, or the nature of the service or some other reason that fits the organization's security policy.
  • Or: a firewall administrator can forcibly close SSH tunnels or VPNs that rogue employees leave open over night between their office desktops and home networks. This can be a real problem, and it is a well known access route into private networks.
  • Or a web server administrator can request that a rogue incoming connection is terminated without having to "kill" the web server process on the server.
A connection cutter is NOT a way for rogue systems to terminate connections made by others - it must be run on one of the routers through which the connection passes and as such has limited application for attackers interested in denial-of-service exploits.

How to kill a TCP/IP connection using "IPTables REJECT with RESET"

Simply put: Fire the "RST" bullet.

At the most basic level, it's dead easy - just send an "RST" packet to both ends of the connection.
The TCP/IP protocol defines a packet called "RST", which is short for "Reset". When an RST packet arrives on a connection it is understood to mean that something has gone badly wrong and that the application should abort the conversation. "Badly wrong" means something like a protocol error, unrecoverable corruption, breaks in the circuit etc. The RST packet does not include information about the nature of the problem but is simply a kind of "Panic button" that tells it's recipient to stop talking.

But we cant take the first shot, or shoot on someone else's behalf

Since RST packets present such a golden opportunity for attack, most systems will insist that the sequence number information contained in the packet, and the address from which it comes contain good "expected" values. Some systems even check the layer 2 MAC address before agreeing to act on the instruction to reset. These measures make RSTs harder to "spoof". In fact, the normal RST-sending logic embedded in the Linux kernel (and, I imagine: others) is to send RSTs only in response to incoming packets - that way, the sequence number can be guaranteed to be correct.

IPTables as a possible "gun" (but not a perfect one)

One solution for a Linux router using IPTables is to define a rule that says "reject packets sent from address 100.1.2.3 to 10.0.0.2 (and visa versa) with an RST".
To use this technique, we must..
  • Discover which IP addresses and port numbers refer to both ends of the conversation, and the "NAT"ed addresses that are used to present them over the subnets. All the relevant information is held in the pseudo file /proc/net/ip_conntrack.
  • Build an IPTables rule that rejects relevant outbound forwarded traffic by responding to it with an RST. For our example above, the iptables command will look something like the following (depending on how your tables are named, and the port numbers used)..
    • iptables -A FORWARD -p tcp -s 10.0.0.2 --sport 3245 -d 100.1.2.3 -dport 22 -j REJECT --reject-with tcp-reset 
  • Build another rule that does the same for inbound traffic.
    • iptables -A FORWARD -p tcp -s 100.1.2.3 --sport 22 -d 10.0.0.2 --dport 3245 -j REJECT -reject-with tcp-reset
  • Watch the network traffic using something like tcpdump to wait for the next incoming and outgoing packets from both ends of the connection, and observe that IPTables does indeed send the RST packets back, or keep a track of the iptables counters for the rules we have created.
  • Finally; remove the IPTables rules so that they don't interfere with future traffic or clog up precious table space.
    • iptables -D FORWARD -p tcp -s 10.0.0.2 --sport 3245 -d 100.1.2.3 -dport 22 -j REJECT --reject-with tcp-reset
    • iptables -D FORWARD -p tcp -s 100.1.2.3 --sport 22 -d 10.0.0.2 --dport 3245 -j REJECT -reject-with tcp-reset
The result of all this activity is that the client end of the conversation thinks that the server has reset the link, and the server thinks that the client did it - so we have a clean closure of the connection.
However, there are a couple of issues with this approach.
First: IPTables will not send an RST until an incoming or outgoing packet arrives from the client or server for it to reject. If the application is connected but idle - this may take many minutes or hours to occur. An example is an SSH or telnet session where the user is typing nothing. The connection stays "up" until the user hits the first keystroke on the keyboard, at which point a packet is sent to the server (via the firewall), and firewall can respond to it with an RST.
Second; we cant abort both ends simultaneously. To take the SSH or telnet example already sited - the client will abort the connection when it gets it's RST after the user presses a key, but the server will know nothing about what has happened, and will still believe the connection to be open. This situation will persist until the server sends a packet - which it may never do.
It would be nice to be able to force the transmission of RST packets immediately, so closing the connection even when there is no application data being sent.

In effect, the firewall cant "shoot" it's RST bullet until client and/or server have sent something through the firewall that allows it to determine the sequence number that should be included in the RST packet. Simply guessing a sequence number wont work - the client and server will (if they are sensible) ignore the packet.

Better: How to cut a TCP/IP connection by sending a FIN

The idea of sending an "RST" packet to both ends is good, but we could do with a better way of getting it sent than turning on an IPtables "reject" rule and waiting for something to arrive that the firewall can reject. What is needed is some way of forcing the two ends of the connection to send a packet to the firewall that IPtables can then respond to.
There is a feature of the TCP/IP protocol that we could use to good effect here :- If a packet (other than an RST) is received on a connection that has the wrong sequence number, then the host responds by sending a corrective "ACK" packet back. This "ACK" reply is designed to put the sequence numbers at both ends back into step - and allows the protocol to retransmit packets that got lost. This is very nice for our needs - if the firewall sends a packet that is "correct" in all respects except for the sequence number, then the host very helpfully tells us what should have been used. We can then use this information to build the RST packet that will abort the connection.
Following this idea, we can do the following..
  • Identify the IP addresses and port numbers of the hosts at both ends of the connection, and any NATted address that the firewall is using to present the private host to the public network by inspecting the /proc/net/ip_conntrack file.
  • Build the IPtables rules that will send RST packets to both ends of the connection when an incoming packet arrives (the rules have already been described).
  • Send a packet to both ends with bad sequence numbers.
    • use sequence_number = zero - it's pretty much bound to be wrong (which is what we want).
    • use a FIN packet - they fairly easy to put together and don't need to contain any "data" payload.
    • Send the packet using Layer 2 raw Ethernet access - so that the IP layers don't mess around with the headers.
      • We need the MAC address of the next hop to the target machine for this - which we can determine by inspecting the firewall's ARP and routing tables.
  • Wait for the hosts to respond with their ACK, and for Iptables to send it's RST packet back.
  • Remove the newly added Iptables rules.
This procedure is better than the previous one because the effect is immediate. We don't have to wait for the user of the offending SSH session to press a key because we have tricked his computer into sending us something to respond to.
But - we still have to have a process for determining when the FIN - ACK - RST packets have done their stuff so that we can clean up the iptables rules. Various options for doing this are possible. For example: the rules can be left in place, while a cron job does a periodic cleanup. Or we can "listen in" to the packet flow using Linux's raw packet mode. I'm sure there are any number of other "clean up" solutions that could be devised.

Better still: Without IPTables rules

It turns out that we can produce the same FIN -> ACK -> RST sequence of packets without using Iptables to generate the RST at all - so there are no IPTables rules to create or clean up.
The "raw packet socket" technique we have already suggested for the sending of the FIN packet can be used to listen for the incoming ACK, and send the resulting RST. This is how the "cutter" program works.

Cutter 1.03

Description and Synopsis

"Cutter" is an open source program that uses the FIN-ACK-RST packet technique described above to abort TCP/IP connections routed over the firewall or router on which it is run. It can be called using one of the following four syntaxes..
cutter ip-address
Example: "cutter 10.10.0.45"
Cuts all connections passing through the firewall between any ports on the specified ip-address (either a "private" or "public" address) and any other hosts. This can be used to close down all incoming connections to a particular server, all outgoing connections from a particular client or all outgoing connections to a server.
cutter ip-address port
Example: "cutter 200.1.2.3 80"
Cuts all connections to or from the specified ip-address/port pair. This allows the user to be a little more specific than the previous example and allows targetting of specific services on specific hosts.
cutter ip-address-1 port-1 ip-address-2
Example "cutter 200.1.2.3 22 10.10.0.45"
Cuts all connections between ip-address-2 and ip-address-1/port-1. This allows the user to cut connections between a specified "client" and a particular service on a specified host. Our example closes host 10.10.0.45's SSH connection to server  200.1.2.3.
cutter ip-address-1 port-1 ip-address-2 port-2
Example: "cutter 200.1.2.3 22 10.10.0.45 32451"
Cuts the specific connection between the two ip/port number pairs given.

License

Cutter 1.03 is released under the terms of GNU GENERAL PUBLIC LICENSE Version 2 (June 1991) and comes with all the usual freedom, openness and disclaimers associated with that license.

Status

Cutter 1.03 should be considered experimental. The author is releasing a tool that works on the systems he has access to (namely: IPCop and RedHat Linux), and he is seeking input on it's use on other systems, ideas for improvement, offers of sponsorship - etc.

Courtesy : http://www.lowth.com/cutter/