Strategic Security Intelligence

Linux Firewalls

Internet Protocols and Protocol Attacks

Copyright(c), 1990, 1995, 2002 Dr. Frederick B. Cohen - All Rights Reserved

The Internet Protocol (IP) suite is a collection of communications protocols that define the syntax and semantics required for mutual communication between networked computers. IP is defined in RFC 791 and can be roughly divided into Internet Control Message Protocol (ICMP) as defined in RFC 792, User Datagram Protocol (UDP) as defined in RFC 768, Transmission Control Protocol (TCP) as defined in RFC 793, and other IP protocols that are defined in other Requests For Comments (RFCs). The Domain Name System (DNS) is critical to the function of the Internet and operates predominatly within the UDP protocol. Address Resolution Protocol (ARP) is used in conjunction with the most common hardware devices (Ethernets) and is controlled by the hardware and device drivers within the operating system (Linux in our examples) of the computer.

The IP version 4 header is defined in RFC791. It provides for 2^8 different possible protocol suites, 2^19 bytes maximum datagram size, an easily forged checksum, 32 bit source and destination IP address fields, and data of up to about 65535 bytes. Each datagram stands alone. There are no built-in authentication mechanisms for datagrams at the IP level. Datagrams may be fragmented into smaller packets to pass through intermediate infrastructure nodes along a communicaitons path, and there are no reliability features. Traffic routing is done along the way from place to place using the 'best effort' of intervening nodes, and there are options for source routing if desired as well as some additional datagram labeling schemes.

  0                   1                   2                   3   
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
|Version|  IHL  |Type of Service|          Total Length         |
|         Identification        |Flags|      Fragment Offset    |
|  Time to Live |    Protocol   |         Header Checksum       |
|                       Source Address                          |
|                    Destination Address                        |
|                    Options                    |    Padding    |

IP Address Forgery

IP address forgery is easily done by replacing the bytes associated with the source address with any desired bytes and fixing the checksum. You cannot tell a real datagram from a fake one once it starts flowing through the Internet, anyone can create fake IP packets, tools are freely available to do it, and most providers don't stop forgeries from passing into or through them.

IP address forgery can easily be stopped from exiting your network, and if you are an ISP or backbone provider, you can control entrances and exists to prevent most forgery as well. We start with the trivial cases. It turns out that certain addresses are not suypposed to pass to or from the Internet or get routed through the Internet. These include; 127.*.*.*,, *.0, *.255, as specified in Internet Standard 4, and the private subnets 10.*.*.*, 127.16-32.*.*, and 192.168.*.* as specified in RFC 597. Every routing device should reject these IP addresses unless it is part of purely internal routing.

To demonstrate this, we configure a network as follows:

At this point you should be able to see each computer pinging the other and replies being returned. Sniffing the network traffic can also be used to verify what is hapenning. Of course this whole notion of 'forgery' assumes that computers have a 'legitimate' address. In the classroom they do not, but in the Internet, computers tend to be associated with addresses based on routing and operational requirements and addresses are assig\ned in order ot make the Internet operate properly.

In Linux, there are several method for filtering packets on IP interfaces. We will use the 'ipchains' package for our examples. As a precursor to using 'ipchains', it is a good idea to review the ipchains manual entry by using:

In this approach, we will use used ipchains to eliminate packet fragment packets altogether. The 'insmod' command loads the 'ipchains' module into the operating system kernel so that it can be used to filter traffic on the IP interfaces. This has to be done once after system bootup and before using 'ipchains' in order for ipchains to work properly.

The basic notion behind ipchains and these other filtering mechanisms is that they seive out undesired packets based on some set of rules. Typically, we think of these filters as acting to keep the outside from sending in bad things.

But in this case we are also acting to prevent internal information from inappropriately travelling out of the internal environment. Using the 'ipchains' packet filtering mechanism, these controls can be implemented with the following commands in a router or gateway computer. Note that in this particular case the gateway or router itself must not have an IP address on those networks because the packet filter will prevent it's proper operation:

For out specific example, we will cut off traffic from to by adding a firewall rule to the computer operating as as follows:

