]> git.ipfire.org Git - thirdparty/snort3.git/blob - src/network_inspectors/appid/client_plugins/client_app_tns.cc
8ee79c11c4399155527d69ae21e62473b363711c
[thirdparty/snort3.git] / src / network_inspectors / appid / client_plugins / client_app_tns.cc
1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2005-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 // client_app_tns.cc author Sourcefire Inc.
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "client_app_tns.h"
27
28 #include "app_info_table.h"
29 #include "application_ids.h"
30
31 static const char TNS_BANNER[] = "\000\000";
32 #define TNS_BANNER_LEN (sizeof(TNS_BANNER)-1)
33
34 #define TNS_TYPE_CONNECT 1
35 #define TNS_TYPE_ACCEPT 2
36 #define TNS_TYPE_ACK 3
37 #define TNS_TYPE_REFUSE 4
38 #define TNS_TYPE_REDIRECT 5
39 #define TNS_TYPE_DATA 6
40 #define TNS_TYPE_NULL 7
41 #define TNS_TYPE_ABORT 9
42 #define TNS_TYPE_RESEND 11
43 #define TNS_TYPE_MARKER 12
44 #define TNS_TYPE_ATTENTION 13
45 #define TNS_TYPE_CONTROL 14
46 #define TNS_TYPE_MAX 19
47
48 #define CONNECT_VERSION_OFFSET 8
49 #define CONNECT_DATA_OFFSET 26
50
51 #define USER_STRING "user="
52 #define MAX_USER_POS ((int)sizeof(USER_STRING) - 2)
53
54 enum TNSState
55 {
56 TNS_STATE_MESSAGE_LEN = 0,
57 TNS_STATE_MESSAGE_CHECKSUM,
58 TNS_STATE_MESSAGE,
59 TNS_STATE_MESSAGE_RES,
60 TNS_STATE_MESSAGE_HD_CHECKSUM,
61 TNS_STATE_MESSAGE_DATA,
62 TNS_STATE_MESSAGE_CONNECT,
63 TNS_STATE_MESSAGE_CONNECT_OFFSET_DC,
64 TNS_STATE_MESSAGE_CONNECT_OFFSET,
65 TNS_STATE_MESSAGE_CONNECT_PREDATA,
66 TNS_STATE_MESSAGE_CONNECT_DATA,
67 TNS_STATE_COLLECT_USER
68 };
69
70 struct ClientTNSData
71 {
72 TNSState state;
73 unsigned stringlen;
74 unsigned offsetlen;
75 unsigned pos;
76 unsigned message;
77 union
78 {
79 uint16_t len;
80 uint8_t raw_len[2];
81 } l;
82 const char* version;
83 uint8_t* data;
84 };
85
86 #pragma pack(1)
87 struct ClientTNSMsg
88 {
89 uint16_t len;
90 uint16_t checksum;
91 uint8_t msg;
92 uint8_t res;
93 uint16_t hdchecksum;
94 uint8_t data;
95 };
96 #pragma pack()
97
98 TnsClientDetector::TnsClientDetector(ClientDiscovery* cdm)
99 {
100 handler = cdm;
101 name = "TNS";
102 proto = IpProtocol::TCP;
103 minimum_matches = 1;
104 provides_user = true;
105
106 tcp_patterns =
107 {
108 { (const uint8_t*)TNS_BANNER, TNS_BANNER_LEN, 2, 0, APP_ID_ORACLE_DATABASE },
109 };
110
111 appid_registry =
112 {
113 { APP_ID_ORACLE_DATABASE, APPINFO_FLAG_CLIENT_ADDITIONAL | APPINFO_FLAG_CLIENT_USER }
114 };
115
116 handler->register_detector(name, this, proto);
117 }
118
119
120 static int reset_flow_data(ClientTNSData* fd)
121 {
122 memset(fd, '\0', sizeof(ClientTNSData));
123 fd->state = TNS_STATE_MESSAGE_LEN;
124 return APPID_EINVALID;
125 }
126
127 #define TNS_MAX_INFO_SIZE 63
128 int TnsClientDetector::validate(AppIdDiscoveryArgs& args)
129 {
130 char username[TNS_MAX_INFO_SIZE + 1];
131 ClientTNSData* fd;
132 uint16_t offset;
133 int user_pos = 0;
134 int user_size = 0;
135 uint16_t user_start = 0;
136 uint16_t user_end = 0;
137
138 if (args.dir != APP_ID_FROM_INITIATOR)
139 return APPID_INPROCESS;
140
141 fd = (ClientTNSData*)data_get(args.asd);
142 if (!fd)
143 {
144 fd = (ClientTNSData*)snort_calloc(sizeof(ClientTNSData));
145 data_add(args.asd, fd, &snort_free);
146 fd->state = TNS_STATE_MESSAGE_LEN;
147 }
148
149 offset = 0;
150 while (offset < args.size)
151 {
152 switch (fd->state)
153 {
154 case TNS_STATE_MESSAGE_LEN:
155 fd->l.raw_len[fd->pos++] = args.data[offset];
156 if (fd->pos >= offsetof(ClientTNSMsg, checksum))
157 {
158 fd->stringlen = ntohs(fd->l.len);
159 if (fd->stringlen == 2)
160 {
161 if (offset == args.size - 1)
162 goto done;
163 return reset_flow_data(fd);
164 }
165 else if (fd->stringlen < 2)
166 return reset_flow_data(fd);
167 else if (fd->stringlen > args.size)
168 return reset_flow_data(fd);
169 else
170 fd->state = TNS_STATE_MESSAGE_CHECKSUM;
171 }
172 break;
173
174 case TNS_STATE_MESSAGE_CHECKSUM:
175 if (args.data[offset] != 0)
176 return reset_flow_data(fd);
177 fd->pos++;
178 if (fd->pos >= offsetof(ClientTNSMsg, msg))
179 fd->state = TNS_STATE_MESSAGE;
180 break;
181
182 case TNS_STATE_MESSAGE:
183 fd->message = args.data[offset];
184 if (fd->message < TNS_TYPE_CONNECT || fd->message > TNS_TYPE_MAX)
185 return reset_flow_data(fd);
186 fd->pos++;
187 fd->state = TNS_STATE_MESSAGE_RES;
188 break;
189 case TNS_STATE_MESSAGE_RES:
190 fd->state = TNS_STATE_MESSAGE_HD_CHECKSUM;
191 fd->pos++;
192 break;
193 case TNS_STATE_MESSAGE_HD_CHECKSUM:
194 fd->pos++;
195 if (fd->pos >= offsetof(ClientTNSMsg, data))
196 {
197 switch (fd->message)
198 {
199 case TNS_TYPE_CONNECT:
200 fd->state = TNS_STATE_MESSAGE_CONNECT;
201 break;
202 case TNS_TYPE_ACK:
203 case TNS_TYPE_REFUSE:
204 case TNS_TYPE_DATA:
205 case TNS_TYPE_NULL:
206 case TNS_TYPE_ABORT:
207 case TNS_TYPE_RESEND:
208 case TNS_TYPE_MARKER:
209 case TNS_TYPE_ATTENTION:
210 case TNS_TYPE_CONTROL:
211 if (fd->pos >= fd->stringlen)
212 {
213 if (offset == (args.size - 1))
214 goto done;
215 return reset_flow_data(fd);
216 }
217 fd->state = TNS_STATE_MESSAGE_DATA;
218 break;
219 case TNS_TYPE_ACCEPT:
220 case TNS_TYPE_REDIRECT:
221 default:
222 return reset_flow_data(fd);
223 }
224 }
225 break;
226 case TNS_STATE_MESSAGE_CONNECT:
227 if (fd->pos >= (CONNECT_VERSION_OFFSET + 2))
228 break;
229 fd->l.raw_len[fd->pos - CONNECT_VERSION_OFFSET] = args.data[offset];
230 fd->pos++;
231 if (fd->pos == (CONNECT_VERSION_OFFSET + 2))
232 {
233 {
234 switch (ntohs(fd->l.len))
235 {
236 case 0x136:
237 fd->version = "8";
238 break;
239 case 0x137:
240 fd->version = "9i R1";
241 break;
242 case 0x138:
243 fd->version = "9i R2";
244 break;
245 case 0x139:
246 fd->version = "10g R1/R2";
247 break;
248 case 0x13A:
249 fd->version = "11g R1";
250 break;
251 default:
252 break;
253 }
254 }
255 fd->l.len = 0;
256 fd->state = TNS_STATE_MESSAGE_CONNECT_OFFSET_DC;
257 }
258 break;
259 case TNS_STATE_MESSAGE_CONNECT_OFFSET_DC:
260 fd->pos++;
261 if (fd->pos >= CONNECT_DATA_OFFSET)
262 fd->state = TNS_STATE_MESSAGE_CONNECT_OFFSET;
263 break;
264 case TNS_STATE_MESSAGE_CONNECT_OFFSET:
265 fd->l.raw_len[fd->pos - CONNECT_DATA_OFFSET] = args.data[offset];
266 fd->pos++;
267 if (fd->pos >= (CONNECT_DATA_OFFSET + 2))
268 {
269 fd->offsetlen = ntohs(fd->l.len);
270 if (fd->offsetlen > args.size)
271 {
272 return reset_flow_data(fd);
273 }
274 fd->state = TNS_STATE_MESSAGE_CONNECT_PREDATA;
275 }
276 break;
277 case TNS_STATE_MESSAGE_CONNECT_PREDATA:
278 fd->pos++;
279 if (fd->pos >= fd->offsetlen)
280 {
281 fd->state = TNS_STATE_MESSAGE_CONNECT_DATA;
282 }
283 break;
284 case TNS_STATE_MESSAGE_CONNECT_DATA:
285 if (tolower(args.data[offset]) != USER_STRING[user_pos])
286 {
287 user_pos = 0;
288 if (tolower(args.data[offset]) == USER_STRING[user_pos])
289 user_pos++;
290 }
291 else if (++user_pos > MAX_USER_POS)
292 {
293 user_start = offset+1;
294 fd->state = TNS_STATE_COLLECT_USER;
295 }
296
297 fd->pos++;
298 if (fd->pos >= fd->stringlen)
299 {
300 if (offset == (args.size - 1))
301 goto done;
302 return reset_flow_data(fd);
303 }
304 break;
305 case TNS_STATE_COLLECT_USER:
306 if (user_end == 0 && args.data[offset] == ')')
307 {
308 user_end = offset;
309 }
310
311 fd->pos++;
312 if (fd->pos >= fd->stringlen)
313 {
314 if (offset == (args.size - 1))
315 goto done;
316 return reset_flow_data(fd);
317 }
318 break;
319 case TNS_STATE_MESSAGE_DATA:
320 fd->pos++;
321 if (fd->pos >= fd->stringlen)
322 {
323 if (offset == (args.size - 1))
324 goto done;
325 return reset_flow_data(fd);
326 }
327 break;
328 default:
329 goto inprocess;
330 }
331 offset++;
332 }
333 inprocess:
334 return APPID_INPROCESS;
335
336 done:
337 add_app(args.asd, APP_ID_ORACLE_TNS, APP_ID_ORACLE_DATABASE, fd->version, args.change_bits);
338 if (user_start && user_end && ((user_size = user_end - user_start) > 0))
339 {
340 /* we truncate extra long usernames */
341 if (user_size > TNS_MAX_INFO_SIZE)
342 user_size = TNS_MAX_INFO_SIZE;
343 memcpy(username, &args.data[user_start], user_size);
344 username[user_size] = 0;
345 add_user(args.asd, username, APP_ID_ORACLE_DATABASE, true, args.change_bits);
346 }
347 return APPID_SUCCESS;
348 }