1 /*
2     ettercap -- TCP decoder module
3 
4     Copyright (C) ALoR & NaGA
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include <ec.h>
23 #include <ec_decode.h>
24 #include <ec_fingerprint.h>
25 #include <ec_checksum.h>
26 #include <ec_session.h>
27 #include <ec_session_tcp.h>
28 #include <ec_inject.h>
29 
30 
31 /* globals */
32 
33 struct tcp_header {
34    u_int16  sport;      /* source port */
35    u_int16  dport;      /* destination port */
36    u_int32  seq;        /* sequence number */
37    u_int32  ack;        /* acknowledgement number */
38 #ifndef WORDS_BIGENDIAN
39    u_int8   x2:4;       /* (unused) */
40    u_int8   off:4;      /* data offset */
41 #else
42    u_int8   off:4;      /* data offset */
43    u_int8   x2:4;       /* (unused) */
44 #endif
45    u_int8   flags;
46 #define TH_FIN  0x01
47 #define TH_SYN  0x02
48 #define TH_RST  0x04
49 #define TH_PSH  0x08
50 #define TH_ACK  0x10
51 #define TH_URG  0x20
52 #define TH_ECE  0x40    /* rfc 2481/3168 */
53 #define TH_CWR  0x80    /* rfc 2481/3168 */
54    u_int16  win;        /* window */
55    u_int16  csum;       /* checksum */
56    u_int16  urp;        /* urgent pointer */
57 };
58 
59 /* tcp options */
60 #define TCPOPT_EOL              0
61 #define TCPOPT_NOP              1
62 #define TCPOPT_MAXSEG           2
63 #define TCPOPT_WSCALE           3
64 #define TCPOPT_SACKOK           4
65 #define TCPOPT_TIMESTAMP        8
66 
67 
68 /* Session identifier
69  * It has to be even-lengthed for session hash matching */
70 struct tcp_ident {
71    u_int32 magic;
72       #define TCP_MAGIC  0x0400e77e
73    struct ip_addr L3_src;
74    struct ip_addr L3_dst;
75    u_int16 L4_src;
76    u_int16 L4_dst;
77 };
78 
79 #define TCP_IDENT_LEN sizeof(struct tcp_ident)
80 
81 
82 /* protos */
83 
84 FUNC_DECODER(decode_tcp);
85 FUNC_INJECTOR(inject_tcp);
86 void tcp_init(void);
87 int tcp_match(void *id_sess, void *id_curr);
88 void tcp_create_session(struct ec_session **s, struct packet_object *po);
89 
90 /*******************************************/
91 
92 /*
93  * this function is the initializer.
94  * it adds the entry in the table of registered decoder
95  */
96 
tcp_init(void)97 void __init tcp_init(void)
98 {
99    add_decoder(PROTO_LAYER, NL_TYPE_TCP, decode_tcp);
100    add_injector(CHAIN_ENTRY, NL_TYPE_TCP, inject_tcp);
101 }
102 
103 
FUNC_DECODER(decode_tcp)104 FUNC_DECODER(decode_tcp)
105 {
106    FUNC_DECODER_PTR(next_decoder);
107    struct tcp_header *tcp;
108    u_char *opt_start, *opt_end;
109    struct ec_session *s = NULL;
110    void *ident = NULL;
111    struct tcp_status *status = NULL;
112    int direction = 0;
113    u_int16 sum;
114 
115    tcp = (struct tcp_header *)DECODE_DATA;
116 
117    opt_start = (u_char *)(tcp + 1);
118    opt_end = (u_char*)tcp + tcp->off * 4;
119 
120    DECODED_LEN = (u_int32)(tcp->off * 4);
121 
122    /* source and dest port */
123    PACKET->L4.src = tcp->sport;
124    PACKET->L4.dst = tcp->dport;
125 
126    PACKET->L4.len = DECODED_LEN;
127    PACKET->L4.header = (u_char *)DECODE_DATA;
128 
129    if (opt_start < opt_end) {
130       PACKET->L4.options = opt_start;
131       PACKET->L4.optlen = opt_end - opt_start;
132    } else {
133       PACKET->L4.options = NULL;
134       PACKET->L4.optlen = 0;
135    }
136 
137    /* this is TCP */
138    PACKET->L4.proto = NL_TYPE_TCP;
139 
140    /* save the flags */
141    PACKET->L4.flags = tcp->flags;
142 
143    /* save the seq number */
144    PACKET->L4.seq = tcp->seq;
145    PACKET->L4.ack = tcp->ack;
146 
147    /* set up the data pointers */
148    PACKET->DATA.data = opt_end;
149    if (PACKET->L3.payload_len < (u_int32)DECODED_LEN)
150       return NULL;
151    PACKET->DATA.len = PACKET->L3.payload_len - DECODED_LEN;
152 
153    /* create the buffer to be displayed */
154    packet_disp_data(PACKET, PACKET->DATA.data, PACKET->DATA.len);
155 
156    /*
157     * if the checsum is wrong, don't parse it (avoid ettercap spotting)
158     * the checksum is should be CSUM_RESULT and not equal to tcp->csum ;)
159     *
160     * don't perform the check in unoffensive mode
161     */
162    if (EC_GBL_CONF->checksum_check) {
163       if (!EC_GBL_OPTIONS->unoffensive && (sum = L4_checksum(PACKET)) != CSUM_RESULT) {
164          char tmp[MAX_ASCII_ADDR_LEN];
165 #if defined(OS_DARWIN) || defined (OS_WINDOWS) || defined(OS_LINUX)
166          /*
167           * XXX - hugly hack here !  Mac OS X really sux
168           *
169           * Packets transmitted on interfaces with TCP checksum offloading
170           * don't have valid checksums as presented to the machine's packet-capture
171           * mechanism, as those packets are wrapped around internally rather
172           * than being captured after passing through the network interface, as
173           * the OS doesn't bother computing the checksum and adding it to the packet
174           * it leaves that up to the network interface.
175           *                (taken from a bug report by Guy Harris - libpcap engineer)
176           *
177           * For Windows at least, TCP checksum off-loading can be disabled with a
178           * registry setting.
179           *
180           * Same for Linux, but sometimes even ethtool doesn't turn this feature off.
181           *
182           * if the source is the ettercap host, don't display the message
183           */
184          if (ip_addr_is_ours(&PACKET->L3.src) == E_FOUND)
185             return NULL;
186 #endif
187          if (EC_GBL_CONF->checksum_warning)
188             USER_MSG("Invalid TCP packet from %s:%d : csum [%#x] should be (%#x)\n", ip_addr_ntoa(&PACKET->L3.src, tmp),
189                                     ntohs(tcp->sport), ntohs(tcp->csum), checksum_shouldbe(tcp->csum, sum));
190          return NULL;
191       }
192    }
193 
194    /*
195     * complete the passive fingerprint (started at IP layer)
196     * we are interested only in SYN or SYN+ACK packets
197     * else we can destroy the fingerprint
198     */
199    if ( tcp->flags & TH_SYN ) {
200 
201       fingerprint_push(PACKET->PASSIVE.fingerprint, FINGER_WINDOW, ntohs(tcp->win));
202       fingerprint_push(PACKET->PASSIVE.fingerprint, FINGER_TCPFLAG, (tcp->flags & TH_ACK) ? 1 : 0);
203       /* this is added to the len of ip header (automatic) */
204       fingerprint_push(PACKET->PASSIVE.fingerprint, FINGER_LT, tcp->off * 4);
205 
206       while (opt_start < opt_end) {
207          switch (*opt_start) {
208             case TCPOPT_EOL:
209                /* end option EXIT */
210                opt_start = opt_end;
211                break;
212             case TCPOPT_NOP:
213                fingerprint_push(PACKET->PASSIVE.fingerprint, FINGER_NOP, 1);
214                opt_start++;
215                break;
216             case TCPOPT_SACKOK:
217                fingerprint_push(PACKET->PASSIVE.fingerprint, FINGER_SACK, 1);
218                opt_start += 2;
219                break;
220             case TCPOPT_MAXSEG:
221                opt_start += 2;
222                fingerprint_push(PACKET->PASSIVE.fingerprint, FINGER_MSS, pntos(opt_start));
223                opt_start += 2;
224                break;
225             case TCPOPT_WSCALE:
226                opt_start += 2;
227                fingerprint_push(PACKET->PASSIVE.fingerprint, FINGER_WS, *opt_start);
228                opt_start++;
229                break;
230             case TCPOPT_TIMESTAMP:
231                fingerprint_push(PACKET->PASSIVE.fingerprint, FINGER_TIMESTAMP, 1);
232                opt_start++;
233                if ((*opt_start) > 0)
234                    opt_start += ((*opt_start) - 1);
235                break;
236             default:
237                opt_start++;
238                if (*opt_start > 0)
239                   opt_start += (*opt_start - 1);
240                break;
241          }
242       }
243 
244    } else {
245       /* not an interesting packet */
246       memset(PACKET->PASSIVE.fingerprint, 0, FINGER_LEN);
247    }
248 
249    /* HOOK POINT: HOOK_PACKET_TCP */
250    hook_point(HOOK_PACKET_TCP, po);
251 
252    /* don't save the sessions in unoffensive mode */
253    /* don't save sessions if no filters chain are defined */
254    if (EC_GBL_FILTERS && !EC_GBL_OPTIONS->unoffensive && !EC_GBL_OPTIONS->read) {
255 
256       /* Find or create the correct session */
257       tcp_create_ident(&ident, PACKET);
258       if (session_get(&s, ident, TCP_IDENT_LEN) == -E_NOTFOUND) {
259          tcp_create_session(&s, PACKET);
260          session_put(s);
261       }
262 
263       /* Trace the sessions for injectors */
264       SESSION_PASSTHRU(s, PACKET);
265 
266       /* Select right comunication way */
267       direction = tcp_find_direction(s->ident, ident);
268       SAFE_FREE(ident);
269 
270       /* Record last packet's seq */
271       status = (struct tcp_status *)s->data;
272       status->way[direction].last_seq = ntohl(tcp->seq) + PACKET->DATA.len;
273       if ( tcp->flags & TH_ACK )
274          status->way[direction].last_ack = ntohl(tcp->ack);
275 
276       /* SYN counts as one byte */
277       if ( tcp->flags & TH_SYN )
278          status->way[direction].last_seq++;
279 
280       /* Take trace of the RST flag (to block injection) */
281       if ( tcp->flags & TH_RST ) {
282          status->way[direction].injectable |= INJ_FIN;
283          status->way[!direction].injectable |= INJ_FIN;
284       }
285 
286       /* Take trace if this side of connection is mitm'd */
287       if (PACKET->flags & PO_FORWARDABLE)
288          status->way[direction].injectable |= INJ_FWD;
289       else if (status->way[direction].injectable & INJ_FWD)
290          status->way[direction].injectable ^= INJ_FWD;
291    }
292 
293    /* get the next decoder */
294    next_decoder = get_decoder(APP_LAYER, PL_DEFAULT);
295    EXECUTE_DECODER(next_decoder);
296 
297    /* don't save the sessions in unoffensive mode */
298    if (EC_GBL_FILTERS && !EC_GBL_OPTIONS->unoffensive && !EC_GBL_OPTIONS->read) {
299 
300       /*
301        * Take trace of the FIN flag (to block injection)
302        * It's here to permit some strange tricks with filters.
303        */
304       if ( tcp->flags & TH_FIN )
305          status->way[direction].injectable |= INJ_FIN;
306 
307       /*
308        * Modification checks and adjustments.
309        * - tcp->seq and tcp->ack accoridng to injected/dropped bytes
310        * - seq_adj according to PACKET->delta for modifications
311        *   or the whole payload for dropped packets.
312        * Don't adjust sequence if not forwardable.
313        */
314 
315       /* XXX [...] over TCP encapsulation not supported yet:
316        * upper layer may modify L3 structure
317        */
318 
319       if ((PACKET->flags & PO_DROPPED) && (PACKET->flags & PO_FORWARDABLE))
320          status->way[direction].seq_adj += PACKET->DATA.delta;
321       else if (((PACKET->flags & PO_MODIFIED) ||
322                (status->way[direction].seq_adj != 0) ||
323                (status->way[!direction].seq_adj != 0)) &&
324                (PACKET->flags & PO_FORWARDABLE)) {
325 
326          /* adjust with the previously injected/dropped seq/ack */
327          ORDER_ADD_LONG(tcp->seq, status->way[direction].seq_adj);
328          ORDER_ADD_LONG(tcp->ack, -status->way[!direction].seq_adj);
329 
330          /* and now save the new delta */
331          status->way[direction].seq_adj += PACKET->DATA.delta;
332 
333          /* Recalculate checksum */
334          tcp->csum = CSUM_INIT;
335          tcp->csum = L4_checksum(PACKET);
336       }
337    }
338    return NULL;
339 }
340 
341 /*******************************************/
342 
FUNC_INJECTOR(inject_tcp)343 FUNC_INJECTOR(inject_tcp)
344 {
345    struct ec_session *s = NULL;
346    void *ident = NULL;
347    struct tcp_status *status;
348    int direction;
349    struct tcp_header *tcph;
350    u_char *tcp_payload;
351    u_int32 magic;
352 
353    /* Find the correct session */
354    tcp_create_ident(&ident, PACKET);
355    if (session_get(&s, ident, TCP_IDENT_LEN) == -E_NOTFOUND) {
356       SAFE_FREE(ident);
357       return -E_NOTFOUND;
358    }
359 
360    /* Rember where the payload has to start */
361    tcp_payload = PACKET->packet;
362 
363    /* Allocate stack for tcp header */
364    PACKET->packet -= sizeof(struct tcp_header);
365 
366    /* Create the tcp header */
367    tcph = (struct tcp_header *)PACKET->packet;
368 
369    tcph->sport = PACKET->L4.src;
370    tcph->dport = PACKET->L4.dst;
371    tcph->x2    = 0;
372    tcph->off   = 5;
373    tcph->win   = htons(32120);
374    tcph->csum  = CSUM_INIT;
375    tcph->urp   = 0;
376    tcph->flags = TH_PSH;
377 
378    /* Take the rest of the data from the sessions */
379    status = (struct tcp_status *)s->data;
380    direction = tcp_find_direction(s->ident, ident);
381    SAFE_FREE(ident);
382 
383    /* Is this an injectable connection? */
384    if ((status->way[direction].injectable & INJ_FIN) || !(status->way[direction].injectable & INJ_FWD) || !(status->way[!direction].injectable & INJ_FWD))
385       return -E_NOTHANDLED;
386 
387    tcph->seq = htonl(status->way[direction].last_seq + status->way[direction].seq_adj);
388    tcph->ack = htonl(status->way[direction].last_ack - status->way[!direction].seq_adj);
389 
390    if (status->way[direction].last_ack!=0)
391       tcph->flags |= TH_ACK;
392 
393    /* Prepare data for next injector */
394    PACKET->session = s->prev_session;
395    LENGTH += sizeof(struct tcp_header);
396    memcpy(&magic, s->prev_session->ident, 4);
397 
398    /* Go deeper into injectors chain */
399    EXECUTE_INJECTOR(CHAIN_LINKED, magic);
400 
401    /*
402     * Attach the data (LENGTH was adjusted by LINKED injectors).
403     * Set LENGTH to injectable data len.
404     */
405    LENGTH = EC_GBL_IFACE->mtu - LENGTH;
406    if (LENGTH > PACKET->DATA.inject_len)
407       LENGTH = PACKET->DATA.inject_len;
408    memcpy(tcp_payload, PACKET->DATA.inject, LENGTH);
409 
410    /* Update inject counter into the session */
411    status->way[direction].seq_adj += LENGTH;
412 
413    /* Calculate checksum */
414    PACKET->L4.header = (u_char *)tcph;
415    PACKET->L4.len = sizeof(struct tcp_header);
416    PACKET->DATA.len = LENGTH;
417    tcph->csum = L4_checksum(PACKET);
418 
419    return E_SUCCESS;
420 }
421 
422 /*******************************************/
423 
424 /* Sessions' stuff for tcp packets */
425 
426 
427 /*
428  * create the ident for a session
429  */
430 
tcp_create_ident(void ** i,struct packet_object * po)431 size_t tcp_create_ident(void **i, struct packet_object *po)
432 {
433    struct tcp_ident *ident;
434 
435    /* allocate the ident for that session */
436    SAFE_CALLOC(ident, 1, sizeof(struct tcp_ident));
437 
438    /* the magic */
439    ident->magic = TCP_MAGIC;
440 
441    /* prepare the ident */
442    memcpy(&ident->L3_src, &po->L3.src, sizeof(struct ip_addr));
443    memcpy(&ident->L3_dst, &po->L3.dst, sizeof(struct ip_addr));
444 
445    ident->L4_src = po->L4.src;
446    ident->L4_dst = po->L4.dst;
447 
448    /* return the ident */
449    *i = ident;
450 
451    /* return the length of the ident */
452    return sizeof(struct tcp_ident);
453 }
454 
455 
456 /*
457  * compare two session ident
458  *
459  * return 1 if it matches
460  */
461 
tcp_match(void * id_sess,void * id_curr)462 int tcp_match(void *id_sess, void *id_curr)
463 {
464    struct tcp_ident *ids = id_sess;
465    struct tcp_ident *id = id_curr;
466 
467    /* sanity check */
468    BUG_IF(ids == NULL);
469    BUG_IF(id == NULL);
470 
471    /*
472     * is this ident from our level ?
473     * check the magic !
474     */
475    if (ids->magic != id->magic)
476       return 0;
477 
478    /* from source to dest */
479    if (ids->L4_src == id->L4_src &&
480        ids->L4_dst == id->L4_dst &&
481        !ip_addr_cmp(&ids->L3_src, &id->L3_src) &&
482        !ip_addr_cmp(&ids->L3_dst, &id->L3_dst) )
483       return 1;
484 
485    /* from dest to source */
486    if (ids->L4_src == id->L4_dst &&
487        ids->L4_dst == id->L4_src &&
488        !ip_addr_cmp(&ids->L3_src, &id->L3_dst) &&
489        !ip_addr_cmp(&ids->L3_dst, &id->L3_src) )
490       return 1;
491 
492    return 0;
493 }
494 
495 
496 /*
497  * prepare the ident and the pointer to match function
498  * for a dissector.
499  */
500 
tcp_create_session(struct ec_session ** s,struct packet_object * po)501 void tcp_create_session(struct ec_session **s, struct packet_object *po)
502 {
503    void *ident;
504 
505    DEBUG_MSG("tcp_create_session");
506 
507    /* allocate the session */
508    SAFE_CALLOC(*s, 1, sizeof(struct ec_session));
509 
510    /* create the ident */
511    (*s)->ident_len = tcp_create_ident(&ident, po);
512 
513    /* link to the session */
514    (*s)->ident = ident;
515 
516    /* the matching function */
517    (*s)->match = &tcp_match;
518 
519    /* alloca of data elements */
520    SAFE_CALLOC((*s)->data, 1, sizeof(struct tcp_status));
521 }
522 
523 /*
524  * Find right comunication way for session data.
525  * First array data is relative to the direction first caught.
526  */
tcp_find_direction(void * ids,void * id)527 int tcp_find_direction(void *ids, void *id)
528 {
529    if (memcmp(ids, id, TCP_IDENT_LEN))
530       return 1;
531 
532    return 0;
533 }
534 
535 /* EOF */
536 
537 // vim:ts=3:expandtab
538 
539