This rule says, in effect, that all packets coming as input to any interface with a source address of 10. anything (the /8 indicates that only the first 8 bits are differentiating) will be denied entry and ignored.

Note the resulting behavior. Both the pings are cut off. This is because the outbound ping from to is prevented from entering and the response of the ping from is not allowed to enter because it is from In your sniffer you should see that there are two different ping requests and one ping reply. If the rest of the class configures their computers to have 10 net addresses as the example above shows, but with different last IP numbers (10.0.0.something-else) they should be able to ping each other but also be cut off from

In many cases, these IP addresses are used for internal use only networks (their intended purpose), and in such cases added care must be used to assure that proper packets are allowed to pass.

Large-Scale Address Forgery Elimination

The notation a.b.c.d/x indicates that the bits of the address (a.b.c.d) are to be ignored after the first 'x' bits. Thus '' means any IP address starting with '10'. In addition, if private concerns, ISPs, and backbone providers filtered packets, the rest of IP address forgery would be essentially eliminated. This is done as follows:

Private Networks
  • 0) Trivial Defenses
  • 1) Internal source address packets should not be allowed to pass inbound.
  • 2) Internal destinations address packets should not be allowed to pass outbound.
  • 3) External source address packets should not be allowed to pass outbound.
  • 4) External destinations address packets should not be allowed to pass inbound.
  • ISPs
  • 0) Trivial Defenses
  • 1) Non-client source addresses rejected if arriving from a client
  • 2) Non-client destination addresses not sent to client
  • 3) Non-ISP destination addresses rejected from the backbone
  • 4) Non-ISP source addresses not sent to the backbone
  • 5) Destination addresses to a client from same client rejected
  • 6) Source addresses from a client rejected from the backbone
  • Backbone Providers
  • 0) Trivial Defenses
  • 1) Packets from an ISP not in the ISP's address range are rejected
  • 2) Packet not to an ISP are not sent to that ISP
  • 3) Sources from an ISP and to that same ISP are rejected
  • 4) Destinations from an ISP to that same ISP are rejected
  • A sample implementation using 'ipchains' for a private network is provided here. In this case, we will assume IP addresses and take actions as follows. Assume that the 'inside' interface is 'eth1', that the IP address range for the 'internal' network is '', that the outside interface is 'eth0', and that we will be ignoring undesired packets rather than otherwise responding to them:

    Who Rule Command
    Private 1 ipchains -A input -i eth0 -s -j DENY
    Private 2 ipchains -A input -i eth1 -d -j DENY
    Private 3 ipchains -A input -i eth0 -d -j ACCEPT
    Private 3 ipchains -A input -i eth0 -d -j DENY
    Private 4 ipchains -A input -i eth0 -d -j ACCEPT
    Private 4 ipchains -A input -i eth0 -d -j DENY

    Note that we deny packets for external addresses by first allowing packets for internal addresses and then denying everything else. This is common in routers and gateway computers because they tend not to have inversion rules (that is, rules that exclude rather than include IP address and port sets). In this case we have added these rules to the end of the chains rather than inserting them at the beginnings as we did for the last rule set. That is because we don't want these rules to override the previous ones that limit other unauthorized packets. It turns out that as we devise more and more rules, the ordering of rules becomes more and more complex and can be the cause of many errors.

    To see the current rule set for ipchains, use the following command:

    The '-L' option lists the chains and the '-v' option provides verbose output. While this simple example of verbose output is not exceedingly informative, for more complex chains involving multiple interfaces and for packet counting on services. IPchains verbose output is important to use.

    Rule Sequences

    This brings up a very important point. Rules in most firewall languages are sequential in nature. For every packet arriving at or leaving an interface, the rules are examined in order and the furst applicable rule is applied. The name for this sort of a system is a 'production system' and it is essentially the same mechanism used in mosat forms of rule-based systems. The ipchains command simply inserts rules into the sequence, either before other rules or after other rules. 'I' is for Insert (before) and 'A' is for Append (after). There are also default rules in ipchains, designated by P for Policy, and these rules follow after all other rules in the rule sequence (or chain).

    As the number of addresses increase, this can also become more complex. For example, if there were three internal address spaces, rules 1 and 2 would need to be repeated once for each of them, and rules 3 and 4 would require an extra 2 rules each. In some cases things get much more complex. For example, if we were to allow each of three sets of IP addresses to travel into or out of each of 3 different interfaces, we could end up with 9 'ipchains' commands for each rule instead of 3. This problem grows as the product of the number of interfaces and the number of address spaces. When augmented with the ordering problems this gets still more complex.

    As the number of rules increase, the difficulty in getting the sequences right also get harder. For example, if we were to make rule sets for each of 100 pairs of IP addresses allowing only those into each IP address that was desired, the total number of rules could grow to something like 5,000 rules. For this reason, we generally control things at a less granular level, which in turn means that the rules we use tend to be less accurate than we might like to have them. Similarly, if we actually implemented 5,000 rules by hand the odds of getting the right sequence after a few changes would be very low unless we used some standardization and care in our creation of these rules.

    To test rules, we typically send packets and observe behaviors. If you want to observe a specific rule in action, you usually start without the rul and demonstrate a function, then turn the rule on and demonstrate the changed funtion. While this is not a thorough test, it is a test that gives some level of confidence that the rule is doing something useful - or not. A good starting point is the use if Internet Control Message Protocol (ICMP) to 'ping' computers. This is implemented by the 'ping' command. For example, we can set up a 'gateway', 'inside', and 'outside' computer:

    Wire these computers so that the outside computer connects to eth0 on the gateway and the inside computer connects to eth1 on the gateway and try this:

    On the outside computer:

      wg:root /root> ifconfig eth0
      wg:root /root> route add default gateway

    On the gateway:

      wg:root /root> ifconfig eth0
      wg:root /root> ifconfig eth1
      wg:root /root> echo 1> /proc/sys/net/ipv4/ip_forward
      wg:root /root> insmod ipchains
      wg:root /root> tcpdump -n -i eth0
      (in another window) wg:root /root> tcpdump -n -i eth1

    On the inside computer:

      wg:root /root> ifconfig eth0
      wg:root /root> route add default gateway
      wg:root /root> ping

    By wiring the computers to the gateway and watching both interfaces on the gateway, we can see the traffic on both sides of the gateway computer and verify that packets entering one side are not passed to the other side. By then turning off the 'ipchains' rules (using the '-F' option to flush the rule set), we can confirm that the packets did indeed pass through the firewall with the rules turned off:

    To do most of the rest of the examples in this course, a network configuration something like this will be helpful, however, if you do not have 3 computers handy, you can do it with one computer that has more interface cards. But be cautious because some of the examples will not be as clear in this configuration and some things won't work in the same manner.

    TCP Sequence-based Attacks

    TCP dtatagrams include TCP header information in the data area of the datagram as follows:

      0                   1                   2                   3   
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
       |          Source Port          |       Destination Port        |
       |                        Sequence Number                        |
       |                    Acknowledgment Number                      |
       |  Data |           |U|A|P|R|S|F|                               |
       | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
       |       |           |G|K|H|T|N|N|                               |
       |           Checksum            |         Urgent Pointer        |
       |                    Options                    |    Padding    |
       |                             data                              |

    The process consists of an initial communication between a source port and a destination port with the SYN bit turned on in the TCP header to start SYNchronous communication. The response reverses the ports and sets SYN and ACK to ACKnowledge the synchronization and provides the previous synchronization as an acknowledgement number along with its updated sequence number. From then on, the ACKnowledgement is set and the previous synchronization number is used for the next acknowledgement until the sequence is to be ended. If data is being sent along with the rest of the protocol, the PSH bit is also set and the data included. When the session ends, a FIN bit is sent to FINish the communication and the FIN is ACKnowledged with the FIN and ACK bits set in the datagram which agrees to close the connection. The sequence looke like this:

    This TCP session sequencing allows TCP to guarantee sequential arrival of transmitted data, but it is also subject to a number of attacks including but not limited to:

    Many people believe that these things are too complicated to do, but in reality, complications such as this are not effective defenses. Fundamentally, if one smart person creates a bypass mechanism, they can make it freely available over the Internet and thousands of bad actors can have it within a few minutes. There are free software packages to do these things that can be found by looking for them on the Internet.

    Probably the best defense available today against most of these attacks is the use of randomized sequence numbers, SYN cookies, and timeouts on connections. SYN cookies and randomized sequence numbers are done by having the operating system generate pseudo-random sequence numbers for TCP instead of easily predicted ones. In the case of SYN cookies, instead of setting up and remembering a while connection when a SYN packet comes in, the operating system generates a 'cookie' that is used in the next protocol element as a sequence number. If the sequence number matches, then the connection is formed. Otherwise, no connection is formed and resources are not wasted. The SYN cookie can be generated using a pseudo-random unmber generator triggered by an internal system-by-system value so that no storage is required for it, and yet it is hard to guess and easy to verify. In the case of the rest of the TCP sequence, randomized sequence numbers are used to increase the complexity of forgeries and similar methods of attack. Connection timeouts, generally done at the application level, limit the total number of open and inactive channels by limiting the amount of time over which the applications can be inactive. The net effect is that the total number of open unused channels possible is the time per channel openning divided into the timeout. If 300 channels can be openned each second over a 100Mbps line, and the timeout is 10 seconds, then 3,000 is the largest number of channels that can be used in an exploitation. The operating system is then configured to handle more than that, say 10,000 simultaneous sessions, and it becomes impossible to exhaust resources. For programs running through 'inetd', a parameter in inetd can be set so as to facilitate the total maximum unmber of connections.

    This example comes from the implementation of the built-in secure web server under White Glove. When root types 'service www start', the file '/etc/inetd.conf' is filled as follows:

    The 'nowait.10000' indicates a maximum of 10,000 simultaneous sessions is permitted. Within '/usr/local/dtk/src/thttpd' there are built-in timeouts for inactivity so that unless a legitimate request shows up in 10 seconds, the process terminates. Thus, assuming that the rates given above are correct, it is impossible to flood this system so as to disable web service entirely as long as legitimated users can get packets into the wire leading to the interface. This has been tested extensively using maximum throughput on a 100Mbps line directly into the seb server and, while service is slowed a bit, it continues to operate. To test this, a program called 'bomb' is quite effective, however, we do not include tools in the White Glove distribution that are more useful for attacking systems than for defending them.

    This sort of calculation must be underetaken for the combined set of all services running on each infrastructure if a claer understanding of what can happen is desired. If services are to be reasonably guaranteed, adequate resources must be made available, and making this sort of calculation is the only way to accurately understand this issue.

    Fragmentation Attacks

    Fragmentation happens when packets don't fit into the media. Ethernet for example is 1508 bytes, SLIP is typically 265 bytes, and ATM is 56 bytes. The problem of incompatable media lengths is solved in IP by packet fragmentation and reassembly.

    When a packet has to be fragmented, or when a system is configured to send fragmented packet parts, it sets the fragmentation bit in the IP header field of each packet and provides a fragment offset value associated with where the data in this packet will get reassembled into the final datagram at the receiving end of the connection.

    The filtering mechanisms most commonly used for filtering out IP datagrams are based on limiting IP addresses and ports. Ports (e.g., the Source port and Destination port in the above datagram diagram) are used to identify which service program in the receiving computer is run to interpret incoming data and provide responses. For example, we might filter out incoming traffic to port 80 (http) initialized from afar while allowing outbound http (web) traffic to be originated from within our firewall. At the same time we might allos incoming email traffic (normally to port 25) to be initiated from afar to assure that we can get email in. Here is the 'ipchains' sequence for this:

    In this case we have refused to allow incoming packets at interface 'eth0' if they have a destination port of 80 and the SYN flag set, but we are (explicitly) allowing other port 80 packets as well as all port 25 packets. This example is not likely to appear in many cases for various reasons that will become clear later, however, suppose we want to by pass this restriction. In a packet fragmentation attack, the initial SYN bit is set for an inbound packet to port 25, but the fragmentation bit is also set. Then, in the next packet fragment, the offset is configured so that the new packet overlays the part of the datagram containing the port identifier, replacing the previous value of 28 with 80, but not overwriting the area containing the 'SYN' bit. The firewall rule specifies that such a packet should be allowed to pass, and the result is that the port number of the assembled datagram is set to 80 even though the rules would seem to imply that this could not happen. In May of 1995 the first fragmentation attacks bypassed almost every firewall on the market.

    Countermeasures include (1) Assemble the whole packet before decision to pass or stop (a) May have to store a lot of data, (b) May have to wait for a long time, (c) Denial of service threat - OR - (2) Don't allow overlaid fragments; (a) Have to store fragment starts and estents (2^N space for N fragments), (b) Have to compare each new fragment (N^2 time for N fragments).

    The simplest approach to mitigating this threat is to eliminate fragmented packets entirely as follows:

    This command causes the inputs on all input devices using IP to drop packets without response if they have the fragmentation bit in the packet header set. In most cases, this works without creating serious traffic problems. In order to test this, it is necessary that we be able to generate fragmented packets. In order to see the results of our test, we need to be able to observe network traffic. This is done, in this case, with:

    In this particular case we will be watching the 'lo', or loopback interface with numeric display only. In order for this to work well, it is sometimes useful to make the X11 window wider so that large width output from tcpdump can be fully observed with one line per packet.

    To generate packets that will fragment, we will use the 'ping' command which includes options to send ICMP packets of any desired length. By specifying a long length, we can induce fragmentation:

    In the above case, we are creating packets of length 65,000 bytes. Use 'ifconfig' and look for the Maximum transmission Unit (MTU) entry on any given interface to see the size required before a packet will fragment:

    Since 16436 is the default packet size on the loopback interface, packets of larger than that size will generate fragments. In the example given above, we are preventing fragments from entering, and indeed we get no responses from our ping packets, however, to demonstrate how this works more clearly, type this command while watching the packets with tcpdump:

    The result will be immediately apparent since the outbound packets will also be blocked and thus the ping will not be able to send the packets and report an error. To clear the 'ipchains' protection and start again, use:

    There is another problem with fragmented packets in that it takes time and space to reassemble them. A denial of service attack could be created, for example, by sending a large number of large fragments that have to be reassembled, but not sending every even numbered fragment in the set. The firewall or receiving system would have to reassemble these packets until it ran out of momory or gave up on them. One solution to this attack, assuming you have decided to allow fragments at all, is to make the timeout on fragmented packet reassembly very low. This causes fragmented packets to be discarded if the entire packet is not in place before the timeout expires. This example lowers the assembly time to 1 second by using the 'proc' file system as follows:

    In this case we are really just informing the operating system kernel of a desired parameter change, using the proc file system as a convenient method for communicating with Linux.

    ICMP Issues

    The Internet Control Message Protocol (ICMP) is a low-level mechanism that influences the bahavior of all IP treaffic. IT informs hosts and routers of routing updates and routing trouble, it can slow or redirect connections, and it supports the 'ping' protocol used to find and test for the presence of hosts.

    ICMP provides services including (1) Routing advertisement (masquerade as a default router or active tapping to disrupt), (2) Network, Host, and Protocol unreachable (forger can more or less sever the network), (3) Source Quench (slow packets till they are nearly discontinued, (4) Redirect Host/Network/Type of servce (redirect routing through active tapper), (5) ICMP is integral to IP, (6) All hosts and networks are vulnerable. See RFC 792 and RFC 1256 for details.

    The easiest way to defeat ICMP attacks against a Linux system or a gateway or router implemented under Linux is to turn off ICMP elements that affect the computer itself:

    If the computer is acting as a router or gateway, you can also limit inbound packets using the ipchains or iptables interface. Here is an example that eliminates all ICMP traffic from entering the computer on any interface:

    Note that this rule has been inserted at the begiunning of the chain, so if we applied it to the previous rules, ICMP would be prevented as a higher priority than the other rules. If we added it at the end, it would be ineffective because we already allowed these packets through by the other rules. The complexity of rule sequence and interactions between rules is getting more complicated already.

    Additional command line arguments can be used to specify specific interfaces or other related conditions. To test out ICMP responses, the program 'sing' is very handy. Typically, you would set up a 'tcpdump' in one X11 window to watch for packets on the 'lo' interface (the loopback interface will have relatively little traffic and is handy for such testing):

    In another window, you would use 'sing' to generate packets (sing -help provides details on its use):

    If the filter is in place, you should see requests but no responses. You can try various 'sing' options to test out different ICMP packjet types and observe the responses. This test should be used from a remote site to test out firewall settings in any firewall you actually plan to use.

    Notice that once this is done, you can no longer use the 'ping' command to test other firewall rules. Indeed, as we add more and more rules, it will become harder and harder to find the right tests to assure that each rule is operating and harder and harder to make certain that the rules are right.

    UDP Viruses

    User Datagram Protocol (UDP) extends IP service to user programs. It has no error correction, no retransmission, optional error detection, no flow control, low overhead, ports ans IP addresses just as TCP, and no authentication at all. In addition, all transmissions are stateless. The following example of a UDP datagram shows the basic structure. Within the IP datagram, the UDP area includes source and destination port numbers, a packet length in bytes, a checksum, and the data.

    A critical property of UDP is that, because it is stateless, it can be used to create infinite protocol loops. Here is an example of a packet whose contents can be used to consume a network's traffic capacity and crash some of its servers. It is called a UDP virus because it is based on a packet that reproduces in the UDP environment. Some UDP services respond either with content or with a copy of the packet sent to them whenever a request comes in. These include the 'echo', 'daytime', 'quote', and 'chargen' services (UDP ports 7, 13, 17, and 19 respectively). If these services are enabgled and no special protection is provided, a single packet will cause them to loop packet back to themselves. Typically, sending two such packets will cause a pair of systems to crash - the ones at each end of the protocol. This is done simply by forging a packet with the proper source and destination addresses and ports. Similarly, if we make the source and destination addresses and ports identical, the loop usually will happen within the machine and not interfere with network traffic.

    An easy way to defeat these attacks at a firewall is by filtering these packets out. They are easy to identify if you know what you are looking for, and typical filtering software can eliminate them. In this example, we use 'ipchains' to filter out UDP echo loops:

    Of course this will not really do the full job because we could have a loop between port 7 and port 13, etc. Se we really need something more like this:

    This then generates 16 different ipchains commands with all of the combinations of source and destination ports specified above that cause UDP viruses. Of course if we don't really care to provide these services at all, we can simnply filter them out completely:

    Making it bootable

    The White Glove CD is particularly well suited to using as a firewall and firewall setup tool because it allows you to provide a small amount of information on the floppy disk and have it used at system startup to automate customized configurations. Now we will make a floppy that does all of the things we have described in this section and makes tham activate automatically at bootup. Start by getting a blank floppy (or one that will be overwritten in this process) and putting it in the 'A' drive of the computer with the write protect tab set to allow writing. Then type:

    This will build you a new file system on the floppy disk. Once it is done, you can mount the floppy disk to make this file system available to you under the directory '/mnt/floppy' by using:

    Now use any editor of your choice to create a file on the floppy called 'PLAC.go'. Remember that case counts in filenames and commands under Linux. Place the following lines from above into the PLAC.go file and save the file:

    After saving this file, use the following commands to unmount the floppy disk and assure that it contains retains the files written to it:

    Once the light on the floppy is out and the command completed, remove the floppy disk from the drive, switch the write protect tab to prevent modification, replace the floppy disk in the drive, and press reset or power off and back on to restart the computer. When the computer comes back up, it will automatically find the instructiuons on the floppy disk and set up your firewall according to the instructions provided.


    In this section we have discussed the basic structure of the Internet Protocol and how that structure can be xploited by attackers. We have described packet fragmentation attacks, address forgery attacks, and sequence number attacks and detailed some of the methods for explopiting ICMP. We have also described countermeasures to defeat many of these attacks and demonstrated settings associated with those contermeasures in a Linux-based firewall as well as the limitations of those countermeasures. We provided tests that allow you to detect and verify that the conditions associated with these problems are mitigated in your firewall, described some of the problems of rule ordering and the large numbers of rules that can result from complex configuration requirements, and discussed some of the problems that will likely get worse. Finally, we have created a bootable floppy that will configure our gateway to the desired operation whenever we reboot the computer.