COMMAND

    ipchains

SYSTEMS AFFECTED

    Linux

PROBLEM

    Following is based  on data protect  GmbH - Advisory  #2 by Thomas
    Lopatic  and  John  McDonald.   They  had  discovered  a potential
    vulnerability in the Linux  ipchains firewall implementation.   In
    certain situations, it is possible  for an attacker to bypass  the
    packet filter when communicating with machines that allow incoming
    packets  to  specific  ports.   This  attack  is  a  variation  of
    previously  discussed  fragmentation  attacks,  where the attacker
    uses fragments to rewrite parts of the TCP or UDP protocol header.
    In this case port information is rewritten in order to gain access
    to ports that should be blocked by the firewall.  Included in this
    advisory is a patch to the 2.2.10 Linux kernel that corrects  this
    vulnerability, and  a pointer  to example  code that  demonstrates
    the problem.

    The Linux  ipchains firewall  code has  special provisions  for IP
    fragments that  do not  contain enough  information for  transport
    protocol header analysis.  Fragments  that start at offset 0,  and
    are  not  long  enough   to  provide  complete  transport   header
    information are treated like fragments with an offset > 0 (> 1  in
    the TCP case).  This is the relevant code from ip_fw.c:

        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);
        }

    As mentioned above,  fragments with an  offset of 0,  that are too
    short to  provide a  full transport  protocol header,  are treated
    like non-first fragments.  This allows an attacker to perform  the
    following port rewriting attack:

        1. Attacker sends a fragment, with offset 0, a set IP_MF  bit,
           and a full transport protocol header which meets the packet
           filter and is passed to the victim machine.

        2. Attacker sends a fragment, with offset 0, a set IP_MF  bit,
           and a length of 4 bytes.  This contains the (blocked) ports
           that the attacker wishes  to access on the  victim machine.
           This fragment will be accepted by the firewall and  overlap
           -  in  the  victim  machine's  reassembly  chain - the port
           information contained in the fragment sent in step 1.

        3. Attacker  sends  a  fragment  with  a  cleared  IP_MF  bit,
           starting where the first fragment left off, that  completes
           the set of fragments.

    Depending on the defragmentation strategy of the victim  machine's
    operating system, it might be necessary to swap steps 1 and 2.  It
    is important to  note that there  are two conditions  that must be
    met for a particular ipchains packet filter to be vulnerable:

        1. The  packet filter  must not  be configured  with the Linux
           kernel option CONFIG_IP_ALWAYS_DEFRAG. If the packet filter
           reassembles the fragments before doing the firewall checks,
           then this attack will fail.

        2.  The  packet  filter  must  have  a rule to allow non-first
           fragments to pass.  The Linux ipchains how-to suggests that
           either an administrator selects CONFIG_IP_ALWAYS_DEFRAG, or
           implements such  a rule.   This rule  was considered  to be
           safe because fragments with an  offset of 1 are blocked  by
           the  packet  filter,  which   prevents  attacks  based   on
           rewriting the TCP flags.

    fragrouter, a component of Nidsbench, has been updated to  perform
    this attack transparently.  This is an excellent open source  tool
    for  testing  intrusion  detection  systems  and  packet   filters
    provided  by  Anzen  Computing.   The  version  of fragrouter that
    performs this attack should be available shortly, at

        http://www.anzen.com/research/nidsbench/

SOLUTION

    The following  Linux kernel  patch (against  version 2.2.10)  will
    close this vulnerability by blocking packets that could be used to
    rewrite header information in this  fashion.  It is also  possible
    to reconfigure the ipchains machine to always defragment  packets,
    or to remove any rule which passes non-first IP fragments  through
    the firewall ("-f" option of the "ipchains" command).  The latter,
    however, might introduce incompatibilities, e.g. with applications
    that transmit large  UDP datagrams across  the firewall and  hence
    cause IP fragmentation.

    *** linux.old/net/ipv4/ip_fw.c  Wed Jun  9 05:33:07 1999
    --- linux/net/ipv4/ip_fw.c      Fri Jul 23 19:20:45 1999
    ***************
    *** 37,42 ****
    --- 37,45 ----
       * 19-May-1999: Star Wars: The Phantom Menace opened.  Rule num
       *            printed in log (modified from Michael Hasenstein's patch).
       *            Added SYN in log message. --RR
    +  * 23-Jul-1999: Fixed small fragment security exposure opened on 15-May-1998.
    +  *              John McDonald <jm@dataprotect.com>
    +  *              Thomas Lopatic <tl@dataprotect.com>
       */
  
      /*
    ***************
    *** 644,650 ****
                    default:
                            size_req = 0;
                    }
    !               offset = (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req);
            }

            src = ip->saddr;
    --- 647,666 ----
                    default:
                            size_req = 0;
                    }
    !
    !               /* If it is a truncated first fragment then it can be
    !                * used to rewrite port information, and thus should
    !                * be blocked.
    !                */
    !
    !               if (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req)
    !               {
    !                       if (!testing && net_ratelimit()) {
    !                               printk("Suspect short first fragment.\n");
    !                               dump_packet(ip,rif,NULL,NULL,0,0,0,0);
    !                       }
    !                       return FW_BLOCK;
    !               }
            }

            src = ip->saddr;