/* * TCP Toolkit * * Simple utility for crafting TCP traffic of your choosing. * Allows full control over virtually every parameter you can think * of and makes spoofing traffic or poking holes in your favorite firewall * or other pieces of networking equipment a piece of cake. * * Requires: * libnet >= 1.1.x (http://www.packetfactory.net/projects/libnet/) * root * a basic understanding what this tool does * * Compile with something like: * gcc -Wall `libnet-config --defines --cflags` -o tcp-tk tcp-tk.c `libnet-config --libs` * * This code can be found in its original form here: * * http://spoofed.org/files/tcp-tk.c * * * Jon Hart * * Copyright (c) 2002, Jon Hart * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the organization nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Changes: * 10/30/2002 * Fixed the TTL so that it is not obviously spoofed. * Use random number between 1024 and 65535 for src/dst if no port provided */ #include #if (SOLARIS || BSD) #include #else #include #endif /* These are currently not defined by libnet or any OS that I know of... */ #ifndef TH_RES1 #define TH_RES1 0x80 #endif #ifndef TH_RES2 #define TH_RES2 0x40 #endif #define OPT_HELP 0 #define OPT_VERBOSE 1 #define OPT_INTERFACE 2 #define OPT_SRCIP 3 #define OPT_DSTIP 4 #define OPT_SRCETHER 5 #define OPT_DSTETHER 6 #define OPT_SRCPORTS 7 #define OPT_DSTPORTS 8 #define OPT_TCPFLAGS 9 #define OPT_PAYLOAD 10 #define OPT_TCPSEQ 11 #define OPT_TCPACK 12 #define OPT_TCPURG 13 #define OPT_TCPWIN 14 #define OPT_IPID 15 #define OPT_IPTOS 16 #define OPT_IPTTL 17 struct opt { char *name; /* name of this option */ int req; /* required? */ int set; /* Does it have a value? */ }; struct opt opts[] = { {"help", 0, 0}, {"verbose", 0, 0}, {"interface", 1, 0}, {"source IP", 1, 0}, {"destination IP", 1, 0}, {"source ethernet address", 0, 0}, {"destination ethernet address", 0, 0}, {"source port(s)", 1, 0}, {"destination port(s)", 1, 0}, {"TCP flags", 1, 0}, {"payload", 0, 0}, {"sequence number", 1, 0}, {"acknowledgement number", 1, 0}, {"urgent pointer", 1, 0}, {"TCP window size", 1, 0}, {"IP ID number", 1, 0}, {"TOS", 1, 0}, {"TTL", 1, 0} }; /* Given a string, figure out which characters * may represent valid TCP control flags. These include * 1, 2, A, F, P, R, S and U */ u_char make_flags(char *string) { int i, j, flag_num, num_flags; char *flag_vals = "afprsu12"; u_char flags = 0x00; /* If no value is given for the flag string, make one up. */ if (string == NULL) { if ((string = malloc(8)) == NULL) { printf("Failed to malloc() for new flag string\n"); exit(EXIT_FAILURE); } srand(libnet_get_prand(LIBNET_PR8)); num_flags = (int) (8.0*rand()/(RAND_MAX + 1.0)); for(j = 0; j < num_flags; j++) { /* Randomly select a flag */ flag_num = (int) (8.0*rand()/RAND_MAX + 1.0); snprintf(string+j, sizeof(char *), "%c", flag_vals[flag_num]); } } // for (i = 0; i < strlen(string); i++) { switch (string[i]) { case '1': flags += TH_RES1; break; case '2': flags += TH_RES2; break; case 'a': case 'A': flags += TH_ACK; break; case 'f': case 'F': flags += TH_FIN; break; case 'p': case 'P': flags += TH_PUSH; break; case 'r': case 'R': flags += TH_RST; break; case 's': case 'S': flags += TH_SYN; break; case 'u': case 'U': flags += TH_URG; break; default: break; } } return flags; } /* Generate a random string to represent an ethernet address. * evil. */ char *rand_ether() { int i; char *ether; if ((ether = malloc(17)) == NULL) { printf("Failed to malloc() for ether\n"); exit(EXIT_FAILURE); } for (i = 0; i < 16; i++) { snprintf(ðer[i], 2, "%lx", libnet_get_prand(LIBNET_PR8)); if ((i + 1) % 3 == 0 && i != 0 && i != 16) { sprintf(ðer[i], ":"); } } return ether; } /* Generate a random string to represent an ip address */ void usage() { fprintf(stderr, "\ttcp-tk\n\n\tA simple TCP Toolkit\n\tby Jon Hart \n"); fprintf(stderr, "\thttp://spoofed.org/files/tcp-tk.c\n\n"); fprintf(stderr, "Usage:\n"); fprintf(stderr, "\t(note: the options whos description starts with a '*' will be assigned\n"); fprintf(stderr, "\trandom values if the option is used but no value is specified.\n"); fprintf(stderr, "\tAlso, those options *must* be specified in -option form,\n"); fprintf(stderr, "\tnot -option form)\n\n"); fprintf(stderr, "\tRequired:\n"); fprintf(stderr, "\t-i Specify interface\n"); fprintf(stderr, "\t-d * Destination IP\n"); fprintf(stderr, "\n\tOptional:\n\n"); fprintf(stderr, "\tLink Layer:\n"); fprintf(stderr, "\t-e * Source ethernet address (default: auto)\n"); fprintf(stderr, "\t-E * Destination ethernet address (default: auto)\n"); fprintf(stderr, "\tIP Layer:\n"); fprintf(stderr, "\t-I IP ID number (default: sane)\n"); fprintf(stderr, "\t-s Source IP (default: auto)\n"); fprintf(stderr, "\t-t IP TTL (default: 255)\n"); fprintf(stderr, "\t-T IP TOS (default: 0)\n"); fprintf(stderr, "\tTCP Layer:\n"); fprintf(stderr, "\t-a * TCP Acknowledgement number (default: sane random)\n"); fprintf(stderr, "\t-c Packet payload (default: NULL)\n"); fprintf(stderr, "\t-f * TCP Flags (default: syn)\n"); fprintf(stderr, "\t-p Source ports (default: random)\n"); fprintf(stderr, "\t-P Destination ports (default: random)\n"); fprintf(stderr, "\t-q * TCP Sequence number (default: sane random)\n"); fprintf(stderr, "\t-u * TCP Urgent pointer (default: sane)\n"); fprintf(stderr, "\t-w TCP Window size (default: sane)\n"); fprintf(stderr, "\tOther:\n"); fprintf(stderr, "\t-h Help (this message)\n"); fprintf(stderr, "\t-v Be verbose\n"); } int main(int argc, char *argv[]) { int c, i; libnet_t *libnet; libnet_ptag_t tcp, ipv4, ether; u_long src_ip, dst_ip; u_short src_port, dst_port; u_char tcp_flags, ip_ttl, ip_tos; u_long tcp_ack, tcp_seq; u_short tcp_urg, tcp_win, ip_id; /* The source and destination MAC addresses * for the ethernet level */ struct libnet_ether_addr *src_ether = NULL; struct libnet_ether_addr *dst_ether = NULL; char *interface; char *rand_ether_t; struct ether_addr *ether_t; struct servent *servent; u_char *tcp_payload; u_long tcp_payload_l; char errbuf[LIBNET_ERRBUF_SIZE]; libnet_seed_prand(libnet); while ((c = getopt(argc, argv, "i:c:ep:s:EP:d:i:q::f::a::u::w:I:t:T:vh")) != EOF) { switch (c) { case 'h': usage(); exit(EXIT_SUCCESS); case 'v': opts[OPT_VERBOSE].set = 1; break; case 'i': interface = optarg; opts[OPT_INTERFACE].set = 1; break; case 'e': if (optarg == NULL) { /* They didn't specify a source ethernet address, but * they do want it set. Pick a random one. */ rand_ether_t = rand_ether(); if ((ether_t = ether_aton(rand_ether_t)) == NULL) { printf("Invalid random source ethernet addresss\n"); return(EXIT_FAILURE); } free(rand_ether_t); } else if ((ether_t = ether_aton(optarg)) == NULL) { printf("Invalid source ethernet address: %s\n", optarg); return(EXIT_FAILURE); } if ((src_ether = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for src_ether\n"); return(EXIT_FAILURE); } memcpy(src_ether->ether_addr_octet, ether_t, sizeof(struct ether_addr)); opts[OPT_SRCETHER].set = 1; break; case 'E': if (optarg == NULL) { /* They didn't speciy a destination ethernet address, but * they do want it set. Pick a random one. */ rand_ether_t = rand_ether(); if ((ether_t = ether_aton(rand_ether_t)) == NULL) { printf("Invalid random destination address\n"); return(EXIT_FAILURE); } free(rand_ether_t); } else if ((ether_t = ether_aton(optarg)) == NULL) { printf("Invalid ethernet address: %s\n", optarg); return(EXIT_FAILURE); } if ((dst_ether = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for dst_ether\n"); return(EXIT_FAILURE); } memcpy(dst_ether->ether_addr_octet, ether_t, sizeof(struct ether_addr)); opts[OPT_DSTETHER].set = 1; break; case 'p': src_port = atoi(optarg); opts[OPT_SRCPORTS].set = 1; break; case 'P': dst_port = atoi(optarg); opts[OPT_DSTPORTS].set = 1; break; case 's': src_ip = libnet_name2addr4(libnet, (u_char *) optarg, LIBNET_RESOLVE); opts[OPT_SRCIP].set = 1; break; case 'd': dst_ip = libnet_name2addr4(libnet, (u_char *) optarg, LIBNET_RESOLVE); opts[OPT_DSTIP].set = 1; break; case 'q': /* sequence number is optional. If no value is specified, generate a * random value now. If this option is not used, the sequence number may * or may not be set later on, depending on various other options. This is * useful to, say, set the sequence number randomly even if the SYN flag * is not set. */ if (optarg == NULL) { tcp_seq = libnet_get_prand(LIBNET_PRu32); } else { tcp_seq = atol(optarg); } opts[OPT_TCPSEQ].set = 1; break; case 'a': /* acknowledgement number is optional. If no value is specified, generate a * random value now. If this option is not used, the acknowledgement number * may or may not be set later on, depending on various other options. This is * useful to, say, set the acknowledgement number randomly even if the ACK flag * is not set. */ if (optarg == NULL) { tcp_ack = libnet_get_prand(LIBNET_PRu32); } else { tcp_ack = atol(optarg); } opts[OPT_TCPACK].set = 1; break; case 'u': /* urgent pointer is optional. If no value is specified, generate a random value * now. If this option is not used, the acknowledgement number may or may not be * set later on, depending on various other options. */ if (optarg == NULL) { tcp_urg = libnet_get_prand(LIBNET_PRu16); } else { tcp_urg = atol(optarg); } opts[OPT_TCPURG].set = 1; break; case 't': ip_ttl = atoi(optarg); opts[OPT_IPTTL].set = 1; break; case 'T': ip_tos = atoi(optarg); opts[OPT_IPTOS].set = 1; break; case 'w': tcp_win = atoi(optarg); opts[OPT_TCPWIN].set = 1; break; case 'f': if (optarg == NULL) { tcp_flags = make_flags(NULL); } else { tcp_flags = make_flags(optarg); } opts[OPT_TCPFLAGS].set = 1; break; case 'c': tcp_payload = (u_char *) optarg; tcp_payload_l = strlen(tcp_payload); opts[OPT_PAYLOAD].set = 1; break; case 'I': ip_id = atoi(optarg); opts[OPT_IPID].set = 1; break; default: usage(); goto pass; break; } } /* Ensure that an interface is specified or have libnet guess */ if (!opts[OPT_INTERFACE].set) { usage(); goto fail; } /* Depending on whether or not they choose to pick their own MACs, * libnet needs to be initialized differently for some reason */ if (opts[OPT_SRCETHER].set || opts[OPT_DSTETHER].set) { if ((libnet = libnet_init(LIBNET_LINK, interface, errbuf)) == NULL) { fprintf(stderr, "libnet_init() failed: %s", errbuf); goto fail; } } else { if ((libnet = libnet_init(LIBNET_RAW4, interface, errbuf)) == NULL) { fprintf(stderr, "libnet_init() failed: %s", errbuf); goto fail; } } /* If they didn't set a source ethernet address, figure out */ if (!opts[OPT_SRCETHER].set) { if ((src_ether = libnet_get_hwaddr(libnet)) == NULL) { fprintf(stderr, "libnet_get_hwaddr() failed: %s", errbuf); libnet_destroy(libnet); goto fail; } } /* If they didn't set a destination ethernet address, figure out */ if (!opts[OPT_DSTETHER].set) { if ((dst_ether = libnet_get_hwaddr(libnet)) == NULL) { fprintf(stderr, "libnet_get_hwaddr() failed: %s", errbuf); libnet_destroy(libnet); goto fail; } } /* If they didn't set a source IP, have libnet figure it out */ if (!opts[OPT_SRCIP].set) { src_ip = libnet_get_ipaddr4(libnet); opts[OPT_SRCIP].set = 1; } /* If no source port is given, make one up */ if (!opts[OPT_SRCPORTS].set) { src_port = 1024 + (libnet_get_prand(LIBNET_PRu16) % (65535 - 1024)); opts[OPT_SRCPORTS].set = 1; } /* If no destination port is given, make one up */ if (!opts[OPT_DSTPORTS].set) { dst_port = 1024 + (libnet_get_prand(LIBNET_PRu16) % (65535 - 1024)); opts[OPT_DSTPORTS].set = 1; } /* If no TCP control flags are set, default to TH_SYN */ if (!opts[OPT_TCPFLAGS].set) { tcp_flags = make_flags("S"); opts[OPT_TCPFLAGS].set = 1; } /* If a control flag is set that has a corresponding control field, * attempt to set that too */ if (!opts[OPT_TCPACK].set) { if (tcp_flags & TH_ACK) { tcp_ack = libnet_get_prand(LIBNET_PRu32); } else { tcp_ack = 0x000; } opts[OPT_TCPACK].set = 1; } /* If no sequence number is set and one is needed, * go ahead and set it. */ if (!opts[OPT_TCPSEQ].set) { if (tcp_flags & TH_SYN) { tcp_seq = libnet_get_prand(LIBNET_PRu32); } else { tcp_seq = 0x000; } opts[OPT_TCPSEQ].set = 1; } /* If no urgent pointer is set and one is needed, * go ahead and set it. */ if (!opts[OPT_TCPURG].set) { if (tcp_flags & TH_URG) { tcp_urg = libnet_get_prand(LIBNET_PRu16); } else { tcp_urg = 0x000; } opts[OPT_TCPURG].set = 1; } /* If no window is set, pick a random one */ if (!opts[OPT_TCPWIN].set) { tcp_win = libnet_get_prand(LIBNET_PRu16); opts[OPT_TCPWIN].set = 1; } /* If no IP id is set, pick a random one */ if (!opts[OPT_IPID].set) { ip_id = libnet_get_prand(LIBNET_PRu16); opts[OPT_IPID].set = 1; } /* If no IP TOS is set, pick 0 */ if (!opts[OPT_IPTOS].set) { ip_tos = 0; opts[OPT_IPTOS].set = 1; } /* No payload? Then NULL */ if (!opts[OPT_PAYLOAD].set) { tcp_payload = NULL; tcp_payload_l = 0; opts[OPT_PAYLOAD].set = 1; } /* If no TTL is set, default to something sly... */ if (!opts[OPT_IPTTL].set) { ip_ttl = 200 + (libnet_get_prand(LIBNET_PR8) % 55); opts[OPT_IPTTL].set = 1; } /* make sure that everything that needs to be set is set... */ for(i = 0; i < 10; i++) { if (opts[i].req && !opts[i].set) { fprintf(stderr, "No %s specified\n\n", opts[i].name); usage(); libnet_destroy(libnet); goto fail; } } tcp = libnet_build_tcp( src_port, /* source port */ dst_port, /* destination port */ tcp_seq, /* seq # */ tcp_ack, /* ack # */ tcp_flags, /* flags */ tcp_win, /* window */ 0, /* auto checksum */ tcp_urg, /* urg pointer */ LIBNET_TCP_H + tcp_payload_l, /* TCP packet size */ tcp_payload, /* payload */ tcp_payload_l, /* payload size */ libnet, /* libnet handle */ 0); /* libnet id */ if (tcp == -1) { fprintf(stderr, "Can't build tcp: %s\n", libnet_geterror(libnet)); libnet_destroy(libnet); goto fail; } ipv4 = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_TCP_H + tcp_payload_l, /* length */ ip_tos, /* TOS */ ip_id, /* ID */ IP_DF, /* Frag */ ip_ttl, /* TTL */ IPPROTO_TCP, /* Protocol */ 0, /* Sum */ src_ip, /* source IP */ dst_ip, /* destination IP */ NULL, /* Payload */ 0, /* Payload size */ libnet, 0); if (ipv4 == -1) { fprintf(stderr, "Can't build ipv4: %s\n", libnet_geterror(libnet)); libnet_destroy(libnet); goto fail; } /* If they wish to set their own src/dst ethernet addresses * we need to actually build the ethernet. If they don't, * libnet does it automagically for us. */ if (opts[OPT_SRCETHER].set || opts[OPT_DSTETHER].set) { ether = libnet_build_ethernet( dst_ether->ether_addr_octet, /* Destination ethernet address */ src_ether->ether_addr_octet, /* Source ethernet address */ ETHERTYPE_IP, /* Protocol type */ NULL, /* Payload */ 0, /* Payload size */ libnet, 0); if (ether == -1) { fprintf(stderr, "Can't build ethernet: %s\n", libnet_geterror(libnet)); libnet_destroy(libnet); goto fail; } } if ((c = libnet_write(libnet)) == -1) { fprintf(stderr, "Couldn't write packet to the wire: %s\n", libnet_geterror(libnet)); } else { if (opts[OPT_VERBOSE].set) { if (opts[OPT_SRCETHER].set || opts[OPT_DSTETHER].set) { printf("Link Layer: "); printf("%s -> ", opts[OPT_SRCETHER].set ? ether_ntoa((struct ether_addr *) src_ether->ether_addr_octet) : interface); printf("%s\n", opts[OPT_DSTETHER].set ? ether_ntoa((struct ether_addr *) dst_ether->ether_addr_octet) : "(auto)"); } printf(" IP Layer: %s -> %s\n", libnet_addr2name4(src_ip, LIBNET_DONT_RESOLVE), libnet_addr2name4(dst_ip, LIBNET_DONT_RESOLVE)); printf(" IP Layer: TTL: %d TOS: 0x%X ID: %d\n", ip_ttl, ip_tos, ip_id); printf(" TCP Layer: SrcPort: %d (%s) ", src_port, (servent = getservbyport(htons(src_port), "udp")) != NULL ? servent->s_name : "unknown"); printf("DstPort: %d (%s)\n", dst_port, (servent = getservbyport(htons(dst_port), "udp")) != NULL ? servent->s_name : "unknown"); printf(" TCP Layer: %s%s%s%s%s%s%s%s", (tcp_flags & TH_RES1) ? "1" : "*", (tcp_flags & TH_RES2) ? "2" : "*", (tcp_flags & TH_ACK) ? "A" : "*", (tcp_flags & TH_FIN) ? "F" : "*", (tcp_flags & TH_PUSH) ? "P" : "*", (tcp_flags & TH_RST) ? "R" : "*", (tcp_flags & TH_SYN) ? "S" : "*", (tcp_flags & TH_URG) ? "U" : "*"); printf(" Seq: 0x%lx Ack: 0x%lx Urg: 0x%x Win: 0x%d\n", tcp_seq, tcp_ack, ntohs(tcp_urg), tcp_win); printf(" App Layer: %ld byte payload\n", tcp_payload_l); } } libnet_destroy(libnet); goto pass; fail: if (opts[OPT_SRCETHER].set) { free(src_ether); } if (opts[OPT_DSTETHER].set) { free(dst_ether); } return(EXIT_FAILURE); pass: if (opts[OPT_SRCETHER].set) { free(src_ether); } if (opts[OPT_DSTETHER].set) { free(dst_ether); } return(EXIT_SUCCESS); }