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 // portscan.c author Daniel Roelker <droelker@sourcefire.com>
21 // ps_detect.cc author Russ Combs <rucombs@cisco.com>
22
23 /*
24 ** - Marc Norton and Jeremy Hewlett were involved in the requirements and
25 ** design of this portscan detection engine.
26 ** - Thanks to Judy Novak for her suggestion to log open ports on hosts
27 ** that are portscanned. This idea makes portscan a lot more useful for
28 ** analysts.
29 */
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "ps_detect.h"
35
36 #include "hash/hash_defs.h"
37 #include "hash/xhash.h"
38 #include "log/messages.h"
39 #include "protocols/icmp4.h"
40 #include "protocols/packet.h"
41 #include "protocols/tcp.h"
42 #include "stream/stream.h"
43 #include "time/packet_time.h"
44 #include "utils/cpp_macros.h"
45 #include "utils/stats.h"
46
47 #include "ps_inspect.h"
48 #include "ps_pegs.h"
49
50 using namespace snort;
51
52 PADDING_GUARD_BEGIN
53 struct PS_HASH_KEY
54 {
55 int protocol;
56 SfIp scanner;
57 SfIp scanned;
58 int16_t group;
59 uint16_t asid;
60 };
61 PADDING_GUARD_END
62
63 class PortScanCache : public XHash
64 {
65 public:
PortScanCache(unsigned rows,unsigned key_len,unsigned datasize,unsigned memcap)66 PortScanCache(unsigned rows, unsigned key_len, unsigned datasize, unsigned memcap)
67 : XHash(rows, key_len, datasize, memcap)
68 { }
69
is_node_recovery_ok(HashNode * hnode)70 bool is_node_recovery_ok(HashNode* hnode) override
71 {
72 PS_TRACKER* tracker = (PS_TRACKER*)hnode->data;
73
74 if ( !tracker->priority_node )
75 return true;
76
77 /*
78 ** Cycle through the protos to see if it's past the time.
79 ** We only get here if we ARE a priority node.
80 */
81 if ( tracker->proto.window >= packet_time() )
82 return false;
83
84 return true;
85 }
86 };
87
88 static THREAD_LOCAL PortScanCache* portscan_hash = nullptr;
89 extern THREAD_LOCAL PsPegStats spstats;
90
PS_PKT(Packet * p)91 PS_PKT::PS_PKT(Packet* p)
92 {
93 pkt = p;
94 scanner = scanned = nullptr;
95 proto = reverse_pkt = 0;
96 }
97
PortscanConfig()98 PortscanConfig::PortscanConfig()
99 {
100 memset(this, 0, sizeof(*this));
101 }
102
~PortscanConfig()103 PortscanConfig::~PortscanConfig()
104 {
105 if ( ignore_scanners )
106 ipset_free(ignore_scanners);
107
108 if ( ignore_scanned )
109 ipset_free(ignore_scanned);
110
111 if ( watch_ip )
112 ipset_free(watch_ip);
113 }
114
ps_cleanup()115 void ps_cleanup()
116 {
117 if ( portscan_hash )
118 {
119 delete portscan_hash;
120 portscan_hash = nullptr;
121 }
122 }
123
ps_node_size()124 unsigned ps_node_size()
125 { return sizeof(PS_HASH_KEY) + sizeof(PS_TRACKER); }
126
ps_init_hash(unsigned long memcap)127 bool ps_init_hash(unsigned long memcap)
128 {
129 if ( portscan_hash )
130 {
131 bool need_pruning = (memcap < portscan_hash->get_mem_used());
132 portscan_hash->set_memcap(memcap);
133 return need_pruning;
134 }
135
136 int rows = memcap / ps_node_size();
137 portscan_hash = new PortScanCache(rows, sizeof(PS_HASH_KEY), sizeof(PS_TRACKER),
138 memcap);
139
140 return false;
141 }
142
ps_prune_hash(unsigned work_limit)143 bool ps_prune_hash(unsigned work_limit)
144 {
145 if ( !portscan_hash )
146 return true;
147
148 unsigned num_pruned = 0;
149 int result = portscan_hash->tune_memory_resources(work_limit, num_pruned);
150 spstats.reload_prunes += num_pruned;
151 return result != HASH_PENDING;
152 }
153
ps_reset()154 void ps_reset()
155 {
156 if ( portscan_hash )
157 portscan_hash->clear_hash();
158 }
159
160 // Check scanner and scanned ips to see if we can filter them out.
ps_ignore_ip(const SfIp * scanner,uint16_t scanner_port,const SfIp * scanned,uint16_t scanned_port)161 bool PortScan::ps_ignore_ip(const SfIp* scanner, uint16_t scanner_port,
162 const SfIp* scanned, uint16_t scanned_port)
163 {
164 if (config->ignore_scanners)
165 {
166 if (ipset_contains(config->ignore_scanners, scanner, &scanner_port))
167 return true;
168 }
169
170 if (config->ignore_scanned)
171 {
172 if (ipset_contains(config->ignore_scanned, scanned, &scanned_port))
173 return true;
174 }
175
176 return false;
177 }
178
179 /*
180 ** Check the incoming packet to decide whether portscan detection cares
181 ** about this packet. We try to ignore as many packets as possible.
182 */
ps_filter_ignore(PS_PKT * ps_pkt)183 bool PortScan::ps_filter_ignore(PS_PKT* ps_pkt)
184 {
185 Packet* p;
186 int reverse_pkt = 0;
187 const SfIp* scanner, * scanned;
188
189 p = (Packet*)ps_pkt->pkt;
190
191 if(!p->ptrs.ip_api.is_ip())
192 return true;
193
194 if (p->ptrs.tcph)
195 {
196 if ( !(config->detect_scans & PS_PROTO_TCP) )
197 return true;
198
199 /*
200 ** This is where we check all of snort's flags for different
201 ** TCP session scenarios. The checks cover:
202 **
203 ** - dropping packets in established sessions, but not the
204 ** TWH packet.
205 ** - dropping the SYN/ACK packet from the server on a valid
206 ** connection (we'll catch the TWH later if it happens).
207 */
208 /*
209 ** Ignore packets that are already part of an established TCP
210 ** stream.
211 */
212 if (((p->packet_flags & (PKT_STREAM_EST | PKT_STREAM_TWH))
213 == PKT_STREAM_EST) && !(p->ptrs.tcph->th_flags & TH_RST))
214 {
215 return true;
216 }
217
218 /*
219 ** Ignore the server's initial response, unless it's to RST
220 ** the connection.
221 */
222 /*
223 if(!(p->ptrs.tcph->th_flags & TH_RST) &&
224 !(p->packet_flags & (PKT_STREAM_EST)) &&
225 (p->is_from_server()))
226 {
227 return true;
228 }
229 */
230 }
231 else if (p->ptrs.udph)
232 {
233 if ( !(config->detect_scans & PS_PROTO_UDP) )
234 return true;
235 }
236 else if (p->ptrs.icmph)
237 {
238 if ( p->ptrs.icmph->type != ICMP_DEST_UNREACH and !(config->detect_scans & PS_PROTO_ICMP) )
239 return true;
240 }
241 else
242 {
243 if ( !(config->detect_scans & PS_PROTO_IP) )
244 return true;
245 }
246
247 // Check if the packet is reversed
248 if ((p->is_from_server()))
249 {
250 reverse_pkt = 1;
251 }
252 else if (p->ptrs.icmph && p->ptrs.icmph->type == ICMP_DEST_UNREACH)
253 {
254 reverse_pkt = 1;
255 }
256 else if (p->ptrs.udph and p->flow )
257 {
258 if (Stream::get_packet_direction(p) & PKT_FROM_SERVER)
259 reverse_pkt = 1;
260 }
261
262 scanner = p->ptrs.ip_api.get_src();
263 scanned = p->ptrs.ip_api.get_dst();
264
265 if (reverse_pkt)
266 {
267 if (ps_ignore_ip(scanned, p->ptrs.dp, scanner, p->ptrs.sp))
268 return true;
269 }
270 else
271 {
272 if (ps_ignore_ip(scanner, p->ptrs.sp, scanned, p->ptrs.dp))
273 return true;
274 }
275
276 ps_pkt->reverse_pkt = reverse_pkt;
277
278 if (config->watch_ip)
279 {
280 if (ipset_contains(config->watch_ip, scanner, &(p->ptrs.sp)))
281 return false;
282
283 if (ipset_contains(config->watch_ip, scanned, &(p->ptrs.dp)))
284 return false;
285
286 return true;
287 }
288 return false;
289 }
290
291 /*
292 ** Get a tracker node by either finding one or starting a new one. We may
293 ** return null, in which case we wait `til the next packet.
294 */
ps_tracker_get(PS_HASH_KEY * key)295 static PS_TRACKER* ps_tracker_get(PS_HASH_KEY* key)
296 {
297 PS_TRACKER* ht = (PS_TRACKER*)portscan_hash->get_user_data((void*)key);
298
299 if ( ht )
300 return ht;
301
302 auto prev_count = portscan_hash->get_num_nodes();
303 if ( portscan_hash->insert((void*)key, nullptr) != HASH_OK )
304 return nullptr;
305
306 ++spstats.trackers;
307 if ( prev_count == portscan_hash->get_num_nodes() )
308 ++spstats.alloc_prunes;
309
310 ht = (PS_TRACKER*)portscan_hash->get_mru_user_data();
311
312 if ( ht )
313 memset(ht, 0x00, sizeof(PS_TRACKER));
314
315 return ht;
316 }
317
ps_tracker_lookup(PS_PKT * ps_pkt,PS_TRACKER ** scanner,PS_TRACKER ** scanned)318 bool PortScan::ps_tracker_lookup(
319 PS_PKT* ps_pkt, PS_TRACKER** scanner, PS_TRACKER** scanned)
320 {
321 PS_HASH_KEY key;
322 Packet* p = (Packet*)ps_pkt->pkt;
323
324 if (ps_get_proto(ps_pkt, &key.protocol) == -1)
325 return false;
326
327 ps_pkt->proto = key.protocol;
328 key.asid = p->pkth->address_space_id;
329
330 /*
331 ** Let's lookup the host that is being scanned, taking into account
332 ** the pkt may be reversed.
333 */
334 if (config->detect_scan_type &
335 (PS_TYPE_PORTSCAN | PS_TYPE_DECOYSCAN | PS_TYPE_DISTPORTSCAN))
336 {
337 key.scanner.clear();
338
339 if (ps_pkt->reverse_pkt)
340 {
341 key.scanned = *p->ptrs.ip_api.get_src();
342 key.group = p->get_ingress_group();
343 }
344 else
345 {
346 key.scanned = *p->ptrs.ip_api.get_dst();
347 key.group = p->get_egress_group();
348 }
349
350 *scanned = ps_tracker_get(&key);
351 }
352
353 // Let's lookup the host that is scanning.
354 if (config->detect_scan_type &
355 (PS_TYPE_PORTSWEEP | PS_TYPE_PORTSCAN | PS_TYPE_DECOYSCAN | PS_TYPE_DISTPORTSCAN))
356 {
357 key.scanned.clear();
358
359 if (ps_pkt->reverse_pkt)
360 {
361 key.scanner = *p->ptrs.ip_api.get_dst();
362 key.group = p->get_egress_group();
363 }
364 else
365 {
366 key.scanner = *p->ptrs.ip_api.get_src();
367 key.group = p->get_ingress_group();
368 }
369
370 *scanner = ps_tracker_get(&key);
371 }
372
373 return *scanner or *scanned;
374 }
375
376 /*
377 ** This logic finds the index to the proto array based on the
378 ** portscan configuration. We need special logic because the
379 ** index of the protocol changes based on the configuration.
380 */
ps_get_proto(PS_PKT * ps_pkt,int * proto)381 int PortScan::ps_get_proto(PS_PKT* ps_pkt, int* proto)
382 {
383 Packet* p;
384
385 if (!ps_pkt || !ps_pkt->pkt || !proto)
386 return -1;
387
388 p = (Packet*)ps_pkt->pkt;
389 *proto = 0;
390
391 if ( config->detect_scans & PS_PROTO_TCP )
392 {
393 if ((p->ptrs.tcph)
394 || ((p->ptrs.icmph) && (p->ptrs.icmph->type == ICMP_DEST_UNREACH)
395 && ((p->ptrs.icmph->code == ICMP_PORT_UNREACH)
396 || (p->ptrs.icmph->code == ICMP_PKT_FILTERED))
397 && (p->proto_bits & PROTO_BIT__TCP_EMBED_ICMP)))
398 {
399 *proto = PS_PROTO_TCP;
400 return 0;
401 }
402 }
403
404 if ( config->detect_scans & PS_PROTO_UDP )
405 {
406 if ((p->ptrs.udph)
407 || ((p->ptrs.icmph) && (p->ptrs.icmph->type == ICMP_DEST_UNREACH)
408 && ((p->ptrs.icmph->code == ICMP_PORT_UNREACH)
409 || (p->ptrs.icmph->code == ICMP_PKT_FILTERED))
410 && (p->proto_bits & PROTO_BIT__UDP_EMBED_ICMP)))
411 {
412 *proto = PS_PROTO_UDP;
413 return 0;
414 }
415 }
416
417 if ( config->detect_scans & PS_PROTO_IP )
418 {
419 if ((p->ptrs.ip_api.is_ip() && (!p->ptrs.icmph))
420 || ((p->ptrs.icmph) && (p->ptrs.icmph->type == ICMP_DEST_UNREACH)
421 && ((p->ptrs.icmph->code == ICMP_PROT_UNREACH)
422 || (p->ptrs.icmph->code == ICMP_PKT_FILTERED))))
423 {
424 *proto = PS_PROTO_IP;
425 return 0;
426 }
427 }
428
429 if ( config->detect_scans & PS_PROTO_ICMP )
430 {
431 if (p->ptrs.icmph)
432 {
433 *proto = PS_PROTO_ICMP;
434 return 0;
435 }
436 }
437
438 return -1;
439 }
440
ps_proto_update_window(unsigned interval,PS_PROTO * proto,time_t pkt_time)441 void PortScan::ps_proto_update_window(unsigned interval, PS_PROTO* proto, time_t pkt_time)
442 {
443 if (pkt_time > proto->window)
444 {
445 memset(proto, 0x00, sizeof(PS_PROTO));
446
447 proto->window = pkt_time + interval;
448 }
449 }
450
451 /*
452 ** This function updates the PS_PROTO structure.
453 **
454 ** @param PS_PROTO pointer to structure to update
455 ** @param int number to increment portscan counter
456 ** @param u_long IP address of other host
457 ** @param unsigned short port/ip_proto to track
458 ** @param time_t time the packet was received. update windows.
459 */
ps_proto_update(PS_PROTO * proto,int ps_cnt,int pri_cnt,unsigned window,const SfIp * ip,unsigned short port,time_t pkt_time)460 int PortScan::ps_proto_update(PS_PROTO* proto, int ps_cnt, int pri_cnt,
461 unsigned window, const SfIp* ip, unsigned short port, time_t pkt_time)
462 {
463 if (!proto)
464 return 0;
465
466 /*
467 ** If the ps_cnt is negative, that means we are just taking off
468 ** for valid connection, and we don't want to do anything else,
469 ** like update ip/port, etc.
470 */
471 if (ps_cnt < 0)
472 {
473 proto->connection_count += ps_cnt;
474 if (proto->connection_count < 0)
475 proto->connection_count = 0;
476
477 return 0;
478 }
479
480 /*
481 ** If we are updating a priority cnt, it means we already did the
482 ** unique port and IP on the connection packet.
483 **
484 ** Priority points are only added for invalid response packets.
485 */
486 if (pri_cnt)
487 {
488 proto->priority_count += pri_cnt;
489 if (proto->priority_count < 0)
490 proto->priority_count = 0;
491
492 return 0;
493 }
494
495 /*
496 ** Do time check first before we update the counters, so if
497 ** we need to reset them we do it before we update them.
498 */
499 ps_proto_update_window(window, proto, pkt_time);
500
501 // Update ps counter
502 proto->connection_count += ps_cnt;
503 if (proto->connection_count < 0)
504 proto->connection_count = 0;
505
506 if (!proto->u_ips.equals(*ip, false))
507 {
508 proto->u_ip_count++;
509 proto->u_ips = *ip;
510 }
511
512 /* we need to do the IP comparisons in host order */
513
514 if (proto->low_ip.is_set())
515 {
516 if (proto->low_ip.greater_than(*ip))
517 proto->low_ip = *ip;
518 }
519 else
520 {
521 proto->low_ip = *ip;
522 }
523
524 if (proto->high_ip.is_set())
525 {
526 if (proto->high_ip.less_than(*ip))
527 proto->high_ip = *ip;
528 }
529 else
530 {
531 proto->high_ip = *ip;
532 }
533
534 if (proto->u_ports != port)
535 {
536 proto->u_port_count++;
537 proto->u_ports = port;
538 }
539
540 if (proto->low_p)
541 {
542 if (proto->low_p > port)
543 proto->low_p = port;
544 }
545 else
546 {
547 proto->low_p = port;
548 }
549
550 if (proto->high_p)
551 {
552 if (proto->high_p < port)
553 proto->high_p = port;
554 }
555 else
556 {
557 proto->high_p = port;
558 }
559
560 return 0;
561 }
562
ps_update_open_ports(PS_PROTO * proto,unsigned short port)563 static int ps_update_open_ports(PS_PROTO* proto, unsigned short port)
564 {
565 int iCtr;
566
567 for (iCtr = 0; iCtr < proto->open_ports_cnt; iCtr++)
568 {
569 if (port == proto->open_ports[iCtr])
570 return 0;
571 }
572
573 if (iCtr < (PS_OPEN_PORTS - 1))
574 {
575 proto->open_ports[iCtr] = port;
576 proto->open_ports_cnt++;
577 }
578
579 return 0;
580 }
581
582 /*
583 ** Determine how to update the portscan counter depending on the type
584 ** of TCP packet we have.
585 **
586 ** We are concerned with three types of TCP packets:
587 **
588 ** - initiating TCP packets (we don't care about flags)
589 ** - TCP 3-way handshake packets (we decrement the counter)
590 ** - TCP reset packets on unestablished streams.
591 */
ps_tracker_update_tcp(PS_PKT * ps_pkt,PS_TRACKER * scanner,PS_TRACKER * scanned)592 void PortScan::ps_tracker_update_tcp(PS_PKT* ps_pkt, PS_TRACKER* scanner,
593 PS_TRACKER* scanned)
594 {
595 Packet* p = (Packet*)ps_pkt->pkt;
596 unsigned win = config->tcp_window;
597
598 SfIp cleared;
599 cleared.clear();
600
601 /*
602 ** Handle the initiating packet.
603 **
604 ** If this what stream4 considers to be a valid initiator, then
605 ** we will use the available stream4 information. Otherwise, we
606 ** can just revert to flow and look for initiators and responders.
607 **
608 ** For Stream, depending on the configuration, there might not
609 ** be a session created only based on the SYN packet. Stream
610 ** by default has code that helps deal with SYN flood attacks,
611 ** and may simply ignore the SYN. In this case, we fall through
612 ** to the checks for specific TCP header files (SYN, SYN-ACK, RST).
613 **
614 ** The "midstream" logic below says that, if we include sessions
615 ** picked up midstream, then we don't care about the MIDSTREAM flag.
616 ** Otherwise, only consider streams not picked up midstream.
617 */
618 // FIXIT-E using SSNFLAG_COUNTED_INITIALIZE is a hack to get parity with 2.X
619 // this should be completely redone and port_scan should require stream_tcp
620 if ( p->flow and (p->flow->ssn_state.session_flags & SSNFLAG_COUNTED_INITIALIZE) )
621 {
622 uint32_t session_flags = p->flow->get_session_flags();
623
624 if ((session_flags & SSNFLAG_SEEN_CLIENT) &&
625 !(session_flags & SSNFLAG_SEEN_SERVER) &&
626 (config->include_midstream || !(session_flags & SSNFLAG_MIDSTREAM)))
627 {
628 if (scanned)
629 {
630 ps_proto_update(&scanned->proto, 1, 0, win,
631 p->ptrs.ip_api.get_src(), p->ptrs.dp, packet_time());
632 }
633
634 if (scanner)
635 {
636 ps_proto_update(&scanner->proto, 1, 0, win,
637 p->ptrs.ip_api.get_dst(), p->ptrs.dp, packet_time());
638 }
639 }
640 // Handle the final packet of the three-way handshake.
641 else if (p->packet_flags & PKT_STREAM_TWH)
642 {
643 if (scanned)
644 {
645 ps_proto_update(&scanned->proto, -1, 0, win, &cleared, 0, 0);
646 }
647
648 if (scanner)
649 {
650 ps_proto_update(&scanner->proto, -1, 0, win, &cleared, 0, 0);
651 }
652 }
653 // RST packet on unestablished streams
654 else if ((p->is_from_server()) &&
655 (p->ptrs.tcph && (p->ptrs.tcph->th_flags & TH_RST)) &&
656 (!(p->packet_flags & PKT_STREAM_EST) ||
657 (session_flags & SSNFLAG_MIDSTREAM)))
658 {
659 if (scanned)
660 {
661 ps_proto_update(&scanned->proto, 0, 1, win, &cleared, 0, 0);
662 scanned->priority_node = 1;
663 }
664
665 if (scanner)
666 {
667 ps_proto_update(&scanner->proto, 0, 1, win, &cleared, 0, 0);
668 scanner->priority_node = 1;
669 }
670 }
671 /*
672 ** We only get here on the server's response to the initial
673 ** client connection.
674 **
675 ** That's why we use the sp, because that's the port that is
676 ** open.
677 */
678 else if ((p->is_from_server()) &&
679 !(p->packet_flags & PKT_STREAM_EST))
680 {
681 if (scanned)
682 ps_update_open_ports(&scanned->proto, p->ptrs.sp);
683 }
684 }
685 /*
686 ** Stream didn't create a session on the SYN packet,
687 ** so check specifically for SYN here.
688 */
689 else if ( p->ptrs.tcph and p->ptrs.tcph->is_syn_only() )
690 {
691 /* No session established, packet only has SYN. SYN only
692 ** packet always from client, so use dp.
693 */
694 if (scanned)
695 {
696 ps_proto_update(&scanned->proto, 1, 0, win,
697 p->ptrs.ip_api.get_src(), p->ptrs.dp, packet_time());
698 }
699
700 if (scanner)
701 {
702 ps_proto_update(&scanner->proto, 1, 0, win,
703 p->ptrs.ip_api.get_dst(), p->ptrs.dp, packet_time());
704 }
705 }
706 /*
707 ** Stream didn't create a session on the SYN packet,
708 ** so check specifically for SYN & ACK here. Clear based
709 ** on the 'completion' of three-way handshake.
710 */
711 else if ( p->ptrs.tcph and p->ptrs.tcph->is_syn_ack() )
712 {
713 if (scanned)
714 {
715 ps_proto_update(&scanned->proto, -1, 0, win, &cleared, 0, 0);
716 }
717
718 if (scanner)
719 {
720 ps_proto_update(&scanner->proto, -1, 0, win, &cleared, 0, 0);
721 }
722 }
723 /*
724 ** No session created, clear based on the RST on non
725 ** established session.
726 */
727 else if (p->ptrs.tcph && (p->ptrs.tcph->th_flags & TH_RST))
728 {
729 if (scanned)
730 {
731 ps_proto_update(&scanned->proto, 0, 1, win, &cleared, 0, 0);
732 scanned->priority_node = 1;
733 }
734
735 if (scanner)
736 {
737 ps_proto_update(&scanner->proto, 0, 1, win, &cleared, 0, 0);
738 scanner->priority_node = 1;
739 }
740 }
741 // If we are an icmp unreachable, deal with it here.
742 else if (p->ptrs.icmph)
743 {
744 if (scanned)
745 {
746 ps_proto_update(&scanned->proto, 0, 1, win, &cleared, 0, 0);
747 scanned->priority_node = 1;
748 }
749
750 if (scanner)
751 {
752 ps_proto_update(&scanner->proto, 0, 1, win, &cleared, 0, 0);
753 scanner->priority_node = 1;
754 }
755 }
756 }
757
ps_tracker_update_ip(PS_PKT * ps_pkt,PS_TRACKER * scanner,PS_TRACKER * scanned)758 void PortScan::ps_tracker_update_ip(PS_PKT* ps_pkt, PS_TRACKER* scanner,
759 PS_TRACKER* scanned)
760 {
761 Packet* p = (Packet*)ps_pkt->pkt;
762
763 if ( !p->ptrs.ip_api.is_ip() )
764 return;
765
766 unsigned win = config->ip_window;
767 SfIp cleared;
768 cleared.clear();
769
770 if (p->ptrs.icmph and (p->ptrs.icmph->type == ICMP_DEST_UNREACH))
771 {
772 if (p->ptrs.icmph->code == ICMP_PROT_UNREACH)
773 {
774 if (scanned)
775 {
776 ps_proto_update(&scanned->proto, 0, 1, win, &cleared, 0, 0);
777 scanned->priority_node = 1;
778 }
779 if(scanner)
780 {
781 ps_proto_update(&scanner->proto, 0, 1, win, &cleared, 0, 0);
782 scanner->priority_node = 1;
783 }
784 }
785 else
786 return;
787 }
788 else
789 {
790 if (scanned)
791 {
792 ps_proto_update(&scanned->proto, 1, 0, win, p->ptrs.ip_api.get_src(),
793 (unsigned short)p->get_ip_proto_next(), packet_time());
794 }
795 if (scanner)
796 {
797 ps_proto_update(&scanner->proto, 1, 0, win, p->ptrs.ip_api.get_dst(),
798 (unsigned short)p->get_ip_proto_next(), packet_time());
799 }
800 }
801 }
802
ps_tracker_update_udp(PS_PKT * ps_pkt,PS_TRACKER * scanner,PS_TRACKER * scanned)803 void PortScan::ps_tracker_update_udp(
804 PS_PKT* ps_pkt, PS_TRACKER* scanner, PS_TRACKER* scanned)
805 {
806 Packet* p = (Packet*)ps_pkt->pkt;
807 unsigned win = config->udp_window;
808
809 SfIp cleared;
810 cleared.clear();
811
812 if (p->ptrs.icmph)
813 {
814 if (scanned)
815 {
816 ps_proto_update(&scanned->proto, 0, 1, win, &cleared, 0, 0);
817 scanned->priority_node = 1;
818 }
819
820 if (scanner)
821 {
822 ps_proto_update(&scanner->proto, 0, 1, win, &cleared, 0, 0);
823 scanner->priority_node = 1;
824 }
825 }
826 else if (p->ptrs.udph)
827 {
828 if ( p->flow )
829 {
830 uint32_t direction = Stream::get_packet_direction(p);
831
832 if (direction == PKT_FROM_CLIENT)
833 {
834 if (scanned)
835 {
836 ps_proto_update(&scanned->proto, 1, 0, win,
837 p->ptrs.ip_api.get_src(), p->ptrs.dp, packet_time());
838 }
839
840 if (scanner)
841 {
842 ps_proto_update(&scanner->proto, 1, 0, win,
843 p->ptrs.ip_api.get_dst(), p->ptrs.dp, packet_time());
844 }
845 }
846 else if (direction == PKT_FROM_SERVER)
847 {
848 if (scanned)
849 ps_proto_update(&scanned->proto, -1, 0, win, &cleared, 0, 0);
850
851 if (scanner)
852 ps_proto_update(&scanner->proto, -1, 0, win, &cleared, 0, 0);
853 }
854 }
855 }
856 }
857
ps_tracker_update_icmp(PS_PKT * ps_pkt,PS_TRACKER * scanner,PS_TRACKER *)858 void PortScan::ps_tracker_update_icmp(
859 PS_PKT* ps_pkt, PS_TRACKER* scanner, PS_TRACKER*)
860 {
861 Packet* p = (Packet*)ps_pkt->pkt;
862 unsigned win = config->icmp_window;
863
864 if (p->ptrs.icmph)
865 {
866 switch (p->ptrs.icmph->type)
867 {
868 case ICMP_ECHO:
869 case ICMP_TIMESTAMP:
870 case ICMP_ADDRESS:
871 case ICMP_INFO_REQUEST:
872 if (scanner)
873 {
874 ps_proto_update(&scanner->proto, 1, 0, win,
875 p->ptrs.ip_api.get_dst(), 0, packet_time());
876 }
877 break;
878
879 case ICMP_DEST_UNREACH:
880 if (scanner)
881 {
882 SfIp cleared;
883 cleared.clear();
884
885 ps_proto_update(&scanner->proto, 0, 1, win, &cleared, 0, 0);
886 scanner->priority_node = 1;
887 }
888 break;
889
890 default:
891 break;
892 }
893 }
894 }
895
896 /*
897 ** At this point, we should only be looking at transport protocols
898 ** that we want to. For instance, if we aren't doing UDP portscans
899 ** then we won't see UDP packets here because they were ignored.
900 **
901 ** This is where we evaluate the packet to add/subtract portscan
902 ** tracker values and prioritize a tracker. We also update the
903 ** time windows.
904 */
ps_tracker_update(PS_PKT * ps_pkt,PS_TRACKER * scanner,PS_TRACKER * scanned)905 bool PortScan::ps_tracker_update(PS_PKT* ps_pkt, PS_TRACKER* scanner, PS_TRACKER* scanned)
906 {
907 if ( scanner and scanner->proto.alerts )
908 scanner->proto.alerts = PS_ALERT_GENERATED;
909
910 if ( scanned and scanned->proto.alerts )
911 scanned->proto.alerts = PS_ALERT_GENERATED;
912
913 switch ( ps_pkt->proto )
914 {
915 case PS_PROTO_TCP:
916 ps_tracker_update_tcp(ps_pkt, scanner, scanned);
917 break;
918
919 case PS_PROTO_UDP:
920 ps_tracker_update_udp(ps_pkt, scanner, scanned);
921 break;
922
923 case PS_PROTO_ICMP:
924 ps_tracker_update_icmp(ps_pkt, scanner, scanned);
925 break;
926
927 case PS_PROTO_IP:
928 ps_tracker_update_ip(ps_pkt, scanner, scanned);
929 break;
930
931 default:
932 return false;
933 }
934 return true;
935 }
936
ps_alert_one_to_one(const PS_ALERT_CONF & conf,PS_PROTO * scanner,PS_PROTO * scanned)937 static bool ps_alert_one_to_one(
938 const PS_ALERT_CONF& conf, PS_PROTO* scanner, PS_PROTO* scanned)
939 {
940 // Let's evaluate the scanned host.
941 if (scanned && !scanned->alerts)
942 {
943 if (scanned->priority_count >= conf.priority_count)
944 {
945 if (scanned->u_ip_count < conf.u_ip_count &&
946 scanned->u_port_count >= conf.u_port_count)
947 {
948 if (scanner)
949 {
950 if (scanner->priority_count >= conf.priority_count)
951 {
952 // Now let's check to make sure this is one to one
953 scanned->alerts = PS_ALERT_ONE_TO_ONE;
954 return true;
955 }
956 }
957 else
958 {
959 // If there is no scanner, then we do the best we can.
960 scanned->alerts = PS_ALERT_ONE_TO_ONE;
961 return true;
962 }
963 }
964 }
965 if (scanned->connection_count >= conf.connection_count)
966 {
967 if (conf.connection_count == 0)
968 return false;
969
970 if (scanned->u_ip_count < conf.u_ip_count &&
971 scanned->u_port_count >= conf.u_port_count)
972 {
973 scanned->alerts = PS_ALERT_ONE_TO_ONE_FILTERED;
974 return true;
975 }
976 }
977 }
978
979 return false;
980 }
981
ps_alert_one_to_one_decoy(const PS_ALERT_CONF & conf,PS_PROTO * scanner,PS_PROTO * scanned)982 static bool ps_alert_one_to_one_decoy(
983 const PS_ALERT_CONF& conf, PS_PROTO* scanner, PS_PROTO* scanned)
984 {
985 if (scanned && !scanned->alerts)
986 {
987 if (scanned->priority_count >= conf.priority_count)
988 {
989 if (scanned->u_ip_count >= conf.u_ip_count &&
990 scanned->u_port_count >= conf.u_port_count)
991 {
992 if (scanner && scanner->u_port_count >= conf.u_port_count)
993 {
994 scanned->alerts = PS_ALERT_ONE_TO_ONE_DECOY;
995 return true;
996 }
997 }
998 }
999 if (scanned->connection_count >= conf.connection_count)
1000 {
1001 if (conf.connection_count == 0)
1002 return false;
1003
1004 if (scanned->u_ip_count >= conf.u_ip_count &&
1005 scanned->u_port_count >= conf.u_port_count)
1006 {
1007 if (scanner && scanner->u_port_count >= conf.u_port_count)
1008 {
1009 scanned->alerts = PS_ALERT_ONE_TO_ONE_DECOY_FILTERED;
1010 return true;
1011 }
1012 }
1013 }
1014 }
1015
1016 return false;
1017 }
1018
ps_alert_many_to_one(const PS_ALERT_CONF & conf,PS_PROTO * scanner,PS_PROTO * scanned)1019 static bool ps_alert_many_to_one(
1020 const PS_ALERT_CONF& conf, PS_PROTO* scanner, PS_PROTO* scanned)
1021 {
1022 if (scanned && !scanned->alerts)
1023 {
1024 if (scanned->priority_count >= conf.priority_count)
1025 {
1026 if (scanned->u_ip_count >= conf.u_ip_count &&
1027 scanned->u_port_count >= conf.u_port_count)
1028 {
1029 if (scanner && scanner->u_port_count <= conf.u_port_count)
1030 {
1031 scanned->alerts = PS_ALERT_DISTRIBUTED;
1032 return true;
1033 }
1034 }
1035 }
1036 if (scanned->connection_count >= conf.connection_count)
1037 {
1038 if (conf.connection_count == 0)
1039 return false;
1040
1041 if (scanned->u_ip_count >= conf.u_ip_count &&
1042 scanned->u_port_count >= conf.u_port_count)
1043 {
1044 if (scanner && scanner->u_port_count <= conf.u_port_count)
1045 {
1046 scanned->alerts = PS_ALERT_DISTRIBUTED_FILTERED;
1047 return true;
1048 }
1049 }
1050 }
1051 }
1052
1053 return false;
1054 }
1055
ps_alert_one_to_many(const PS_ALERT_CONF & conf,PS_PROTO * scanner,PS_PROTO *)1056 static bool ps_alert_one_to_many(
1057 const PS_ALERT_CONF& conf, PS_PROTO* scanner, PS_PROTO*)
1058 {
1059 if (scanner && !scanner->alerts)
1060 {
1061 if (scanner->priority_count >= conf.priority_count)
1062 {
1063 if (scanner->u_ip_count >= conf.u_ip_count &&
1064 scanner->u_port_count <= conf.u_port_count)
1065 {
1066 scanner->alerts = PS_ALERT_PORTSWEEP;
1067 return true;
1068 }
1069 }
1070 if (scanner->connection_count >= conf.connection_count)
1071 {
1072 if (conf.connection_count == 0)
1073 return false;
1074
1075 if (scanner->u_ip_count >= conf.u_ip_count &&
1076 scanner->u_port_count <= conf.u_port_count)
1077 {
1078 scanner->alerts = PS_ALERT_PORTSWEEP_FILTERED;
1079 return true;
1080 }
1081 }
1082 }
1083
1084 return false;
1085 }
1086
ps_alert_tcp(PS_PROTO * scanner,PS_PROTO * scanned)1087 void PortScan::ps_alert_tcp(PS_PROTO* scanner, PS_PROTO* scanned)
1088 {
1089 if ((config->detect_scan_type & PS_TYPE_PORTSCAN) &&
1090 ps_alert_one_to_one(config->tcp_ports, scanner, scanned))
1091 {
1092 return;
1093 }
1094
1095 if ((config->detect_scan_type & PS_TYPE_DECOYSCAN) &&
1096 ps_alert_one_to_one_decoy(config->tcp_decoy, scanner, scanned))
1097 {
1098 return;
1099 }
1100
1101 if ((config->detect_scan_type & PS_TYPE_PORTSWEEP) &&
1102 ps_alert_one_to_many(config->tcp_sweep, scanner, scanned))
1103 {
1104 return;
1105 }
1106
1107 if ((config->detect_scan_type & PS_TYPE_DISTPORTSCAN) &&
1108 ps_alert_many_to_one(config->tcp_dist, scanner, scanned))
1109 {
1110 return;
1111 }
1112 }
1113
ps_alert_ip(PS_PROTO * scanner,PS_PROTO * scanned)1114 void PortScan::ps_alert_ip(PS_PROTO* scanner, PS_PROTO* scanned)
1115 {
1116 if ((config->detect_scan_type & PS_TYPE_PORTSCAN) &&
1117 ps_alert_one_to_one(config->ip_proto, scanner, scanned))
1118 {
1119 return;
1120 }
1121
1122 if ((config->detect_scan_type & PS_TYPE_DECOYSCAN) &&
1123 ps_alert_one_to_one_decoy(config->ip_decoy, scanner, scanned))
1124 {
1125 return;
1126 }
1127
1128 if ((config->detect_scan_type & PS_TYPE_PORTSWEEP) &&
1129 ps_alert_one_to_many(config->ip_sweep, scanner, scanned))
1130 {
1131 return;
1132 }
1133
1134 if ((config->detect_scan_type & PS_TYPE_DISTPORTSCAN) &&
1135 ps_alert_many_to_one(config->ip_dist, scanner, scanned))
1136 {
1137 return;
1138 }
1139 }
1140
ps_alert_udp(PS_PROTO * scanner,PS_PROTO * scanned)1141 void PortScan::ps_alert_udp(PS_PROTO* scanner, PS_PROTO* scanned)
1142 {
1143 if ((config->detect_scan_type & PS_TYPE_PORTSCAN) &&
1144 ps_alert_one_to_one(config->udp_ports, scanner, scanned))
1145 {
1146 return;
1147 }
1148
1149 if ((config->detect_scan_type & PS_TYPE_DECOYSCAN) &&
1150 ps_alert_one_to_one_decoy(config->udp_decoy, scanner, scanned))
1151 {
1152 return;
1153 }
1154
1155 if ((config->detect_scan_type & PS_TYPE_PORTSWEEP) &&
1156 ps_alert_one_to_many(config->udp_sweep, scanner, scanned))
1157 {
1158 return;
1159 }
1160
1161 if ((config->detect_scan_type & PS_TYPE_DISTPORTSCAN) &&
1162 ps_alert_many_to_one(config->udp_dist, scanner, scanned))
1163 {
1164 return;
1165 }
1166 }
1167
ps_alert_icmp(PS_PROTO * scanner,PS_PROTO * scanned)1168 void PortScan::ps_alert_icmp(PS_PROTO* scanner, PS_PROTO* scanned)
1169 {
1170 if ((config->detect_scan_type & PS_TYPE_PORTSWEEP) &&
1171 ps_alert_one_to_many(config->icmp_sweep, scanner, scanned))
1172 {
1173 return;
1174 }
1175 }
1176
1177 /*
1178 ** This function evaluates the scanner and scanned trackers and if
1179 ** applicable, generate an alert or alerts for either of the trackers.
1180 **
1181 ** The following alerts can be generated:
1182 ** - One to One Portscan
1183 ** - One to One Decoy Portscan
1184 ** - One to Many Portsweep
1185 ** - Distributed Portscan (Many to One)
1186 ** - Filtered Portscan?
1187 */
ps_tracker_alert(PS_PKT * ps_pkt,PS_TRACKER * scanner,PS_TRACKER * scanned)1188 bool PortScan::ps_tracker_alert(
1189 PS_PKT* ps_pkt, PS_TRACKER* scanner, PS_TRACKER* scanned)
1190 {
1191 PS_PROTO* scanner_proto = nullptr;
1192 PS_PROTO* scanned_proto = nullptr;
1193
1194 if ( scanner )
1195 {
1196 if ( config->alert_all )
1197 scanner->proto.alerts = 0;
1198 scanner_proto = &scanner->proto;
1199 }
1200
1201 if ( scanned )
1202 {
1203 if ( config->alert_all )
1204 scanned->proto.alerts = 0;
1205 scanned_proto = &scanned->proto;
1206 }
1207
1208 switch (ps_pkt->proto)
1209 {
1210 case PS_PROTO_TCP:
1211 ps_alert_tcp(scanner_proto, scanned_proto);
1212 break;
1213
1214 case PS_PROTO_UDP:
1215 ps_alert_udp(scanner_proto, scanned_proto);
1216 break;
1217
1218 case PS_PROTO_ICMP:
1219 ps_alert_icmp(scanner_proto, scanned_proto);
1220 break;
1221
1222 case PS_PROTO_IP:
1223 ps_alert_ip(scanner_proto, scanned_proto);
1224 break;
1225
1226 default:
1227 return false;
1228 }
1229
1230 return true;
1231 }
1232
1233 /*
1234 ** The design of portscan is as follows:
1235 **
1236 ** - Filter Packet. Is the packet part of the ignore or watch list? Is
1237 ** the packet part of an established TCP session (we ignore it)?
1238 **
1239 ** - Tracker Lookup. We lookup trackers for src and dst if either is in
1240 ** the watch list, or not in the ignore list if there is no watch list.
1241 ** If there is not tracker, we create a new one and keep track, both of
1242 ** the scanned host and the scanning host.
1243 **
1244 ** - Tracker Update. We update the tracker using the incoming packet. If
1245 ** the update causes a portscan alert, then we move into the log alert
1246 ** phase.
1247 **
1248 ** - Tracker Evaluate. Generate an alert from the updated tracker. We
1249 ** decide whether we are logging a portscan or sweep (based on the
1250 ** scanning or scanned host, we decide which is more relevant).
1251 */
ps_detect(PS_PKT * ps_pkt)1252 int PortScan::ps_detect(PS_PKT* ps_pkt)
1253 {
1254 PS_TRACKER* scanner = nullptr;
1255 PS_TRACKER* scanned = nullptr;
1256 int check_tcp_rst_other_dir = 1;
1257
1258 assert(ps_pkt and ps_pkt->pkt);
1259
1260 if (ps_filter_ignore(ps_pkt))
1261 return 0;
1262
1263 Packet* p = (Packet*)ps_pkt->pkt;
1264
1265 do
1266 {
1267 if ( !ps_tracker_lookup(ps_pkt, &scanner, &scanned) )
1268 return 0;
1269
1270 if ( !ps_tracker_update(ps_pkt, scanner, scanned) )
1271 return 0;
1272
1273 if ( !ps_tracker_alert(ps_pkt, scanner, scanned) )
1274 return 0;
1275
1276 /* This is added to address the case of no
1277 * session and a RST packet going back from the Server. */
1278 if ( p->ptrs.tcph and (p->ptrs.tcph->th_flags & TH_RST) and !p->flow )
1279 {
1280 if (ps_pkt->reverse_pkt == 1)
1281 check_tcp_rst_other_dir = 0;
1282 else
1283 ps_pkt->reverse_pkt = 1;
1284 }
1285 else
1286 {
1287 check_tcp_rst_other_dir = 0;
1288 }
1289 }
1290 while (check_tcp_rst_other_dir);
1291
1292 ps_pkt->scanner = scanner;
1293 ps_pkt->scanned = scanned;
1294
1295 return 1;
1296 }
1297
1298