Stateless firewalls, although straightforward in design, have some fundamental problems that surface when you use them on real-world networks. TCPStateless firewalls don't maintain any state information about TCP connections, so they must use a simple set of rules to filter TCP packets. In general, stateless firewalls look for packets containing connection initiation requestspackets with the SYN flag set. In many cases, they apply network policy rules to those SYN packets and more or less let most other TCP packets go by without blocking them. This method actually works out well enough in many cases, but it can have some major security implications. Consider a sample configuration of a stateless firewall using the older Linux ipchains firewall. Say you want to allow yourself to connect out to anywhere but not allow anyone to connect in to any of your services. The following configuration should do the trick: ipchains -A input -p TCP ! -y -j ACCEPT ipchains -P input DENY The first line tells the firewall to allow all inbound TCP packets that don't have the SYN flag set (indicated by ! -y). The second line tells the firewall to simply drop everything else that's inbound. The code that determines whether the packet passes the -y test is quite simple, and it's based on the contents of the tcpsyn variable. The following code sets the value of tcpsyn based on the packet's TCP header: /* Connection initilisation can only * be made when the syn bit is set and * neither of the ack or reset is * set. */ if(tcp->syn && !(tcp->ack || tcp->rst)) tcpsyn=1; If the tcpsyn variable is set to 1, the packet passes the -y test and the firewall treats the packet as a connection initiation packet. Therefore, any packet with the SYN flag set and the ACK and RST flags cleared is considered a connection packet. ScanningThere are several techniques for gathering information from a host by sending TCP packets of varying degrees of sanity. One technique of note is FIN scanning, which is a method for port scanning documented by Uriel Maimon in Phrack 49, Article 15. For certain IP stacks, if you send a FIN packet to a closed port, the IP stack sends back an RST packet. If you send a FIN packet to an open port, the IP stack doesn't send anything back. Therefore, you can use FIN packets to scan a machine's ports to determine which ones are open and which are closed. Because FIN and RST packets are more or less required for TCP's normal operation, a stateless firewall often has to let them through. If the firewall doesn't perform any outbound filtering, it can be a little more restrictive, but generally it passes these packets through to allow TCP responses. Therefore, FIN port-scanning commonly works through a stateless packet filter. Attackers can ascertain even more information about hosts behind a network, such as the OS type and version, by sending specially crafted packets. Ambiguity with TCP SYNsStateless firewalls need to enforce rules on TCP connection initiation. This enforcing is normally done via a handshake involving a TCP packet with the SYN flag set, which is fairly simple to intercept and process. However, certain IP stacks accept different permutations of the SYN flag when setting up TCP connections, and these permutations might lead to exposures in stateless packet filters. Many TCP/IP stacks initiate a connection if a packet with SYN and FIN set is sent instead of a straightforward SYN packet. If a stateless packet filter doesn't interpret this packet as a connection initiation, it could give attackers an easy way to bypass the firewall. They can simply modify their traffic to send SYN-FIN instead of SYN, and the stateless firewall might pass it along unfiltered. Paul Starzetz posted an excellent write-up of this problem to the Bugtraq mailing list (archived at http://archives.neohapsis.com/archives/bugtraq/2002-10/0266.html), which is summarized briefly in the following list:
This vulnerability is rumored to have affected multiple firewalls over the years, including Cisco IOS and even early versions of Firewall-1. With this in mind, take another look at the ipchains code for recognizing connection initiation packets: /* Connection initilisation can only * be made when the syn bit is set and * neither of the ack or reset is * set. */ if(tcp->syn && !(tcp->ack || tcp->rst)) tcpsyn=1; You can see that a packet with SYN-FIN set would make it through the firewall. You can also see that, according to Startez's analysis, a SYN-FIN packet counts as a connection initiation packet for Linux hosts, which means someone could get through the ipchains firewall! UDPUser Datagram Protocol (UDP) connections are a problem for stateless firewalls. In TCP, a particular packet represents a connection initiation: the SYN packet. In UDP, however, there's no such packet. This issue usually shows up when administrators try to punch the DNS protocol through the firewall. Say you want to make a rule allowing a client computer on an internal network to talk to a DNS server outside the firewall. You would tell the firewall to allow UDP packets from that host, with source ports 1024 to 65535 destined to destination host 1.2.3.4 on destination port 53. This rule works fine, but what happens when the DNS server responds? To allow the response, you need a rule to allow UDP packets from source port 53 to destination ports 1024 to 65535. The problem with allowing those UDP packets is that attackers could talk to any UDP service on a port between 1024 and 65535, as long as they use a source port of 53. There are some interesting UDP daemons on those high ports for most operating systems, with RPC functionality usually being the easiest target. This risk can be mitigated by host configuration and network design, but it's a fundamental limitation in stateless packet filtering technology. Figure 15-3 summarizes a sample attack of this nature. Figure 15-3. UDP source port 53 attack for stateless firewalls
FTPAs you learned in the sidebar, "Understanding FTP," FTP presents a problem for most firewalls. This section focuses on an aspect of FTP that leads to a problem in stateless firewalls. Say you want to let your users use FTP to connect to machines on the Internet. You can do this easily with a stateless firewall by allowing outbound port 21 TCP connections. However, if users are using active FTP, they can initiate data transfers by telling the FTP server to connect to a port on their computer (via the PORT command). Then you see a TCP connection coming from source port 20 to your client host on a high port. A stateless firewall generally isn't going to allow arbitrary connections from the outside to the inside, which breaks active FTP (not passive FTP). It's possible to work around this problem by allowing connections with source port 20. However, allowing these connections causes a major security flaw because TCP connections with a source port of 20 are allowed through the firewall. Figure 15-4 demonstrates how this issue can be exploited to attack an XServer running on destination port 6000. Figure 15-4. TCP source port 20 attack for stateless firewallsFragmentationA stateless firewall can't keep track of fragments, so it has to deny them categorically or apply a simple set of rules to process them as they come in. Typically, these firewalls approach this by allowing any fragment that doesn't have upper-layer header information to go through. IP fragmentation was covered in Chapter 14, "Network Protocols," but you should look out for the following points:
A few classic attacks against packet-filtering firewalls, described in the following sections, are based on overlapped fragments. New implementations of packet filters are often vulnerable to these classic attacks, so inspect them carefully. Are Fragmented Packets Handled?The most straightforward attack is to simply fragment a packet so that the upper-layer (TCP or UDP) protocol header is split across multiple packets. Granted, only a firewall from the 1980s would be fooled by this method, but it sets the stage for more topical attacks. Figure 15-5 shows what the malicious packets would look like. A vulnerable firewall would allow both fragments through but be unable to check them because both are incomplete. Figure 15-5. Straightforward fragment attackHow Are Offset 1 Fragments Handled?This classic fragmentation attack involves rewriting TCP flags against a stateless packet filter. Figure 15-6 shows how this attack would unfold. It works by first sending a fragment that the firewall accepts, such as a lone FIN or RST TCP packet, to an otherwise filtered port. The second fragment has an offset of 1 and is passed by the firewall. Depending on the host's reassembly algorithm, the target machine actually honors the new data from the second fragment and changes the flags in the TCP header from FIN to SYN. In this way, the attacker has initiated a connection to an otherwise filtered port. Figure 15-6. TCP flags rewrite fragment attackHow Are Multiple 0-Offset Fragments Handled?Thomas Lopatic and John McDonald (one of this book's authors) came up with a similar fragmentation attack that worked against ipchains and Cisco IOS 11 routers, to a limited extent (archived at http://archives.neohapsis.com/archives/bugtraq/1999-q3/0236.html). This technique involves sending multiple 0-offset fragments. Essentially, an IP fragment with a 0-offset is sent to a firewall; the fragment contains a TCP or UDP header that matches an allow rule in the firewall's rule set. This fragment is followed by another 0-offset fragment that's much smaller, and it rewrites a few bytes of the TCP or UDP port fields. When these fragments are reassembled on the other side, a port that shouldn't be accessible can be reached. Figure 15-7 shows how this attack works. This advisory eventually spawned the creation of RFC 3128, describing the attack. Figure 15-7. TCP ports rewrite fragment attackThe following is an excerpt of code from an old version of the ipchains stateless firewall. Review it with the points about fragments in mind: offset = ntohs(ip->frag_off) & IP_OFFSET; /* * Don't allow a fragment of TCP 8 bytes in. Nobody * normal causes this. Its a cracker trying to break * in by doing a flag overwrite to pass the direction * checks. */ if (offset == 1 && ip->protocol == IPPROTO_TCP) { if (!testing && net_ratelimit()) { printk("Suspect TCP fragment.\n"); dump_packet(ip,rif,NULL,NULL,0,0); } return FW_BLOCK; } First, you can see that the firewall blocks IP fragments with an offset of 1 for TCP data. This is a good thing, and it prevents the TCP flags rewriting attack. Now look at the following block of code. You can see that if the firewall is looking at the first fragment (an IP offset of 0), it tries to determine how much data it needs to see to make a decision about the packet. For TCP, it wants to see at least 16 bytes of TCP data. /* If we can't investigate ports, treat as fragment. * It's a trucated whole packet, or a truncated first * fragment, or a TCP first fragment of length 8-15, * in which case the above rule stops reassembly. */ if (offset == 0) { unsigned int size_req; switch (ip->protocol) { case IPPROTO_TCP: /* Don't care about things past flags word */ size_req = 16; break; case IPPROTO_UDP: case IPPROTO_ICMP: size_req = 8; break; default: size_req = 0; } offset = (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req); } If offset is 0, indicating it's a header fragment, the firewall proceeds to do a minimum size check on the packet. If there's enough data for a complete protocol header, offset is set to 0. If there isn't enough data, offset is set to 1. This means if you send a fragment with a 0-offset and a super-short length, it's treated as a non-first fragment and passed through the firewall! |