1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2004-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation. You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 //--------------------------------------------------------------------------
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "telnet.h"
25
26 #include "detection/detection_engine.h"
27 #include "log/messages.h"
28 #include "profiler/profiler.h"
29 #include "protocols/packet.h"
30
31 #include "ft_main.h"
32 #include "ftp_print.h"
33 #include "ftpp_return_codes.h"
34 #include "ftpp_si.h"
35 #include "ftpp_ui_config.h"
36 #include "pp_telnet.h"
37 #include "telnet_module.h"
38
39 using namespace snort;
40
41 THREAD_LOCAL ProfileStats telnetPerfStats;
42 THREAD_LOCAL TelnetStats tnstats;
43
44 //-------------------------------------------------------------------------
45 // implementation
46 //-------------------------------------------------------------------------
47
TelnetCheckConfigs(SnortConfig *,void * pData)48 static int TelnetCheckConfigs(SnortConfig*, void* pData)
49 {
50 TELNET_PROTO_CONF* telnet_config = (TELNET_PROTO_CONF*)pData;
51
52 if ((telnet_config->ayt_threshold > 0) &&
53 !telnet_config->normalize)
54 {
55 ParseWarning(WARN_CONF, "telnet configuration check: using an "
56 "AreYouThere threshold requires telnet normalization to be "
57 "turned on.\n");
58 }
59 if ( telnet_config->detect_encrypted &&
60 !telnet_config->normalize)
61 {
62 ParseWarning(WARN_CONF, "telnet configuration check: checking for "
63 "encrypted traffic requires telnet normalization to be turned on.\n");
64 }
65
66 return 0;
67 }
68
SnortTelnet(TELNET_PROTO_CONF * telnet_config,TELNET_SESSION * Telnetsession,Packet * p,int iInspectMode)69 static int SnortTelnet(TELNET_PROTO_CONF* telnet_config, TELNET_SESSION* Telnetsession,
70 Packet* p, int iInspectMode)
71 {
72 Profile profile(telnetPerfStats);
73
74 if ( !Telnetsession )
75 return FTPP_NONFATAL_ERR;
76
77 if ( Telnetsession->encr_state &&
78 !Telnetsession->telnet_conf->check_encrypted_data )
79 return FTPP_SUCCESS;
80
81 if ( telnet_config->normalize )
82 {
83 DataBuffer& buf = DetectionEngine::get_alt_buffer(p);
84 int ret = normalize_telnet(Telnetsession, p, buf, iInspectMode,
85 FTPP_APPLY_TNC_ERASE_CMDS, false);
86
87 if ( ret == FTPP_SUCCESS || ret == FTPP_NORMALIZED )
88 do_detection(p);
89 }
90
91 else
92 {
93 do_detection(p);
94 }
95
96 return FTPP_SUCCESS;
97 }
98
snort_telnet(TELNET_PROTO_CONF * GlobalConf,Packet * p)99 static int snort_telnet(TELNET_PROTO_CONF* GlobalConf, Packet* p)
100 {
101 FTPP_SI_INPUT SiInput;
102 int iInspectMode = FTPP_SI_NO_MODE;
103 FTP_TELNET_SESSION* ft_ssn = nullptr;
104
105 /*
106 * Set up the FTPP_SI_INPUT pointer. This is what the session_inspection()
107 * routines use to determine client and server traffic. Plus, this makes
108 * the FTPTelnet library very independent from snort.
109 */
110 SetSiInput(&SiInput, p);
111
112 if (p->flow)
113 {
114 TelnetFlowData* fd = (TelnetFlowData*)
115 p->flow->get_flow_data(FtpFlowData::inspector_id);
116
117 ft_ssn = fd ? &fd->session.ft_ssn : nullptr;
118
119 if (ft_ssn != nullptr)
120 {
121 SiInput.pproto = ft_ssn->proto;
122
123 if (ft_ssn->proto == FTPP_SI_PROTO_TELNET)
124 {
125 if (SiInput.pdir != FTPP_SI_NO_MODE)
126 {
127 iInspectMode = SiInput.pdir;
128 }
129 else
130 {
131 if ( p->is_from_server() )
132 {
133 iInspectMode = FTPP_SI_SERVER_MODE;
134 }
135 else if ( p->is_from_client() )
136 {
137 iInspectMode = FTPP_SI_CLIENT_MODE;
138 }
139 }
140 }
141 else
142 {
143 assert(false);
144 p->flow->free_flow_data(FtpFlowData::inspector_id);
145 return 0;
146 }
147 }
148 }
149
150 if (GlobalConf == nullptr)
151 return 0;
152
153 if (ft_ssn == nullptr)
154 {
155 SiInput.pproto = FTPP_SI_PROTO_UNKNOWN;
156 iInspectMode = FTPP_SI_NO_MODE;
157
158 TelnetsessionInspection(p, GlobalConf, (TELNET_SESSION**)&ft_ssn, &SiInput, &iInspectMode);
159
160 if ( SiInput.pproto != FTPP_SI_PROTO_TELNET )
161 return FTPP_INVALID_PROTO;
162 }
163
164 if (ft_ssn != nullptr)
165 {
166 switch (SiInput.pproto)
167 {
168 case FTPP_SI_PROTO_TELNET:
169 return SnortTelnet(GlobalConf, (TELNET_SESSION*)ft_ssn, p, iInspectMode);
170 }
171 }
172
173 /* Uh, shouldn't get here */
174 return FTPP_INVALID_PROTO;
175 }
176
177 //-------------------------------------------------------------------------
178 // class stuff
179 //-------------------------------------------------------------------------
180
181 class Telnet : public Inspector
182 {
183 public:
184 Telnet(TELNET_PROTO_CONF*);
185 ~Telnet() override;
186
187 bool configure(SnortConfig*) override;
188 void show(const SnortConfig*) const override;
189 void eval(Packet*) override;
190
191 bool get_buf(InspectionBuffer::Type, Packet*, InspectionBuffer&) override;
192 void clear(Packet*) override;
193
194 private:
195 TELNET_PROTO_CONF* config;
196 };
197
Telnet(TELNET_PROTO_CONF * pc)198 Telnet::Telnet(TELNET_PROTO_CONF* pc)
199 {
200 config = pc;
201 }
202
~Telnet()203 Telnet::~Telnet()
204 {
205 if ( config )
206 delete config;
207 }
208
configure(SnortConfig * sc)209 bool Telnet::configure(SnortConfig* sc)
210 {
211 return !TelnetCheckConfigs(sc, config);
212 }
213
show(const SnortConfig *) const214 void Telnet::show(const SnortConfig*) const
215 {
216 if ( !config )
217 return;
218
219 ConfigLogger::log_value("ayt_attack_thresh", config->ayt_threshold);
220 ConfigLogger::log_flag("check_encrypted", config->detect_encrypted);
221 ConfigLogger::log_flag("encrypted_traffic", config->check_encrypted_data);
222 ConfigLogger::log_flag("normalize", config->normalize);
223 }
224
eval(Packet * p)225 void Telnet::eval(Packet* p)
226 {
227 // precondition - what we registered for
228 assert(p->has_tcp_data());
229
230 ++tnstats.total_packets;
231 snort_telnet(config, p);
232 }
233
get_buf(InspectionBuffer::Type ibt,Packet * p,InspectionBuffer & b)234 bool Telnet::get_buf(
235 InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
236 {
237 if ( ibt != InspectionBuffer::IBT_ALT )
238 return false;
239
240 b.data = get_telnet_buffer(p, b.len);
241
242 return (b.data != nullptr);
243 }
244
clear(Packet * p)245 void Telnet::clear(Packet* p)
246 {
247 reset_telnet_buffer(p);
248 }
249
250 //-------------------------------------------------------------------------
251 // api stuff
252 //-------------------------------------------------------------------------
253
mod_ctor()254 static Module* mod_ctor()
255 { return new TelnetModule; }
256
mod_dtor(Module * m)257 static void mod_dtor(Module* m)
258 { delete m; }
259
tn_init()260 static void tn_init()
261 {
262 TelnetFlowData::init();
263 }
264
tn_ctor(Module * m)265 static Inspector* tn_ctor(Module* m)
266 {
267 TelnetModule* mod = (TelnetModule*)m;
268 return new Telnet(mod->get_data());
269 }
270
tn_dtor(Inspector * p)271 static void tn_dtor(Inspector* p)
272 {
273 delete p;
274 }
275
276 // exported in ftp.cc
277 const InspectApi tn_api =
278 {
279 {
280 PT_INSPECTOR,
281 sizeof(InspectApi),
282 INSAPI_VERSION,
283 0,
284 API_RESERVED,
285 API_OPTIONS,
286 TEL_NAME,
287 TEL_HELP,
288 mod_ctor,
289 mod_dtor
290 },
291 IT_SERVICE,
292 PROTO_BIT__PDU,
293 nullptr, // buffers
294 "telnet",
295 tn_init,
296 nullptr, // pterm
297 nullptr, // tinit
298 nullptr, // tterm
299 tn_ctor,
300 tn_dtor,
301 nullptr, // ssn
302 nullptr // reset
303 };
304
305