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 // sfportscan.c author Daniel Roelker <droelker@sourcefire.com>
21 // port_scan.cc author Russ Combs <rucombs@cisco.com>
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "detection/detection_engine.h"
28 #include "log/messages.h"
29 #include "managers/inspector_manager.h"
30 #include "profiler/profiler.h"
31 #include "utils/util.h"
32 #include "utils/util_cstring.h"
33 
34 #include "ps_inspect.h"
35 #include "ps_module.h"
36 
37 using namespace snort;
38 
39 THREAD_LOCAL PsPegStats spstats;
40 THREAD_LOCAL ProfileStats psPerfStats;
41 
make_port_scan_info(Packet * p,PS_PROTO * proto)42 static void make_port_scan_info(Packet* p, PS_PROTO* proto)
43 {
44     DataBuffer& buf = DetectionEngine::get_alt_buffer(p);
45 
46     SfIp* ip1 = &proto->low_ip;
47     SfIp* ip2 = &proto->high_ip;
48 
49     char a1[INET6_ADDRSTRLEN];
50     char a2[INET6_ADDRSTRLEN];
51 
52     ip1->ntop(a1, sizeof(a1));
53     ip2->ntop(a2, sizeof(a2));
54 
55     char type;
56 
57     if ( proto->alerts == PS_ALERT_PORTSWEEP or proto->alerts == PS_ALERT_PORTSWEEP_FILTERED )
58         type = 'd';
59     else
60         type = 'r';
61 
62     buf.len = safe_snprintf((char*)buf.data, sizeof(buf.data),
63         "Priority Count: %d\n"
64         "Connection Count: %d\n"
65         "IP Count: %d\n"
66         "Scanne%c IP Range: %s:%s\n"
67         "Port/Proto Count: %d\n"
68         "Port/Proto Range: %d:%d\n",
69         proto->priority_count,
70         proto->connection_count,
71         proto->u_ip_count,
72         type, a1, a2,
73         proto->u_port_count,
74         proto->low_p, proto->high_p);
75 }
76 
make_open_port_info(Packet * p,PS_PROTO * proto)77 static void make_open_port_info(Packet* p, PS_PROTO* proto)
78 {
79     DataBuffer& buf = DetectionEngine::get_alt_buffer(p);
80 
81     SfIp* ip1 = &proto->low_ip;
82     char a1[INET6_ADDRSTRLEN];
83     ip1->ntop(a1, sizeof(a1));
84 
85     buf.len += safe_snprintf((char*)buf.data+buf.len, sizeof(buf.data)-buf.len,
86         "Scanned IP: %s\n"
87         "Port Count: %d\n"
88         "Open Ports:",
89         a1,
90         proto->open_ports_cnt);
91 
92     for ( int i = 0; i < proto->open_ports_cnt; i++ )
93     {
94         buf.len += safe_snprintf(
95             (char*)buf.data + buf.len, sizeof(buf.data) - buf.len, " %hu", proto->open_ports[i]);
96     }
97     buf.len += safe_snprintf((char*)buf.data + buf.len, sizeof(buf.data) - buf.len, "\n");
98 }
99 
100 #if 0
101 // FIXIT-L add open port for port sweeps
102 static void make_open_port_info(Packet* p, uint16_t port)
103 {
104     DataBuffer& buf = DetectionEngine::get_alt_buffer(p);
105 
106     SfIpString ip_str;
107 
108     buf.len = safe_snprintf((char*)buf.data, sizeof(buf.data),
109         "Scanned IP: %s\n"
110         "Open Port: %hu\n",
111         p->ptrs.ip_api.get_src()->ntop(ip_str), port);
112 }
113 #endif
114 
PortscanAlertTcp(Packet * p,PS_PROTO * proto)115 static void PortscanAlertTcp(Packet* p, PS_PROTO* proto)
116 {
117     assert(proto);
118 
119     if ( proto->open_ports_cnt and proto->alerts != PS_ALERT_PORTSWEEP and
120         proto->alerts != PS_ALERT_PORTSWEEP_FILTERED )
121     {
122         make_open_port_info(p, proto);
123     }
124     switch (proto->alerts)
125     {
126     case PS_ALERT_ONE_TO_ONE:
127         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_PORTSCAN);
128         break;
129 
130     case PS_ALERT_ONE_TO_ONE_DECOY:
131         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_DECOY_PORTSCAN);
132         break;
133 
134     case PS_ALERT_PORTSWEEP:
135         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_PORTSWEEP);
136         break;
137 
138     case PS_ALERT_DISTRIBUTED:
139         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_DISTRIBUTED_PORTSCAN);
140         break;
141 
142     case PS_ALERT_ONE_TO_ONE_FILTERED:
143         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_FILTERED_PORTSCAN);
144         break;
145 
146     case PS_ALERT_ONE_TO_ONE_DECOY_FILTERED:
147         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_FILTERED_DECOY_PORTSCAN);
148         break;
149 
150     case PS_ALERT_PORTSWEEP_FILTERED:
151         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_PORTSWEEP_FILTERED);
152         break;
153 
154     case PS_ALERT_DISTRIBUTED_FILTERED:
155         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_FILTERED_DISTRIBUTED_PORTSCAN);
156         break;
157 
158     default:
159         return;
160     }
161 }
162 
PortscanAlertUdp(Packet *,PS_PROTO * proto)163 static void PortscanAlertUdp(Packet*, PS_PROTO* proto)
164 {
165     assert(proto);
166 
167     switch (proto->alerts)
168     {
169     case PS_ALERT_ONE_TO_ONE:
170         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_UDP_PORTSCAN);
171         break;
172 
173     case PS_ALERT_ONE_TO_ONE_DECOY:
174         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_UDP_DECOY_PORTSCAN);
175         break;
176 
177     case PS_ALERT_PORTSWEEP:
178         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_UDP_PORTSWEEP);
179         break;
180 
181     case PS_ALERT_DISTRIBUTED:
182         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_UDP_DISTRIBUTED_PORTSCAN);
183         break;
184 
185     case PS_ALERT_ONE_TO_ONE_FILTERED:
186         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_UDP_FILTERED_PORTSCAN);
187         break;
188 
189     case PS_ALERT_ONE_TO_ONE_DECOY_FILTERED:
190         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_UDP_FILTERED_DECOY_PORTSCAN);
191         break;
192 
193     case PS_ALERT_PORTSWEEP_FILTERED:
194         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_UDP_PORTSWEEP_FILTERED);
195         break;
196 
197     case PS_ALERT_DISTRIBUTED_FILTERED:
198         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_UDP_FILTERED_DISTRIBUTED_PORTSCAN);
199         break;
200 
201     default:
202         break;
203     }
204 }
205 
PortscanAlertIp(Packet *,PS_PROTO * proto)206 static void PortscanAlertIp(Packet*, PS_PROTO* proto)
207 {
208     assert(proto);
209 
210     switch (proto->alerts)
211     {
212     case PS_ALERT_ONE_TO_ONE:
213         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_IP_PORTSCAN);
214         break;
215 
216     case PS_ALERT_ONE_TO_ONE_DECOY:
217         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_IP_DECOY_PORTSCAN);
218         break;
219 
220     case PS_ALERT_PORTSWEEP:
221         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_IP_PORTSWEEP);
222         break;
223 
224     case PS_ALERT_DISTRIBUTED:
225         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_IP_DISTRIBUTED_PORTSCAN);
226         break;
227 
228     case PS_ALERT_ONE_TO_ONE_FILTERED:
229         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_IP_FILTERED_PORTSCAN);
230         break;
231 
232     case PS_ALERT_ONE_TO_ONE_DECOY_FILTERED:
233         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_IP_FILTERED_DECOY_PORTSCAN);
234         break;
235 
236     case PS_ALERT_PORTSWEEP_FILTERED:
237         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_IP_PORTSWEEP_FILTERED);
238         break;
239 
240     case PS_ALERT_DISTRIBUTED_FILTERED:
241         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_IP_FILTERED_DISTRIBUTED_PORTSCAN);
242         break;
243 
244     default:
245         break;
246     }
247 }
248 
PortscanAlertIcmp(Packet *,PS_PROTO * proto)249 static void PortscanAlertIcmp(Packet*, PS_PROTO* proto)
250 {
251     assert(proto);
252 
253     switch (proto->alerts)
254     {
255     case PS_ALERT_PORTSWEEP:
256         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_ICMP_PORTSWEEP);
257         break;
258 
259     case PS_ALERT_PORTSWEEP_FILTERED:
260         DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_ICMP_PORTSWEEP_FILTERED);
261         break;
262 
263     default:
264         break;
265     }
266 }
267 
PortscanAlert(PS_PKT * ps_pkt,PS_PROTO * proto,int proto_type)268 static void PortscanAlert(PS_PKT* ps_pkt, PS_PROTO* proto, int proto_type)
269 {
270     Packet* p = ps_pkt->pkt;
271     make_port_scan_info(p, proto);
272 
273     switch (proto_type)
274     {
275     case PS_PROTO_TCP:
276         PortscanAlertTcp(p, proto);
277         break;
278 
279     case PS_PROTO_UDP:
280         PortscanAlertUdp(p, proto);
281         break;
282 
283     case PS_PROTO_ICMP:
284         PortscanAlertIcmp(p, proto);
285         break;
286 
287     case PS_PROTO_IP:
288         PortscanAlertIp(p, proto);
289         break;
290     }
291 }
292 
get_protos(int ds)293 static std::string get_protos(int ds)
294 {
295     std::string protos;
296 
297     if ( !ds )
298         return "none";
299     if ( (ds & PS_PROTO_ALL) == PS_PROTO_ALL )
300         return "all";
301     if ( ds & PS_PROTO_TCP )
302         protos += "tcp ";
303     if ( ds & PS_PROTO_UDP )
304         protos += "udp ";
305     if ( ds & PS_PROTO_ICMP )
306         protos += "icmp ";
307     if ( ds & PS_PROTO_IP )
308         protos += "ip ";
309 
310     protos.pop_back();
311 
312     return protos;
313 }
314 
get_types(int dst)315 static std::string get_types(int dst)
316 {
317     std::string types;
318 
319     if ( !dst )
320         return "none";
321     if ( (dst & PS_TYPE_ALL) == PS_TYPE_ALL )
322         return "all";
323     if ( dst & PS_TYPE_PORTSCAN )
324         types += "portscan ";
325     if ( dst & PS_TYPE_PORTSWEEP )
326         types += "portsweep ";
327     if ( dst & PS_TYPE_DECOYSCAN )
328         types += "decoy_portscan ";
329     if ( dst & PS_TYPE_DISTPORTSCAN )
330         types += "distributed_portscan ";
331 
332     types.pop_back();
333 
334     return types;
335 }
336 
to_string(const IPSET * list)337 static std::string to_string(const IPSET* list)
338 {
339     SF_LNODE* cursor;
340     std::string ipset;
341 
342     for (auto p = (const IP_PORT*)sflist_first(&list->ip_list, &cursor); p;
343         p = (const IP_PORT*)sflist_next(&cursor))
344     {
345         SfIpString ip_str;
346 
347         p->ip.get_addr()->ntop(ip_str);
348 
349         if ( p->notflag )
350             ipset += "!";
351 
352         ipset += std::string(ip_str);
353 
354         if ( ((p->ip.get_family() == AF_INET6) and (p->ip.get_bits() != 128)) or
355             ((p->ip.get_family() == AF_INET ) and (p->ip.get_bits() != 32 )) )
356             ipset += "/" + std::to_string(p->ip.get_bits());
357 
358         SF_LNODE* pr_cursor;
359         auto pr =(const PORTRANGE*)sflist_first(&p->portset.port_list, &pr_cursor);
360 
361         if ( pr and pr->port_lo )
362             ipset += " : ";
363 
364         for (; pr; pr = (const PORTRANGE*)sflist_next(&pr_cursor))
365         {
366             if ( pr->port_lo )
367             {
368                 ipset += std::to_string(pr->port_lo);
369                 if ( pr->port_hi != pr->port_lo )
370                     ipset += "-" + std::to_string(pr->port_hi);
371                 ipset += " ";
372             }
373         }
374         ipset += ", ";
375     }
376 
377     if ( ipset.empty() )
378         return "none";
379 
380     ipset.erase(ipset.end() - 2);
381 
382     return ipset;
383 }
384 
portscan_config_show(const PortscanConfig * config)385 static void portscan_config_show(const PortscanConfig* config)
386 {
387     ConfigLogger::log_value("memcap", static_cast<uint64_t>(config->memcap));
388     ConfigLogger::log_value("protos", get_protos(config->detect_scans).c_str());
389     ConfigLogger::log_value("scan_types", get_types(config->detect_scan_type).c_str());
390 
391     if ( config->watch_ip )
392         ConfigLogger::log_list("watch_ip", to_string(config->watch_ip).c_str());
393 
394     if ( config->ignore_scanners )
395         ConfigLogger::log_list("ignore_scanners", to_string(config->ignore_scanners).c_str());
396 
397     if ( config->ignore_scanned )
398         ConfigLogger::log_list("ignore_scanned", to_string(config->ignore_scanned).c_str());
399 
400     ConfigLogger::log_flag("alert_all", config->alert_all);
401     ConfigLogger::log_flag("include_midstream", config->include_midstream);
402 
403     ConfigLogger::log_value("tcp_window", config->tcp_window);
404     ConfigLogger::log_value("udp_window", config->udp_window);
405     ConfigLogger::log_value("ip_window", config->ip_window);
406     ConfigLogger::log_value("icmp_window", config->icmp_window);
407 }
408 
409 //-------------------------------------------------------------------------
410 // class stuff
411 //-------------------------------------------------------------------------
412 
PortScan(PortScanModule * mod)413 PortScan::PortScan(PortScanModule* mod)
414 { config = mod->get_data(); }
415 
~PortScan()416 PortScan::~PortScan()
417 {
418     if ( config )
419         delete config;
420 }
421 
tinit()422 void PortScan::tinit()
423 { ps_init_hash(config->memcap); }
424 
tterm()425 void PortScan::tterm()
426 { ps_cleanup(); }
427 
show(const SnortConfig *) const428 void PortScan::show(const SnortConfig*) const
429 {
430     if ( config )
431         portscan_config_show(config);
432 }
433 
eval(Packet * p)434 void PortScan::eval(Packet* p)
435 {
436     Profile profile(psPerfStats);
437     assert(p->ptrs.ip_api.is_ip());
438 
439     if ( p->packet_flags & PKT_REBUILT_STREAM )
440         return;
441 
442     ++spstats.packets;
443     PS_PKT ps_pkt(p);
444 
445     ps_detect(&ps_pkt);
446 
447     if (ps_pkt.scanner and ps_pkt.scanner->proto.alerts and
448         (ps_pkt.scanner->proto.alerts != PS_ALERT_GENERATED))
449     {
450         PortscanAlert(&ps_pkt, &ps_pkt.scanner->proto, ps_pkt.proto);
451     }
452 
453     if (ps_pkt.scanned and ps_pkt.scanned->proto.alerts and
454         (ps_pkt.scanned->proto.alerts != PS_ALERT_GENERATED))
455     {
456         PortscanAlert(&ps_pkt, &ps_pkt.scanned->proto, ps_pkt.proto);
457     }
458 }
459 
460 //-------------------------------------------------------------------------
461 // api stuff
462 //-------------------------------------------------------------------------
463 
port_scan_tinit()464 static void port_scan_tinit()
465 { }
466 
port_scan_tterm()467 static void port_scan_tterm()
468 { ps_cleanup(); }
469 
mod_ctor()470 static Module* mod_ctor()
471 { return new PortScanModule; }
472 
mod_dtor(Module * m)473 static void mod_dtor(Module* m)
474 { delete m; }
475 
sp_ctor(Module * m)476 static Inspector* sp_ctor(Module* m)
477 { return new PortScan((PortScanModule*)m); }
478 
sp_dtor(Inspector * p)479 static void sp_dtor(Inspector* p)
480 { delete p; }
481 
sp_reset()482 static void sp_reset()
483 { ps_reset(); }
484 
485 static const InspectApi sp_api =
486 {
487     {
488         PT_INSPECTOR,
489         sizeof(InspectApi),
490         INSAPI_VERSION,
491         0,
492         API_RESERVED,
493         API_OPTIONS,
494         PS_NAME,
495         PS_HELP,
496         mod_ctor,
497         mod_dtor
498     },
499     IT_PROBE,
500     PROTO_BIT__ANY_IP,
501     nullptr, // buffers
502     nullptr, // service
503     nullptr, // pinit
504     nullptr, // pterm
505     port_scan_tinit, // tinit
506     port_scan_tterm, // tterm
507     sp_ctor,
508     sp_dtor,
509     nullptr, // ssn
510     sp_reset // FIXIT-L only inspector using this, eliminate?
511 };
512 
513 #ifdef BUILDING_SO
514 SO_PUBLIC const BaseApi* snort_plugins[] =
515 #else
516 const BaseApi* nin_port_scan[] =
517 #endif
518 {
519     &sp_api.base,
520     nullptr
521 };
522 
523