/src/suricata7/src/detect-ssh-software-version.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2007-2020 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Pablo Rincon <pablo.rincon.crespo@gmail.com> |
22 | | * |
23 | | * Implements the ssh.softwareversion keyword |
24 | | * You can match over the software version string of ssh, and it will |
25 | | * be compared from the beginning of the string so you can say for |
26 | | * example ssh.softwareversion:"PuTTY" and it can match, or you can |
27 | | * also specify the version, something like |
28 | | * ssh.softwareversion:"PuTTY-Release-0.55" |
29 | | * I find this useful to match over a known vulnerable server/client |
30 | | * software version in combination to other checks, so you can know |
31 | | * that the risk is higher |
32 | | */ |
33 | | |
34 | | #include "suricata-common.h" |
35 | | #include "threads.h" |
36 | | #include "decode.h" |
37 | | |
38 | | #include "detect.h" |
39 | | #include "detect-parse.h" |
40 | | |
41 | | #include "detect-engine.h" |
42 | | #include "detect-engine-mpm.h" |
43 | | #include "detect-engine-state.h" |
44 | | #include "detect-engine-build.h" |
45 | | |
46 | | #include "flow.h" |
47 | | #include "flow-var.h" |
48 | | #include "flow-util.h" |
49 | | |
50 | | #include "util-debug.h" |
51 | | #include "util-unittest.h" |
52 | | #include "util-unittest-helper.h" |
53 | | |
54 | | #include "app-layer.h" |
55 | | #include "app-layer-parser.h" |
56 | | #include "app-layer-ssh.h" |
57 | | #include "detect-ssh-software-version.h" |
58 | | #include "rust.h" |
59 | | |
60 | | #include "stream-tcp.h" |
61 | | |
62 | | /** |
63 | | * \brief Regex for parsing the softwareversion string |
64 | | */ |
65 | 73 | #define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\:\\.\\-\\_\\+\\s+]+)\\s*\"?\\s*$" |
66 | | |
67 | | static DetectParseRegex parse_regex; |
68 | | |
69 | | static int DetectSshSoftwareVersionMatch (DetectEngineThreadCtx *, |
70 | | Flow *, uint8_t, void *, void *, |
71 | | const Signature *, const SigMatchCtx *); |
72 | | static int DetectSshSoftwareVersionSetup (DetectEngineCtx *, Signature *, const char *); |
73 | | #ifdef UNITTESTS |
74 | | static void DetectSshSoftwareVersionRegisterTests(void); |
75 | | #endif |
76 | | static void DetectSshSoftwareVersionFree(DetectEngineCtx *de_ctx, void *); |
77 | | static int g_ssh_banner_list_id = 0; |
78 | | |
79 | | |
80 | | /** |
81 | | * \brief Registration function for keyword: ssh.softwareversion |
82 | | */ |
83 | | void DetectSshSoftwareVersionRegister(void) |
84 | 73 | { |
85 | 73 | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].name = "ssh.softwareversion"; |
86 | 73 | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].desc = "match SSH software string"; |
87 | 73 | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].url = "/rules/ssh-keywords.html#ssh-softwareversion"; |
88 | 73 | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerTxMatch = DetectSshSoftwareVersionMatch; |
89 | 73 | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup; |
90 | 73 | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; |
91 | | #ifdef UNITTESTS |
92 | | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests; |
93 | | #endif |
94 | 73 | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].flags = SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_INFO_DEPRECATED; |
95 | 73 | sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].alternative = DETECT_AL_SSH_SOFTWARE; |
96 | | |
97 | 73 | DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); |
98 | | |
99 | 73 | g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); |
100 | | |
101 | 73 | DetectAppLayerInspectEngineRegister2("ssh_banner", ALPROTO_SSH, SIG_FLAG_TOSERVER, |
102 | 73 | SshStateBannerDone, DetectEngineInspectGenericList, NULL); |
103 | 73 | DetectAppLayerInspectEngineRegister2("ssh_banner", ALPROTO_SSH, SIG_FLAG_TOCLIENT, |
104 | 73 | SshStateBannerDone, DetectEngineInspectGenericList, NULL); |
105 | 73 | } |
106 | | |
107 | | /** |
108 | | * \brief match the specified version on a ssh session |
109 | | * |
110 | | * \param t pointer to thread vars |
111 | | * \param det_ctx pointer to the pattern matcher thread |
112 | | * \param p pointer to the current packet |
113 | | * \param m pointer to the sigmatch that we will cast into DetectSshSoftwareVersionData |
114 | | * |
115 | | * \retval 0 no match |
116 | | * \retval 1 match |
117 | | */ |
118 | | static int DetectSshSoftwareVersionMatch (DetectEngineThreadCtx *det_ctx, |
119 | | Flow *f, uint8_t flags, void *state, void *txv, |
120 | | const Signature *s, const SigMatchCtx *m) |
121 | 0 | { |
122 | 0 | SCEnter(); |
123 | |
|
124 | 0 | DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m; |
125 | 0 | if (state == NULL) { |
126 | 0 | SCLogDebug("no ssh state, no match"); |
127 | 0 | SCReturnInt(0); |
128 | 0 | } |
129 | | |
130 | 0 | int ret = 0; |
131 | 0 | const uint8_t *software = NULL; |
132 | 0 | uint32_t b_len = 0; |
133 | |
|
134 | 0 | if (rs_ssh_tx_get_software(txv, &software, &b_len, flags) != 1) |
135 | 0 | SCReturnInt(0); |
136 | 0 | if (software == NULL || b_len == 0) |
137 | 0 | SCReturnInt(0); |
138 | 0 | if (b_len == ssh->len) { |
139 | 0 | if (memcmp(software, ssh->software_ver, ssh->len) == 0) { |
140 | 0 | ret = 1; |
141 | 0 | } |
142 | 0 | } |
143 | |
|
144 | 0 | SCReturnInt(ret); |
145 | 0 | } |
146 | | |
147 | | /** |
148 | | * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" |
149 | | * |
150 | | * \param de_ctx Pointer to the detection engine context |
151 | | * \param idstr Pointer to the user provided id option |
152 | | * |
153 | | * \retval id_d pointer to DetectSshSoftwareVersionData on success |
154 | | * \retval NULL on failure |
155 | | */ |
156 | | static DetectSshSoftwareVersionData *DetectSshSoftwareVersionParse (DetectEngineCtx *de_ctx, const char *str) |
157 | 40 | { |
158 | 40 | DetectSshSoftwareVersionData *ssh = NULL; |
159 | 40 | int res = 0; |
160 | 40 | size_t pcre2_len; |
161 | | |
162 | 40 | pcre2_match_data *match = NULL; |
163 | 40 | int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0); |
164 | | |
165 | 40 | if (ret < 1 || ret > 3) { |
166 | 4 | SCLogError("invalid ssh.softwareversion option"); |
167 | 4 | goto error; |
168 | 4 | } |
169 | | |
170 | 36 | if (ret > 1) { |
171 | 36 | const char *str_ptr = NULL; |
172 | 36 | res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); |
173 | 36 | if (res < 0) { |
174 | 0 | SCLogError("pcre2_substring_get_bynumber failed"); |
175 | 0 | goto error; |
176 | 0 | } |
177 | | |
178 | | /* We have a correct id option */ |
179 | 36 | ssh = SCMalloc(sizeof(DetectSshSoftwareVersionData)); |
180 | 36 | if (unlikely(ssh == NULL)) { |
181 | 0 | pcre2_substring_free((PCRE2_UCHAR *)str_ptr); |
182 | 0 | goto error; |
183 | 0 | } |
184 | 36 | ssh->software_ver = (uint8_t *)SCStrdup((char *)str_ptr); |
185 | 36 | if (ssh->software_ver == NULL) { |
186 | 0 | pcre2_substring_free((PCRE2_UCHAR *)str_ptr); |
187 | 0 | goto error; |
188 | 0 | } |
189 | 36 | pcre2_substring_free((PCRE2_UCHAR *)str_ptr); |
190 | | |
191 | 36 | ssh->len = (uint16_t)strlen((char *)ssh->software_ver); |
192 | | |
193 | 36 | SCLogDebug("will look for ssh %s", ssh->software_ver); |
194 | 36 | } |
195 | | |
196 | 36 | pcre2_match_data_free(match); |
197 | 36 | return ssh; |
198 | | |
199 | 4 | error: |
200 | 4 | if (match) { |
201 | 4 | pcre2_match_data_free(match); |
202 | 4 | } |
203 | 4 | if (ssh != NULL) |
204 | 0 | DetectSshSoftwareVersionFree(de_ctx, ssh); |
205 | 4 | return NULL; |
206 | | |
207 | 36 | } |
208 | | |
209 | | /** |
210 | | * \brief this function is used to add the parsed "id" option |
211 | | * \brief into the current signature |
212 | | * |
213 | | * \param de_ctx pointer to the Detection Engine Context |
214 | | * \param s pointer to the Current Signature |
215 | | * \param idstr pointer to the user provided "id" option |
216 | | * |
217 | | * \retval 0 on Success |
218 | | * \retval -1 on Failure |
219 | | */ |
220 | | static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) |
221 | 42 | { |
222 | 42 | DetectSshSoftwareVersionData *ssh = NULL; |
223 | 42 | SigMatch *sm = NULL; |
224 | | |
225 | 42 | if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) |
226 | 2 | return -1; |
227 | | |
228 | 40 | ssh = DetectSshSoftwareVersionParse(NULL, str); |
229 | 40 | if (ssh == NULL) |
230 | 4 | goto error; |
231 | | |
232 | | /* Okay so far so good, lets get this into a SigMatch |
233 | | * and put it in the Signature. */ |
234 | 36 | sm = SigMatchAlloc(); |
235 | 36 | if (sm == NULL) |
236 | 0 | goto error; |
237 | | |
238 | 36 | sm->type = DETECT_AL_SSH_SOFTWAREVERSION; |
239 | 36 | sm->ctx = (void *)ssh; |
240 | | |
241 | 36 | SigMatchAppendSMToList(s, sm, g_ssh_banner_list_id); |
242 | 36 | return 0; |
243 | | |
244 | 4 | error: |
245 | 4 | if (ssh != NULL) |
246 | 0 | DetectSshSoftwareVersionFree(de_ctx, ssh); |
247 | 4 | if (sm != NULL) |
248 | 0 | SCFree(sm); |
249 | 4 | return -1; |
250 | | |
251 | 36 | } |
252 | | |
253 | | /** |
254 | | * \brief this function will free memory associated with DetectSshSoftwareVersionData |
255 | | * |
256 | | * \param id_d pointer to DetectSshSoftwareVersionData |
257 | | */ |
258 | | static void DetectSshSoftwareVersionFree(DetectEngineCtx *de_ctx, void *ptr) |
259 | 36 | { |
260 | 36 | if (ptr == NULL) |
261 | 0 | return; |
262 | | |
263 | 36 | DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)ptr; |
264 | 36 | if (ssh->software_ver != NULL) |
265 | 36 | SCFree(ssh->software_ver); |
266 | 36 | SCFree(ssh); |
267 | 36 | } |
268 | | |
269 | | #ifdef UNITTESTS /* UNITTESTS */ |
270 | | #include "detect-engine-alert.h" |
271 | | |
272 | | /** |
273 | | * \test DetectSshSoftwareVersionTestParse01 is a test to make sure that we parse |
274 | | * a software version correctly |
275 | | */ |
276 | | static int DetectSshSoftwareVersionTestParse01 (void) |
277 | | { |
278 | | DetectSshSoftwareVersionData *ssh = NULL; |
279 | | ssh = DetectSshSoftwareVersionParse(NULL, "PuTTY_1.0"); |
280 | | if (ssh != NULL && strncmp((char *) ssh->software_ver, "PuTTY_1.0", 9) == 0) { |
281 | | DetectSshSoftwareVersionFree(NULL, ssh); |
282 | | return 1; |
283 | | } |
284 | | |
285 | | return 0; |
286 | | } |
287 | | |
288 | | /** |
289 | | * \test DetectSshSoftwareVersionTestParse02 is a test to make sure that we parse |
290 | | * the software version correctly |
291 | | */ |
292 | | static int DetectSshSoftwareVersionTestParse02 (void) |
293 | | { |
294 | | DetectSshSoftwareVersionData *ssh = NULL; |
295 | | ssh = DetectSshSoftwareVersionParse(NULL, "\"SecureCRT-4.0\""); |
296 | | if (ssh != NULL && strncmp((char *) ssh->software_ver, "SecureCRT-4.0", 13) == 0) { |
297 | | DetectSshSoftwareVersionFree(NULL, ssh); |
298 | | return 1; |
299 | | } |
300 | | |
301 | | return 0; |
302 | | } |
303 | | |
304 | | /** |
305 | | * \test DetectSshSoftwareVersionTestParse03 is a test to make sure that we |
306 | | * don't return a ssh_data with an empty value specified |
307 | | */ |
308 | | static int DetectSshSoftwareVersionTestParse03 (void) |
309 | | { |
310 | | DetectSshSoftwareVersionData *ssh = NULL; |
311 | | ssh = DetectSshSoftwareVersionParse(NULL, ""); |
312 | | if (ssh != NULL) { |
313 | | DetectSshSoftwareVersionFree(NULL, ssh); |
314 | | return 0; |
315 | | } |
316 | | |
317 | | return 1; |
318 | | } |
319 | | |
320 | | |
321 | | #include "stream-tcp-reassemble.h" |
322 | | #include "stream-tcp-util.h" |
323 | | |
324 | | /** \test Send a get request in three chunks + more data. */ |
325 | | static int DetectSshSoftwareVersionTestDetect01(void) |
326 | | { |
327 | | TcpReassemblyThreadCtx *ra_ctx = NULL; |
328 | | ThreadVars tv; |
329 | | TcpSession ssn; |
330 | | Flow *f = NULL; |
331 | | Packet *p = NULL; |
332 | | |
333 | | uint8_t sshbuf1[] = "SSH-1."; |
334 | | uint8_t sshbuf2[] = "10-PuTTY_2.123" ; |
335 | | uint8_t sshbuf3[] = "\n"; |
336 | | uint8_t sshbuf4[] = "whatever..."; |
337 | | |
338 | | uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; |
339 | | uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; |
340 | | |
341 | | memset(&tv, 0x00, sizeof(tv)); |
342 | | |
343 | | StreamTcpUTInit(&ra_ctx); |
344 | | StreamTcpUTInitInline(); |
345 | | StreamTcpUTSetupSession(&ssn); |
346 | | StreamTcpUTSetupStream(&ssn.server, 1); |
347 | | StreamTcpUTSetupStream(&ssn.client, 1); |
348 | | |
349 | | f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); |
350 | | FAIL_IF_NULL(f); |
351 | | f->protoctx = &ssn; |
352 | | f->proto = IPPROTO_TCP; |
353 | | f->alproto = ALPROTO_SSH; |
354 | | |
355 | | p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); |
356 | | FAIL_IF(unlikely(p == NULL)); |
357 | | p->flow = f; |
358 | | |
359 | | Signature *s = NULL; |
360 | | ThreadVars th_v; |
361 | | DetectEngineThreadCtx *det_ctx = NULL; |
362 | | |
363 | | memset(&th_v, 0, sizeof(th_v)); |
364 | | |
365 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
366 | | FAIL_IF_NULL(de_ctx); |
367 | | |
368 | | de_ctx->flags |= DE_QUIET; |
369 | | |
370 | | s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)"); |
371 | | FAIL_IF_NULL(s); |
372 | | |
373 | | SigGroupBuild(de_ctx); |
374 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
375 | | |
376 | | uint32_t seq = 2; |
377 | | for (int i=0; i<4; i++) { |
378 | | FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); |
379 | | seq += sshlens[i]; |
380 | | FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); |
381 | | } |
382 | | |
383 | | void *ssh_state = f->alstate; |
384 | | FAIL_IF_NULL(ssh_state); |
385 | | |
386 | | /* do detect */ |
387 | | SigMatchSignatures(&th_v, de_ctx, det_ctx, p); |
388 | | |
389 | | FAIL_IF(PacketAlertCheck(p, 1)); |
390 | | |
391 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
392 | | DetectEngineCtxFree(de_ctx); |
393 | | |
394 | | UTHFreePacket(p); |
395 | | StreamTcpUTClearSession(&ssn); |
396 | | StreamTcpUTDeinit(ra_ctx); |
397 | | UTHFreeFlow(f); |
398 | | PASS; |
399 | | } |
400 | | |
401 | | /** \test Send a get request in three chunks + more data. */ |
402 | | static int DetectSshSoftwareVersionTestDetect02(void) |
403 | | { |
404 | | TcpReassemblyThreadCtx *ra_ctx = NULL; |
405 | | ThreadVars tv; |
406 | | TcpSession ssn; |
407 | | Flow *f = NULL; |
408 | | Packet *p = NULL; |
409 | | |
410 | | uint8_t sshbuf1[] = "SSH-1.99-Pu"; |
411 | | uint8_t sshbuf2[] = "TTY_2.123" ; |
412 | | uint8_t sshbuf3[] = "\n"; |
413 | | uint8_t sshbuf4[] = "whatever..."; |
414 | | |
415 | | uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; |
416 | | uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; |
417 | | |
418 | | memset(&tv, 0x00, sizeof(tv)); |
419 | | |
420 | | StreamTcpUTInit(&ra_ctx); |
421 | | StreamTcpUTInitInline(); |
422 | | StreamTcpUTSetupSession(&ssn); |
423 | | StreamTcpUTSetupStream(&ssn.server, 1); |
424 | | StreamTcpUTSetupStream(&ssn.client, 1); |
425 | | |
426 | | f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); |
427 | | FAIL_IF_NULL(f); |
428 | | f->protoctx = &ssn; |
429 | | f->proto = IPPROTO_TCP; |
430 | | f->alproto = ALPROTO_SSH; |
431 | | |
432 | | p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); |
433 | | FAIL_IF(unlikely(p == NULL)); |
434 | | p->flow = f; |
435 | | |
436 | | Signature *s = NULL; |
437 | | ThreadVars th_v; |
438 | | DetectEngineThreadCtx *det_ctx = NULL; |
439 | | |
440 | | memset(&th_v, 0, sizeof(th_v)); |
441 | | |
442 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
443 | | FAIL_IF_NULL(de_ctx); |
444 | | |
445 | | de_ctx->flags |= DE_QUIET; |
446 | | |
447 | | s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)"); |
448 | | FAIL_IF_NULL(s); |
449 | | |
450 | | SigGroupBuild(de_ctx); |
451 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
452 | | |
453 | | uint32_t seq = 2; |
454 | | for (int i=0; i<4; i++) { |
455 | | FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); |
456 | | seq += sshlens[i]; |
457 | | FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); |
458 | | } |
459 | | |
460 | | void *ssh_state = f->alstate; |
461 | | FAIL_IF_NULL(ssh_state); |
462 | | |
463 | | /* do detect */ |
464 | | SigMatchSignatures(&th_v, de_ctx, det_ctx, p); |
465 | | |
466 | | FAIL_IF(PacketAlertCheck(p, 1)); |
467 | | |
468 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
469 | | DetectEngineCtxFree(de_ctx); |
470 | | |
471 | | UTHFreePacket(p); |
472 | | StreamTcpUTClearSession(&ssn); |
473 | | StreamTcpUTDeinit(ra_ctx); |
474 | | UTHFreeFlow(f); |
475 | | PASS; |
476 | | } |
477 | | |
478 | | /** \test Send a get request in three chunks + more data. */ |
479 | | static int DetectSshSoftwareVersionTestDetect03(void) |
480 | | { |
481 | | TcpReassemblyThreadCtx *ra_ctx = NULL; |
482 | | ThreadVars tv; |
483 | | TcpSession ssn; |
484 | | Flow *f = NULL; |
485 | | Packet *p = NULL; |
486 | | |
487 | | uint8_t sshbuf1[] = "SSH-1."; |
488 | | uint8_t sshbuf2[] = "7-PuTTY_2.123" ; |
489 | | uint8_t sshbuf3[] = "\n"; |
490 | | uint8_t sshbuf4[] = "whatever..."; |
491 | | |
492 | | uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; |
493 | | uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; |
494 | | |
495 | | memset(&tv, 0x00, sizeof(tv)); |
496 | | |
497 | | StreamTcpUTInit(&ra_ctx); |
498 | | StreamTcpUTInitInline(); |
499 | | StreamTcpUTSetupSession(&ssn); |
500 | | StreamTcpUTSetupStream(&ssn.server, 1); |
501 | | StreamTcpUTSetupStream(&ssn.client, 1); |
502 | | |
503 | | f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); |
504 | | FAIL_IF_NULL(f); |
505 | | f->protoctx = &ssn; |
506 | | f->proto = IPPROTO_TCP; |
507 | | f->alproto = ALPROTO_SSH; |
508 | | |
509 | | p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); |
510 | | FAIL_IF(unlikely(p == NULL)); |
511 | | p->flow = f; |
512 | | |
513 | | Signature *s = NULL; |
514 | | ThreadVars th_v; |
515 | | DetectEngineThreadCtx *det_ctx = NULL; |
516 | | |
517 | | memset(&th_v, 0, sizeof(th_v)); |
518 | | |
519 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
520 | | FAIL_IF_NULL(de_ctx); |
521 | | |
522 | | de_ctx->flags |= DE_QUIET; |
523 | | |
524 | | s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:lalala-3.1.4; sid:1;)"); |
525 | | FAIL_IF_NULL(s); |
526 | | |
527 | | SigGroupBuild(de_ctx); |
528 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
529 | | |
530 | | uint32_t seq = 2; |
531 | | for (int i=0; i<4; i++) { |
532 | | FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); |
533 | | seq += sshlens[i]; |
534 | | FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); |
535 | | } |
536 | | |
537 | | void *ssh_state = f->alstate; |
538 | | FAIL_IF_NULL(ssh_state); |
539 | | |
540 | | /* do detect */ |
541 | | SigMatchSignatures(&th_v, de_ctx, det_ctx, p); |
542 | | |
543 | | FAIL_IF(PacketAlertCheck(p, 1)); |
544 | | |
545 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
546 | | DetectEngineCtxFree(de_ctx); |
547 | | |
548 | | UTHFreePacket(p); |
549 | | StreamTcpUTClearSession(&ssn); |
550 | | StreamTcpUTDeinit(ra_ctx); |
551 | | UTHFreeFlow(f); |
552 | | PASS; |
553 | | } |
554 | | |
555 | | /** |
556 | | * \brief this function registers unit tests for DetectSshSoftwareVersion |
557 | | */ |
558 | | static void DetectSshSoftwareVersionRegisterTests(void) |
559 | | { |
560 | | UtRegisterTest("DetectSshSoftwareVersionTestParse01", |
561 | | DetectSshSoftwareVersionTestParse01); |
562 | | UtRegisterTest("DetectSshSoftwareVersionTestParse02", |
563 | | DetectSshSoftwareVersionTestParse02); |
564 | | UtRegisterTest("DetectSshSoftwareVersionTestParse03", |
565 | | DetectSshSoftwareVersionTestParse03); |
566 | | UtRegisterTest("DetectSshSoftwareVersionTestDetect01", |
567 | | DetectSshSoftwareVersionTestDetect01); |
568 | | UtRegisterTest("DetectSshSoftwareVersionTestDetect02", |
569 | | DetectSshSoftwareVersionTestDetect02); |
570 | | UtRegisterTest("DetectSshSoftwareVersionTestDetect03", |
571 | | DetectSshSoftwareVersionTestDetect03); |
572 | | } |
573 | | #endif /* UNITTESTS */ |