1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2002-2013 Sourcefire, Inc.
4 // Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
5 //
6 // This program is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU General Public License Version 2 as published
8 // by the Free Software Foundation.  You may not use, modify or distribute
9 // this program under any other version of the GNU General Public License.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 //--------------------------------------------------------------------------
20 
21 
22 // Telnet sessions can contain telnet negotiation strings that can disrupt
23 // pattern matching.  This plugin detects negotiation strings in stream and
24 // normalizes them much like the http_inspect normalizes encoded URLs.
25 //
26 // official registry of options
27 // http://www.iana.org/assignments/telnet-options
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "pp_telnet.h"
34 
35 #include "detection/detection_engine.h"
36 #include "detection/detection_util.h"
37 #include "protocols/packet.h"
38 #include "stream/stream.h"
39 
40 #include "ftpp_return_codes.h"
41 #include "telnet_module.h"
42 
43 using namespace snort;
44 
45 #define NUL 0x00
46 #define CR 0x0d
47 #define LF 0x0a
48 
49 /* This is the allowable number of 8 bit characters,
50  * ie, non-ASCII, before we declare this packet/stream
51  * as encrypted.
52  */
53 #define CONSECUTIVE_8BIT_THRESHOLD 3
54 
reset_telnet_buffer(Packet * p)55 void reset_telnet_buffer(Packet* p)
56 {
57     DetectionEngine::get_alt_buffer(p).len = 0;
58 }
59 
get_telnet_buffer(Packet * p,unsigned & len)60 const uint8_t* get_telnet_buffer(Packet* p, unsigned& len)
61 {
62     const DataBuffer& buf = DetectionEngine::get_alt_buffer(p);
63     len = buf.len;
64     return len ? buf.data : nullptr;
65 }
66 
normalize_telnet(TELNET_SESSION * tnssn,Packet * p,DataBuffer & buf,int iMode,char ignoreEraseCmds,bool on_ftp_channel)67 int normalize_telnet(
68     TELNET_SESSION* tnssn, Packet* p, DataBuffer& buf,
69     int iMode, char ignoreEraseCmds, bool on_ftp_channel)
70 {
71     int ret = FTPP_NORMALIZED;
72     const unsigned char* read_ptr, * sb_start = nullptr;
73     unsigned char* write_ptr;
74     const unsigned char* end;
75     int normalization_required = 0;
76     int consec_8bit_chars = 0;
77 
78     const unsigned char* start = buf.data;
79     buf.len = 0;
80 
81     /* Telnet commands are handled in here.
82     * They can be 2 bytes long -- ie, IAC NOP, IAC AYT, etc.
83     * Sub-negotiation strings are at least 4 bytes, IAC SB x IAC SE */
84     if (p->dsize < 2)
85     {
86         if (tnssn && iMode == FTPP_SI_CLIENT_MODE)
87             tnssn->consec_ayt = 0;
88         return FTPP_SUCCESS;
89     }
90 
91     /* setup the pointers */
92     read_ptr = p->data;
93     end = p->data + p->dsize;
94 
95     /* look to see if we have any telnet negotiation codes in the data */
96     while (!normalization_required && (read_ptr < end))
97     {
98         /* look for the start of a negotiation string */
99         if (*read_ptr == (unsigned char)TNC_IAC)
100         {
101             /* set a flag for stage 2 normalization */
102             normalization_required = 1;
103         }
104         else
105         {
106             if ( on_ftp_channel )
107             {
108                 return FTPP_SUCCESS;
109             }
110             /* Okay, it wasn't an IAC also its a midstream pickup */
111             if (*read_ptr > 0x7F && Stream::is_midstream(p->flow))
112             {
113                 consec_8bit_chars++;
114                 if (consec_8bit_chars > CONSECUTIVE_8BIT_THRESHOLD)
115                 {
116                     /* This data stream had a series of 8 bit characters.
117                      * It is very likely encrypted.  This handles the case
118                      * where we either missed the option negotiation, or
119                      * lost state of an already encrypted telnet session.
120                      */
121                     if (tnssn)
122                     {
123                         tnssn->encr_state = 1;
124                         DetectionEngine::queue_event(GID_TELNET, TELNET_ENCRYPTED);
125 
126                         if (!tnssn->telnet_conf->check_encrypted_data)
127                         {
128                             /* Mark this session & packet as one to ignore */
129                             Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
130                             /* No point to do further normalization */
131                             return FTPP_ALERT;
132                         }
133                     }
134                     break;
135                 }
136             }
137             else
138             {
139                 consec_8bit_chars = 0;
140             }
141         }
142 
143         read_ptr++;
144     }
145 
146     if (!normalization_required)
147     {
148         if (tnssn && iMode == FTPP_SI_CLIENT_MODE)
149             tnssn->consec_ayt = 0;
150         return FTPP_SUCCESS;
151     }
152 
153     /*
154     * if we found telnet negotiation strings OR backspace characters,
155     * we're going to have to normalize the data
156     *
157     * Note that this is always ( now: 2002-08-12 ) done to a
158     * alternative data buffer.
159     */
160     /* rewind the data stream to p->data */
161     read_ptr = p->data;
162 
163     /* setup for overwriting the negotiation strings with
164     * the follow-on data
165     */
166     write_ptr = (unsigned char*)buf.data;
167 
168     /* walk thru the remainder of the packet */
169     while ((read_ptr < end) &&
170         (write_ptr < ((unsigned char*)buf.data) + sizeof(buf.data)))
171     {
172         /* if the following byte isn't a subnegotiation initialization */
173         if (((read_ptr + 1) < end) &&
174             (*read_ptr == (unsigned char)TNC_IAC) &&
175             (*(read_ptr + 1) != (unsigned char)TNC_SB))
176         {
177             int saw_ayt = 0;
178 
179             /* NOPs are two bytes long */
180             switch (*((const unsigned char*)(read_ptr + 1)))
181             {
182             case TNC_NOP:
183                 read_ptr += 2;
184                 break;
185             case TNC_EAC:
186                 read_ptr += 2;
187                 /* wind it back a character? */
188                 if (ignoreEraseCmds == FTPP_APPLY_TNC_ERASE_CMDS)
189                 {
190                     if (write_ptr  > start)
191                     {
192                         write_ptr--;
193                         buf.len--;
194                     }
195                 }
196                 break;
197             case TNC_EAL:
198                 read_ptr += 2;
199                 /* wind it back a line? */
200                 if (ignoreEraseCmds == FTPP_APPLY_TNC_ERASE_CMDS)
201                 {
202                     /* Go back to previous CR null or CR LF? */
203                     while (write_ptr > start)
204                     {
205                         /* Go to previous char */
206                         write_ptr--;
207                         buf.len--;
208 
209                         if ((*write_ptr == CR) &&
210                             ((*(write_ptr+1) == NUL) || (*(write_ptr+1) == LF)) )
211                         {
212                             /* Okay, found the CR NUL or CR LF, move it
213                              * forward past those two -- that is the
214                              * beginning of this line
215                              */
216                             write_ptr+=2;
217                             buf.len+=2;
218                             break;
219                         }
220                     }
221                 }
222                 break;
223             /* These are two bytes long */
224             case TNC_AYT:
225                 saw_ayt = 1;
226                 if (tnssn)
227                 {
228                     tnssn->consec_ayt++;
229                     if ((tnssn->telnet_conf->ayt_threshold > 0) &&
230                         (tnssn->consec_ayt >
231                         tnssn->telnet_conf->ayt_threshold))
232                     {
233                         /* Alert on consecutive AYT commands */
234                         DetectionEngine::queue_event(GID_TELNET, TELNET_AYT_OVERFLOW);
235                         tnssn->consec_ayt = 0;
236                         return FTPP_ALERT;
237                     }
238                 }
239             /* Fall through */
240             case TNC_BRK:
241             case TNC_DM:
242             case TNC_IP:
243             case TNC_AO:
244             case TNC_GA:
245 #ifdef RFC1184
246             case TNC_EOF:
247             case TNC_SUSP:
248             case TNC_ABOR:
249 #endif
250 #ifdef RFC885
251             case TNC_EOR:
252 #endif
253                 read_ptr += 2;
254                 break;
255             case TNC_SE:
256                 /* Uh, what the heck is a Subnegotiation-end
257                  * doing here without SB?.  could generate an alert.
258                  * Will just normalize it out since we may have
259                  * processed the SB in a previous packet.
260                  */
261                 read_ptr += 2;
262                 break;
263             case TNC_IAC:
264                 /* IAC IAC -- means the IAC character (0xff) should be
265                 * in the data stream since it was escaped */
266                 read_ptr++; /* skip past the first IAC */
267                 *write_ptr++ = *read_ptr++;
268                 buf.len++;
269                 break;
270             case TNC_WILL:
271             case TNC_WONT:
272             case TNC_DO:
273             case TNC_DONT:
274                 read_ptr += 3;
275                 break;
276             default:
277                 /* move the read ptr up 2 bytes */
278                 read_ptr += 2;
279             }
280             /* If not an AYT, reset it */
281             if (!saw_ayt)
282             {
283                 if (tnssn && iMode == FTPP_SI_CLIENT_MODE)
284                     tnssn->consec_ayt = 0;
285             }
286         }
287         /* check for subnegotiation */
288         else if (((read_ptr + 1) < end) &&
289             (*read_ptr == (unsigned char)TNC_IAC) &&
290             (*(read_ptr+1) == (unsigned char)TNC_SB))
291         {
292             sb_start = read_ptr;
293 
294             switch (*(read_ptr+2))
295             {
296             case 0x26: /* Encryption -- RFC 2946 */
297                 /* printf("Telnet: Saw SB for Encryption\n"); */
298                 read_ptr += 3;
299                 switch (*read_ptr)
300                 {
301 #ifdef TRACK_ENCRYPTION_NEGOTIATION
302                 case 0x00:
303                     /* Client sending the Encryption IS marker
304                      * followed by address. */
305                 {
306                     read_ptr++;
307                     if (*read_ptr != 0x00)
308                     /* Encryption type is not null */
309                     {
310                         /* printf("Encryption being negotiated by
311                          * telnet client\n"); */
312                     }
313                 }
314                 break;
315 #endif
316                 case 0x03:
317                     /* Client sending the Encryption START marker
318                      * followed by address. */
319                 {
320                     read_ptr++;
321                     /* printf("Encryption started by telnet client\n"); */
322                     if (tnssn)
323                     {
324                         tnssn->encr_state = 1;
325                         DetectionEngine::queue_event(GID_TELNET, TELNET_ENCRYPTED);
326 
327                         if (!tnssn->telnet_conf->check_encrypted_data)
328                         {
329                             /* Mark this session & packet as one to ignore */
330                             Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
331                             /* No point to do further normalization */
332                             return FTPP_ALERT;
333                         }
334                     }
335                 }
336                 break;
337                 }
338                 break;
339             }
340 
341             /* find the end of the subneg -- this handles when there are
342              * embedded IAC IACs within a sub negotiation.  Just looking
343              * for the TNC_SE could cause problems.  Similarly, just looking
344              * for the TNC_IAC could end it too early. */
345             while (read_ptr < end)
346             {
347                 if ((*read_ptr == (unsigned char)TNC_IAC) &&
348                     (*(read_ptr+1) == (unsigned char)TNC_SE))
349                 {
350                     sb_start = nullptr;
351                     break;
352                 }
353                 read_ptr++;
354             }
355 
356             if (sb_start)
357             {
358                 /* Didn't find the IAC SE.  Normalize out the IAC SB
359                  * and restart from there. Presumption is this is
360                  * just someone trying to fool us, since we usually
361                  * see the entire IAC SB ... IAC SE in one packet. */
362                 read_ptr = sb_start+2;
363                 if (!tnssn)
364                 {
365                     /* Its an FTP session */
366                     ret = FTPP_ALERT;
367                 }
368                 else
369                 {
370                     /* Alert on SB without SE */
371                     DetectionEngine::queue_event(GID_TELNET, TELNET_SB_NO_SE);
372                     ret = FTPP_ALERT;
373                 }
374 
375                 continue;
376             }
377 
378             /* Okay, found the IAC SE -- move past it */
379             if (read_ptr < end)
380             {
381                 read_ptr += 2;
382             }
383 
384             if (tnssn && iMode == FTPP_SI_CLIENT_MODE)
385                 tnssn->consec_ayt = 0;
386         }
387         else
388         {
389             /* overwrite the negotiation bytes with the follow-on bytes */
390             switch (*((const unsigned char*)(read_ptr)))
391             {
392             case 0x7F: /* Delete */
393             case 0x08: /* Backspace/Ctrl-H */
394                 /* wind it back a character */
395                 if (write_ptr > start)
396                 {
397                     write_ptr--;
398                     buf.len--;
399                 }
400                 read_ptr++;
401                 break;
402             default:
403                 *write_ptr++ = *read_ptr++;
404                 buf.len++;
405                 break;
406             }
407 
408             if (tnssn && iMode == FTPP_SI_CLIENT_MODE)
409                 tnssn->consec_ayt = 0;
410         }
411     }
412 
413     return ret;
414 }
415 
416