From b407f95bb1e4ffcfc6c0eb664e9b1a151220b0ae Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Tue, 28 May 2019 15:32:02 +0200 Subject: [PATCH 01/40] Minor readability changes --- brute_force_detector/README.md | 2 +- brute_force_detector/config.cpp | 89 +++++++++++++++++---------------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/brute_force_detector/README.md b/brute_force_detector/README.md index efc1a1bf..a6cc4815 100644 --- a/brute_force_detector/README.md +++ b/brute_force_detector/README.md @@ -1,4 +1,4 @@ -Bruteforce detector module + Bruteforce detector module ========================== diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index e3e43716..6a13c9c6 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -57,7 +57,8 @@ Config::Config() //SSH SSH_LIST_SIZE = 1000; - SSH_LIST_SIZE_BOTTOM_TRESHOLD = 50; // There are two types of tresholds, first means how many records are in list [50/1000] and based on this value is set up TRESHOLD which detects if host is attacker or not + SSH_LIST_SIZE_BOTTOM_TRESHOLD = 50; // There are two types of tresholds, first means how many records are in list [50/1000] + // and based on this value is set up TRESHOLD which detects if host is attacker or not SSH_LIST_THRESHOLD = 30; SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); @@ -227,202 +228,202 @@ bool Config::initFromFile(string path) value.erase(remove_if(value.begin(), value.end(), ::isspace), value.end()); // GENERAL - if(keyword.compare(kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) == 0) + if(keyword == kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) == 0) + else if(keyword == kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) == 0) + else if(keyword == kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) { GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) == 0) + else if(keyword == kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) { GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = atof(value.c_str()); } - else if(keyword.compare(kw_GENERAL_IGNORE_FIRST_SEND) == 0) + else if(keyword == kw_GENERAL_IGNORE_FIRST_SEND) { GENERAL_IGNORE_FIRST_SEND = strtoul(value.c_str(), NULL, 10); } // ********************* // ******* SSH ********* // ********************* - else if(keyword.compare(kw_SSH_LIST_SIZE) == 0) + else if(keyword == kw_SSH_LIST_SIZE) { SSH_LIST_SIZE = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_SSH_LIST_THRESHOLD) == 0) + else if(keyword == kw_SSH_LIST_THRESHOLD) { SSH_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_SSH_ATTACK_TIMEOUT) == 0) + else if(keyword == kw_SSH_ATTACK_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_SSH_RECORD_TIMEOUT) == 0) + else if(keyword == kw_SSH_RECORD_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_SSH_HOST_TIMEOUT) == 0) + else if(keyword == kw_SSH_HOST_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_SSH_REPORT_TIMEOUT) == 0) + else if(keyword == kw_SSH_REPORT_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); SSH_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) - else if(keyword.compare(kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) == 0) + else if(keyword == kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) { SSH_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) == 0) + else if(keyword == kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) { SSH_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_INC_MIN_BYTES) == 0) + else if(keyword == kw_SSH_BRUTEFORCE_INC_MIN_BYTES) { SSH_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_INC_MAX_BYTES) == 0) + else if(keyword == kw_SSH_BRUTEFORCE_INC_MAX_BYTES) { SSH_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); } // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) - else if(keyword.compare(kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) == 0) + else if(keyword == kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) { SSH_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) == 0) + else if(keyword == kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) { SSH_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) == 0) + else if(keyword == kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) { SSH_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) == 0) + else if(keyword == kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) { SSH_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 10); } // ********************* // ******* RDP ********* // ********************* - else if(keyword.compare(kw_RDP_LIST_SIZE) == 0) + else if(keyword == kw_RDP_LIST_SIZE) { RDP_LIST_SIZE = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_RDP_LIST_THRESHOLD) == 0) + else if(keyword == kw_RDP_LIST_THRESHOLD) { RDP_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_RDP_ATTACK_TIMEOUT) == 0) + else if(keyword == kw_RDP_ATTACK_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_RDP_RECORD_TIMEOUT) == 0) + else if(keyword == kw_RDP_RECORD_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_RDP_HOST_TIMEOUT) == 0) + else if(keyword == kw_RDP_HOST_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_RDP_REPORT_TIMEOUT) == 0) + else if(keyword == kw_RDP_REPORT_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); RDP_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) - else if(keyword.compare(kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) == 0) + else if(keyword == kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) { RDP_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) == 0) + else if(keyword == kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) { RDP_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_INC_MIN_BYTES) == 0) + else if(keyword == kw_RDP_BRUTEFORCE_INC_MIN_BYTES) { RDP_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_INC_MAX_BYTES) == 0) + else if(keyword == kw_RDP_BRUTEFORCE_INC_MAX_BYTES) { RDP_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); } // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) - else if(keyword.compare(kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) == 0) + else if(keyword == kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) { RDP_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) == 0) + else if(keyword == kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) { RDP_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) == 0) + else if(keyword == kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) { RDP_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) == 0) + else if(keyword == kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) { RDP_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 10); } // ********************* // ****** TELNET ******* // ********************* - else if(keyword.compare(kw_TELNET_LIST_SIZE) == 0) + else if(keyword == kw_TELNET_LIST_SIZE) { TELNET_LIST_SIZE = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_TELNET_LIST_THRESHOLD) == 0) + else if(keyword == kw_TELNET_LIST_THRESHOLD) { TELNET_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_TELNET_ATTACK_TIMEOUT) == 0) + else if(keyword == kw_TELNET_ATTACK_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_TELNET_RECORD_TIMEOUT) == 0) + else if(keyword == kw_TELNET_RECORD_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_TELNET_HOST_TIMEOUT) == 0) + else if(keyword == kw_TELNET_HOST_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_TELNET_REPORT_TIMEOUT) == 0) + else if(keyword == kw_TELNET_REPORT_TIMEOUT) { uint32_t sec = strtoul(value.c_str(), NULL, 10); TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) == 0) + else if(keyword == kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) { TELNET_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) == 0) + else if(keyword == kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) { TELNET_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) == 0) + else if(keyword == kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) { TELNET_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); } - else if(keyword.compare(kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) == 0) + else if(keyword == kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) { TELNET_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); } From 8405d222fc78c9e6de522971e7b35d439c299a5d Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Tue, 28 May 2019 15:32:25 +0200 Subject: [PATCH 02/40] Minor readability changes --- brute_force_detector/host.h | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 00148ac6..7836e9ed 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -78,7 +78,7 @@ class IHost { inline ip_addr_t getHostIp() { return hostIp; } inline ur_time_t getTimeOfLastReport() { return timeOfLastReport; } - inline bool isReported() { if(timeOfLastReport == 0) return false; else return true; } + inline bool isReported() { return timeOfLastReport != 0; } inline void setReportTime(ur_time_t actualTime) { timeOfLastReport = actualTime; } inline void setNotReported() { @@ -164,10 +164,7 @@ class IHost { protected: bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) { - if(flowTime + timer <= actualTime) - return true; - else - return false; + return flowTime + timer <= actualTime; } bool scanned; @@ -242,8 +239,8 @@ class IHostMap { typename Container::iterator it = c->begin(); while(it != c->end()) { - if(it->second) - delete it->second; + //if(it->second) + delete it->second; it++; } @@ -273,8 +270,8 @@ class IHostMap { class SSHHostMap : public IHostMap { public: - SSHHostMap() {} - ~SSHHostMap() {} + SSHHostMap() = default; + ~SSHHostMap() = default; virtual void clear() { @@ -296,8 +293,8 @@ class SSHHostMap : public IHostMap { class RDPHostMap: public IHostMap { public: - RDPHostMap() {} - ~RDPHostMap() {} + RDPHostMap() = default; + ~RDPHostMap() = default; virtual void clear() { @@ -321,8 +318,8 @@ class RDPHostMap: public IHostMap { class TELNETHostMap: public IHostMap { public: - TELNETHostMap() {} - ~TELNETHostMap() {} + TELNETHostMap() = default; + ~TELNETHostMap() = default; virtual void clear() { From 3b5b7d8ee1b76fdc94e9d771de1f270c6015d07b Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Tue, 28 May 2019 15:33:29 +0200 Subject: [PATCH 03/40] Minor readability changes --- brute_force_detector/brute_force_detector.cpp | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 5d02022d..7737741b 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -142,15 +142,12 @@ void signalHandler(int signal) bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t actualTime) { - if(oldTime + timer <= actualTime) - return true; - else - return false; + return oldTime + timer <= actualTime; } void printFlowPercent(uint64_t b, uint64_t p) { - if (b && p && b * p) { + if (b && p) { ios::fmtflags f(cout.flags()); cout << " (" << std::fixed << std::setprecision(2) @@ -172,7 +169,7 @@ int main(int argc, char **argv) // ***** Capturing signals ***** #ifdef HAVE_SIGACTION - struct sigaction sigAction; + struct sigaction sigAction{}; sigAction.sa_handler = signalHandler; sigemptyset (&sigAction.sa_mask); @@ -283,7 +280,7 @@ int main(int argc, char **argv) // ***** Init UniRec template for sender ***** bool senderState; - Sender *sender = new Sender(&senderState); + auto sender = new Sender(&senderState); if(!senderState) { cerr << "Error: Invalid output UniRec specifier. Check sender.cpp file.\n"; @@ -376,16 +373,17 @@ int main(int argc, char **argv) ur_time_t flowFirstSeen = ur_get(tmplt, data, F_TIME_FIRST); ur_time_t flowLastSeen = ur_get(tmplt, data, F_TIME_LAST); - IRecord::MatchStructure structure; - structure.flags = tcpFlags; - structure.packets = packets; - structure.bytes = bytes; - structure.srcIp = srcIp; - structure.flowFirstSeen = flowFirstSeen; - structure.flowLastSeen = flowLastSeen; - structure.dstIp = dstIp; - structure.srcPort = srcPort; - structure.dstPort = dstPort; + IRecord::MatchStructure structure{ + .flags = tcpFlags, + .packets = packets, + .bytes = bytes, + .srcIp = srcIp, + .dstIp = dstIp, + .srcPort = srcPort, + .dstPort = dstPort, + .flowFirstSeen = flowFirstSeen, + .flowLastSeen = flowLastSeen, + }; ret = 0; From 22b9cdff1d57cd0630fad670f3900f6103b4066f Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 30 May 2019 16:43:40 +0200 Subject: [PATCH 04/40] Updated READMEs --- README.md | 6 ++++++ smtp_spam_detector/README.md | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 325406fa..19aa0476 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,14 @@ This repository contains modules with the following detection capabilities: * [amplification_detection](amplification_detection): universal detector of DNS/NTP/... amplification attacks * [blacklistfilter](blacklistfilter): module that checks whether observed IP addresses are listed in any of given public-available blacklists +* [brute_force_detector](brute_force_detector): detector of brute-force attacks over SSH, RDP and TELNET. +* [ddos_detector](ddos_detector): detector of DDoS attacks +* [haddrscan_detector](haddrscan_detector): detector of horizontal scans * [hoststatsnemea](hoststatsnemea): universal detection module based on computation of statistics about hosts, it can detect some types of DoS, DDoS, scanning +* [miner_detector](miner_detector): detector of crypto mining hosts. * [sip_bf_detector](sip_bf_detector): detector of brute-force attacks attempting to breach passwords of users on SIP (Session Initiation Protocol) devices +* [smtp_spam_detector](smtp_spam_detector): detector of spam sources * [tunnel_detection](tunnel_detection): detector of communication tunnels over DNS (e.g. using iodine or tcp2dns) * [voip_fraud_detection](voip_fraud_detection): detector of guessing dial scheme of Session Initiation Protocol (SIP) * [vportscan_detector](vportscan_detector): detector of vertical scans based on TCP SYN +* [waintrusion_detector](waintrusion_detector): detector of attacks on web applications diff --git a/smtp_spam_detector/README.md b/smtp_spam_detector/README.md index 8f1f7684..8c856526 100644 --- a/smtp_spam_detector/README.md +++ b/smtp_spam_detector/README.md @@ -2,7 +2,7 @@ ## 1.0 Abstract -It may have seem that these days, the emails are not as popular as the new modern +It may seem that these days, emails are not as popular as the new modern Instant Messaging (IM) apps or the social networks. However, we still rely on an old SMTP protocol, which is the standard protocol for sending e-mails from one Message Transfer Agent (MTA) to another. The SMTP stands for “Simple Message Transfer @@ -13,7 +13,7 @@ was abused by the spammers, at that time it was not a big deal as today. With th e-commerce boom had came many new businesses, scamming methods, and problems. One of them is the spam which we have to face today in enormous quantities. -The main goal of this project is not to detect spam such as its, but to detect +The main goal of this project is not to detect spam itself, but to detect entities and clusters that are sending it. All this with just a flow data analysis without interfering a network user privacy. This system contains two modules. First a static module that will autonomously decide whether the entity is a sender, @@ -331,7 +331,7 @@ This module uses PEP 8 coding style ``` COPYRIGHT AND PERMISSION NOTICE -Copyright (C) 2016-2018 CESNET, z.s.p.o. +Copyright (C) 2016-2019 CESNET, z.s.p.o. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 3b06fc7269e8e6f2cf9df83ad93d4ea5f01c13fa Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Mon, 3 Jun 2019 12:10:09 +0200 Subject: [PATCH 05/40] Rework in progress --- brute_force_detector/brute_force_detector.cpp | 217 ++++++++---------- brute_force_detector/brute_force_detector.h | 52 ++++- brute_force_detector/config.cpp | 141 +++++++----- brute_force_detector/config.h | 77 ++++--- brute_force_detector/config/config.conf | 37 +-- brute_force_detector/host.cpp | 148 ++++-------- brute_force_detector/host.h | 66 +++--- brute_force_detector/record.h | 7 +- brute_force_detector/sender.cpp | 6 +- brute_force_detector/sender.h | 12 +- .../telnet_server_profile.cpp | 4 +- brute_force_detector/whitelist_unit_test.cpp | 10 +- nemea-detectors.spec.in | 6 - 13 files changed, 392 insertions(+), 391 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 7737741b..cdfd155c 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -42,7 +42,7 @@ * */ #ifdef HAVE_CONFIG_H -#include "../config.h" //include autogenerated config +#include "../config.h" // include autogenerated config #endif #include @@ -80,22 +80,22 @@ extern "C" { using namespace std; UR_FIELDS( - //BASIC_FLOW - ipaddr SRC_IP, //Source address of a flow - ipaddr DST_IP, //Destination address of a flow - uint16 SRC_PORT, //Source transport-layer port - uint16 DST_PORT, //Destination transport-layer port - uint8 PROTOCOL, //L4 protocol (TCP, UDP, ICMP, etc.) - uint32 PACKETS, //Number of packets in a flow or in an interval - uint64 BYTES, //Number of bytes in a flow or in an interval - time TIME_FIRST, //Timestamp of the first packet of a flow - time TIME_LAST, //Timestamp of the last packet of a flow - uint8 TCP_FLAGS, //TCP flags of a flow (logical OR over TCP flags field of all packets) + // BASIC_FLOW + ipaddr SRC_IP, // Source address of a flow + ipaddr DST_IP, // Destination address of a flow + uint16 SRC_PORT, // Source transport-layer port + uint16 DST_PORT, // Destination transport-layer port + uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint32 PACKETS, // Number of packets in a flow or in an interval + uint64 BYTES, // Number of bytes in a flow or in an interval + time TIME_FIRST, // Timestamp of the first packet of a flow + time TIME_LAST, // Timestamp of the last packet of a flow + uint8 TCP_FLAGS, // TCP flags of a flow (logical OR over TCP flags field of all packets) ) /* ************************************************************************* */ // Struct with information about module -trap_module_info_t *module_info = NULL; +trap_module_info_t *module_info = nullptr; TelnetServerProfileMap TELNETRecord::TSPMap; @@ -129,14 +129,14 @@ void signalHandler(int signal) if(!whitelist.isLockedForConfigurationReload()) whitelist.reloadWhitelist(); else - alarm(1); //cannot reload now.. wait + alarm(1); // cannot reload now.. wait } else if(signal == SIGALRM) { if(!whitelist.isLockedForConfigurationReload()) whitelist.reloadWhitelist(); else - alarm(1); //wait another second + alarm(1); // wait another second } } @@ -145,23 +145,26 @@ bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t actualTime) return oldTime + timer <= actualTime; } + void printFlowPercent(uint64_t b, uint64_t p) { - if (b && p) { - ios::fmtflags f(cout.flags()); - cout << " (" - << std::fixed << std::setprecision(2) - << 100.0 / b * p - << "%)"; - cout.flags(f); - } else { - cerr << "Attempted division by zero in printFlowPercent." << endl; - } + if (b && p) { + ios::fmtflags f(cout.flags()); + cout << " (" + << std::fixed << std::setprecision(2) + << 100.0 / b * p + << "%)"; + cout.flags(f); + } else { + cerr << "Attempted division by zero in printFlowPercent." << endl; + } } + int main(int argc, char **argv) { + getc(stdin); /// DEBUGGING // ***** TRAP initialization ***** int ret; INIT_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) @@ -175,19 +178,19 @@ int main(int argc, char **argv) sigemptyset (&sigAction.sa_mask); sigAction.sa_flags = 0; - //Prevent interruption of signal handler by another SIGTERM or SIGINT + // Prevent interruption of signal handler by another SIGTERM or SIGINT sigaddset(&sigAction.sa_mask, SIGTERM); sigaddset(&sigAction.sa_mask, SIGINT); sigaddset(&sigAction.sa_mask, SIGUSR1); sigaddset(&sigAction.sa_mask, SIGUSR2); sigaddset(&sigAction.sa_mask, SIGALRM); - //register signal handler - sigaction (SIGTERM, &sigAction, NULL); - sigaction (SIGINT , &sigAction, NULL); - sigaction (SIGUSR1, &sigAction, NULL); - sigaction (SIGUSR2, &sigAction, NULL); - sigaction (SIGALRM, &sigAction, NULL); + // register signal handler + sigaction (SIGTERM, &sigAction, nullptr); + sigaction (SIGINT , &sigAction, nullptr); + sigaction (SIGUSR1, &sigAction, nullptr); + sigaction (SIGUSR2, &sigAction, nullptr); + sigaction (SIGALRM, &sigAction, nullptr); #else signal(SIGTERM, signalHandler); signal(SIGINT, signalHandler); @@ -198,15 +201,15 @@ int main(int argc, char **argv) // ***** Parsing non TRAP arguments ***** signed char opt; - char *configFilePath = NULL; - char *whitelistFilePath = NULL; + char *configFilePath = nullptr; + char *whitelistFilePath = nullptr; bool whitelistParserVerbose = false; bool RDP = false, SSH = false, TELNET = false; while((opt = TRAP_GETOPT(argc, argv, module_getopt_string, long_options)) != -1) { switch (opt) { - case 'c': //config + case 'c': // config configFilePath = optarg; break; case 'w': @@ -238,7 +241,7 @@ int main(int argc, char **argv) } // ***** Config init ***** - if(configFilePath != NULL) + if(configFilePath != nullptr) { bool state = Config::getInstance().initFromFile(configFilePath); if(!state) @@ -250,7 +253,7 @@ int main(int argc, char **argv) } // ***** Whitelist init ***** - if(whitelistFilePath != NULL) + if(whitelistFilePath != nullptr) { bool state = whitelist.init(whitelistFilePath, whitelistParserVerbose); if (!state) @@ -264,11 +267,11 @@ int main(int argc, char **argv) // ***** Create UniRec template for input ***** std::string unirecSpecifier = "SRC_IP,DST_IP,SRC_PORT,DST_PORT,PROTOCOL,PACKETS,BYTES,TIME_FIRST,TIME_LAST,TCP_FLAGS"; - char *errstr = NULL; + char *errstr = nullptr; ur_template_t *tmplt = ur_create_input_template(0, unirecSpecifier.c_str(), &errstr); - if (tmplt == NULL) { + if (tmplt == nullptr) { cerr << "Error: Invalid UniRec specifier." << endl; - if(errstr != NULL){ + if(errstr != nullptr){ fprintf(stderr, "%s\n", errstr); free(errstr); } @@ -296,27 +299,10 @@ int main(int argc, char **argv) SSHHostMap sshHostMap; RDPHostMap rdpHostMap; TELNETHostMap telnetHostMap; - - uint64_t SSHTotalFlows = 0; - uint64_t SSHTotalIncomingFlows = 0; - uint64_t SSHTotalOutgoingFlows = 0; - uint64_t SSHTotalMatchedFlows = 0; - uint64_t SSHTotalMatchedIncomingFlows = 0; - uint64_t SSHTotalMatchedOutgoingFlows = 0; - - uint64_t RDPTotalFlows = 0; - uint64_t RDPTotalIncomingFlows = 0; - uint64_t RDPTotalOutgoingFlows = 0; - uint64_t RDPTotalMatchedFlows = 0; - uint64_t RDPTotalMatchedIncomingFlows = 0; - uint64_t RDPTotalMatchedOutgoingFlows = 0; - - uint64_t TELNETTotalFlows = 0; - uint64_t TELNETTotalIncomingFlows = 0; - uint64_t TELNETTotalOutgoingFlows = 0; - uint64_t TELNETTotalMatchedFlows = 0; - uint64_t TELNETTotalMatchedIncomingFlows = 0; - uint64_t TELNETTotalMatchedOutgoingFlows = 0; + + logInfo ssh("SSH"); + logInfo rdp("RDP"); + logInfo telnet("TELNET"); ur_time_t timeOfLastReportCheck = 0; ur_time_t timeOfLastDeleteCheck = 0; @@ -347,8 +333,8 @@ int main(int argc, char **argv) } } - //Skip non TCP flows - if(ur_get(tmplt, data, F_PROTOCOL) != TCP_PROTOCOL_NUM) //TCP flows only + // Skip non TCP flows + if(ur_get(tmplt, data, F_PROTOCOL) != TCP_PROTOCOL_NUM) // TCP flows only continue; uint16_t dstPort = ur_get(tmplt, data, F_DST_PORT); @@ -398,21 +384,21 @@ int main(int argc, char **argv) record = new SSHRecord(dstIp, flowLastSeen); state = record->matchWithIncomingSignature(&structure, &whitelist); if(state) - SSHTotalMatchedIncomingFlows++; - SSHTotalIncomingFlows++; + ssh.matchedIncomingFlows++; + ssh.incomingFlows++; } else { // FLOW_OUTGOING_DIRECTION record = new SSHRecord(srcIp, flowLastSeen); state = record->matchWithOutgoingSignature(&structure, &whitelist); if(state) - SSHTotalMatchedOutgoingFlows++; - SSHTotalOutgoingFlows++; + ssh.matchedOutgoingFlows++; + ssh.outgoingFlows++; } if(state) - SSHTotalMatchedFlows++; - SSHTotalFlows++; + ssh.matchedFlows++; + ssh.flows++; SSHHost *host = sshHostMap.findHost(&structure, direction); @@ -420,26 +406,26 @@ int main(int argc, char **argv) if(!state) delete record; else - { //check for attack - SSHHost::ATTACK_STATE attackState = host->checkForAttack(flowLastSeen); + { // check for attack + auto attackState = host->checkForAttack(flowLastSeen); if(attackState != SSHHost::NO_ATTACK) { if(attackState == SSHHost::NEW_ATTACK) ret = sender->firstReport(host, TCP_SSH_PORT, flowLastSeen, Config::getInstance().getSSHListThreshold()); else if(attackState == SSHHost::ATTACK_REPORT_WAIT || attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) { - //waiting for report timeout or min events to report - //no action + // waiting for report timeout or min events to report + // no action } else if(attackState == SSHHost::END_OF_ATTACK) { - //clear list + // clear list host->clearAllRecords(); host->setNotReported(); } else if(attackState == SSHHost::REPORT_END_OF_ATTACK) { - //report and clear list + // report and clear list ret = sender->continuingReport(host, TCP_SSH_PORT, flowLastSeen, true); host->clearAllRecords(); @@ -464,21 +450,21 @@ int main(int argc, char **argv) record = new RDPRecord(dstIp, flowLastSeen); state = record->matchWithIncomingSignature(&structure, &whitelist); if(state) - RDPTotalMatchedIncomingFlows++; - RDPTotalIncomingFlows++; + rdp.matchedIncomingFlows++; + rdp.incomingFlows++; } else { // FLOW_OUTGOING_DIRECTION record = new RDPRecord(srcIp, flowLastSeen); state = record->matchWithOutgoingSignature(&structure, &whitelist); if(state) - RDPTotalMatchedOutgoingFlows++; - RDPTotalOutgoingFlows++; + rdp.matchedOutgoingFlows++; + rdp.outgoingFlows++; } if(state) - RDPTotalMatchedFlows++; - RDPTotalFlows++; + rdp.matchedFlows++; + rdp.flows++; RDPHost *host = rdpHostMap.findHost(&structure, direction); @@ -486,7 +472,7 @@ int main(int argc, char **argv) if(!state) delete record; else - { //check for attack + { // check for attack RDPHost::ATTACK_STATE attackState = host->checkForAttack(flowLastSeen); if(attackState != RDPHost::NO_ATTACK) { @@ -494,8 +480,8 @@ int main(int argc, char **argv) ret = sender->firstReport(host, TCP_RDP_PORT, flowLastSeen, Config::getInstance().getRDPListThreshold()); else if(attackState == RDPHost::ATTACK_REPORT_WAIT || attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) { - //waiting for report timeout or min events to report - //no action + // waiting for report timeout or min events to report + // no action } else if(attackState == RDPHost::END_OF_ATTACK) { @@ -504,7 +490,7 @@ int main(int argc, char **argv) } else if(attackState == RDPHost::REPORT_END_OF_ATTACK) { - //report and clear list + // report and clear list ret = sender->continuingReport(host, TCP_RDP_PORT, flowLastSeen, true); host->clearAllRecords(); @@ -529,21 +515,21 @@ int main(int argc, char **argv) record = new TELNETRecord(dstIp, flowLastSeen); state = record->matchWithIncomingSignature(&structure, &whitelist); if(state) - TELNETTotalMatchedIncomingFlows++; - TELNETTotalIncomingFlows++; + telnet.matchedIncomingFlows++; + telnet.incomingFlows++; } else { // FLOW_OUTGOING_DIRECTION record = new TELNETRecord(srcIp, flowLastSeen); state = record->matchWithOutgoingSignature(&structure, &whitelist); if(state) - TELNETTotalMatchedOutgoingFlows++; - TELNETTotalOutgoingFlows++; + telnet.matchedOutgoingFlows++; + telnet.outgoingFlows++; } if(state) - TELNETTotalMatchedFlows++; - TELNETTotalFlows++; + telnet.matchedFlows++; + telnet.flows++; TELNETHost *host = telnetHostMap.findHost(&structure, direction); @@ -551,7 +537,7 @@ int main(int argc, char **argv) if(!state) delete record; else - { //check for attack + { // check for attack TELNETHost::ATTACK_STATE attackState = host->checkForAttack(flowLastSeen); if(attackState != TELNETHost::NO_ATTACK) { @@ -559,8 +545,8 @@ int main(int argc, char **argv) ret = sender->firstReport(host, TCP_TELNET_PORT, flowLastSeen, Config::getInstance().getTELNETListThreshold()); else if(attackState == TELNETHost::ATTACK_REPORT_WAIT || attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) { - //waiting for report timeout or min events to report - //no action + // waiting for report timeout or min events to report + // no action } else if(attackState == TELNETHost::END_OF_ATTACK) { @@ -569,7 +555,7 @@ int main(int argc, char **argv) } else if(attackState == TELNETHost::REPORT_END_OF_ATTACK) { - //report and clear list + // report and clear list ret = sender->continuingReport(host, TCP_TELNET_PORT, flowLastSeen, true); host->clearAllRecords(); @@ -583,7 +569,7 @@ int main(int argc, char **argv) } } - //check for timeout + // check for timeout if(checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flowLastSeen)) { timeOfLastReportCheck = flowLastSeen; @@ -607,53 +593,34 @@ int main(int argc, char **argv) telnetHostMap.deleteOldRecordAndHosts(flowLastSeen); } - //kontrola po odeslani + // kontrola po odeslani TRAP_DEFAULT_SEND_DATA_ERROR_HANDLING(ret, continue, break); } // ***** End of main processing loop ***** if(SSH) { - cout.imbue(std::locale(std::locale(), new thousandsSeparator)); - cout << "SSH Counter: " << SSHTotalFlows << endl; - cout << "SSH Incoming Counter: " << SSHTotalIncomingFlows; printFlowPercent(SSHTotalFlows, SSHTotalIncomingFlows); cout< + /** * \file brute_force_detector.h * \author Vaclav Pacholik @@ -55,6 +57,7 @@ const static uint16_t TCP_RDP_PORT = 3389; const static uint8_t FLOW_INCOMING_DIRECTION = 1; const static uint8_t FLOW_OUTGOING_DIRECTION = 2; +void printFlowPercent(uint64_t b, uint64_t p); //ip address comparison for std::map and std::set struct cmpByIpAddr { @@ -65,10 +68,55 @@ struct cmpByIpAddr { struct thousandsSeparator : std::numpunct { // use dot as separator - char do_thousands_sep() const { return '.'; } + char do_thousands_sep() const override { return '.'; } // digits are grouped by 3 digits each - std::string do_grouping() const { return "\3"; } + std::string do_grouping() const override { return "\3"; } +}; + + +class logInfo { +public: + + explicit logInfo(std::string _protocolName) : protocolName(std::move(_protocolName)), + flows(0), + incomingFlows(0), + outgoingFlows(0), + matchedFlows(0), + matchedIncomingFlows(0), + matchedOutgoingFlows(0) + {}; + + void printLogInfo(){ + std::cout << this->protocolName << std::endl; + std::cout.imbue(std::locale(std::locale(), new thousandsSeparator)); // TODO move elsewhere + std::cout << " Total Flows: " << this->flows << std::endl; + std::cout << " Incoming Flows: " << this->incomingFlows; + printFlowPercent(this->flows, this->incomingFlows); + std::cout << std::endl; + std::cout << " Outgoing Flows: " << this->outgoingFlows; + printFlowPercent(this->flows, this->outgoingFlows); + std::cout << std::endl; + std::cout << " Matched Flows: " << this->matchedFlows; + printFlowPercent(this->flows, this->matchedFlows); + std::cout << std::endl; + std::cout << " Matched Incoming Flows: " << this->matchedIncomingFlows; + printFlowPercent(this->matchedFlows, this->matchedIncomingFlows); + printFlowPercent(this->flows, this->matchedIncomingFlows); + std::cout << std::endl; + std::cout << " Matched Outgoing Flows: " << this->matchedOutgoingFlows; + printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows); + printFlowPercent(this->flows, this->matchedOutgoingFlows); + std::cout << std::endl; + } + + std::string protocolName; + uint64_t flows; + uint64_t incomingFlows; + uint64_t outgoingFlows; + uint64_t matchedFlows ; + uint64_t matchedIncomingFlows; + uint64_t matchedOutgoingFlows; }; #endif diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index 6a13c9c6..97e16e14 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -52,13 +52,15 @@ Config::Config() GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(60, 0); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(60, 0); GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10; - GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0; - GENERAL_IGNORE_FIRST_SEND = 0; + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0f; + GENERAL_IGNORE_FIRST_SEND = 0; + + GENERAL_MATCHED_FLOW_RATIO = 0.9f; //SSH SSH_LIST_SIZE = 1000; - SSH_LIST_SIZE_BOTTOM_TRESHOLD = 50; // There are two types of tresholds, first means how many records are in list [50/1000] - // and based on this value is set up TRESHOLD which detects if host is attacker or not + SSH_LIST_SIZE_BOTTOM_THRESHOLD = 50; // There are two types of thresholds, first means how many records are in list [50/1000] + // and based on this value is set up THRESHOLD which detects if host is attacker or not SSH_LIST_THRESHOLD = 30; SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); @@ -78,7 +80,7 @@ Config::Config() //RDP RDP_LIST_SIZE = 1000; - RDP_LIST_SIZE_BOTTOM_TRESHOLD = 50; + RDP_LIST_SIZE_BOTTOM_THRESHOLD = 50; RDP_LIST_THRESHOLD = 30; RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); @@ -99,7 +101,7 @@ Config::Config() //TELNET TELNET_LIST_SIZE = 1000; - TELNET_LIST_SIZE_BOTTOM_TRESHOLD = 50; + TELNET_LIST_SIZE_BOTTOM_THRESHOLD = 50; TELNET_LIST_THRESHOLD = 30; TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); @@ -119,10 +121,13 @@ Config::Config() kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = "GENERAL_ATTACK_MIN_EVENTS_TO_REPORT"; kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = "GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST"; kw_GENERAL_IGNORE_FIRST_SEND = "GENERAL_IGNORE_FIRST_SEND"; + kw_GENERAL_MATCHED_FLOW_RATIO = "GENERAL_MATCHED_FLOW_RATIO"; //SSH kw_SSH_LIST_SIZE = "SSH_LIST_SIZE"; kw_SSH_LIST_THRESHOLD = "SSH_LIST_THRESHOLD"; + kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD = "SSH_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_SSH_RECORD_TIMEOUT = "SSH_RECORD_TIMEOUT"; kw_SSH_HOST_TIMEOUT = "SSH_HOST_TIMEOUT"; kw_SSH_REPORT_TIMEOUT = "SSH_REPORT_TIMEOUT"; @@ -141,7 +146,9 @@ Config::Config() //RDP kw_RDP_LIST_SIZE = "RDP_LIST_SIZE"; kw_RDP_LIST_THRESHOLD = "RDP_LIST_THRESHOLD"; - kw_RDP_RECORD_TIMEOUT = "RDP_RECORD_TIMEOUT"; + kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD = "RDP_LIST_SIZE_BOTTOM_THRESHOLD"; + + kw_RDP_RECORD_TIMEOUT = "RDP_RECORD_TIMEOUT"; kw_RDP_HOST_TIMEOUT = "RDP_HOST_TIMEOUT"; kw_RDP_REPORT_TIMEOUT = "RDP_REPORT_TIMEOUT"; kw_RDP_ATTACK_TIMEOUT = "RDP_ATTACK_TIMEOUT"; @@ -159,7 +166,9 @@ Config::Config() //TELNET kw_TELNET_LIST_SIZE = "TELNET_LIST_SIZE"; kw_TELNET_LIST_THRESHOLD = "TELNET_LIST_THRESHOLD"; - kw_TELNET_RECORD_TIMEOUT = "TELNET_RECORD_TIMEOUT"; + kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD = "TELNET_LIST_SIZE_BOTTOM_THRESHOLD"; + + kw_TELNET_RECORD_TIMEOUT = "TELNET_RECORD_TIMEOUT"; kw_TELNET_HOST_TIMEOUT = "TELNET_HOST_TIMEOUT"; kw_TELNET_REPORT_TIMEOUT = "TELNET_REPORT_TIMEOUT"; kw_TELNET_ATTACK_TIMEOUT = "TELNET_ATTACK_TIMEOUT"; @@ -190,7 +199,7 @@ void Config::reloadConfig() } } -bool Config::initFromFile(string path) +bool Config::initFromFile(const string& path) { configPath = path; @@ -212,7 +221,7 @@ bool Config::initFromFile(string path) if(line[0] == '#') continue; //skip comment line - size_t pos = line.find("="); // = delimiter + size_t pos = line.find('='); // = delimiter if(pos == std::string::npos) { cerr << "Error Config: Invalid line \"" << line << "\"" << endl; @@ -227,205 +236,223 @@ bool Config::initFromFile(string path) keyword.erase(remove_if(keyword.begin(), keyword.end(), ::isspace), keyword.end()); value.erase(remove_if(value.begin(), value.end(), ::isspace), value.end()); - // GENERAL + // ********************* + // ****** GENERAL ****** + // ********************* if(keyword == kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) { - GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = strtoul(value.c_str(), NULL, 10); + GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = std::stoul(value, nullptr); } else if(keyword == kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) { - GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = atof(value.c_str()); + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = std::stod(value, nullptr); } else if(keyword == kw_GENERAL_IGNORE_FIRST_SEND) { - GENERAL_IGNORE_FIRST_SEND = strtoul(value.c_str(), NULL, 10); - } + GENERAL_IGNORE_FIRST_SEND = std::stoul(value, nullptr); + } + else if(keyword == kw_GENERAL_MATCHED_FLOW_RATIO) + { + GENERAL_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + } // ********************* // ******* SSH ********* // ********************* else if(keyword == kw_SSH_LIST_SIZE) { - SSH_LIST_SIZE = strtoul(value.c_str(), NULL, 10); + SSH_LIST_SIZE = std::stoul(value, nullptr); } else if(keyword == kw_SSH_LIST_THRESHOLD) { - SSH_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); + SSH_LIST_THRESHOLD = std::stoul(value, nullptr); + } + else if(keyword == kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD) + { + SSH_LIST_SIZE_BOTTOM_THRESHOLD = std::stoul(value, nullptr); } else if(keyword == kw_SSH_ATTACK_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_SSH_RECORD_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_SSH_HOST_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_SSH_REPORT_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); SSH_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) else if(keyword == kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) { - SSH_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + SSH_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) { - SSH_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + SSH_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_SSH_BRUTEFORCE_INC_MIN_BYTES) { - SSH_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + SSH_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); } else if(keyword == kw_SSH_BRUTEFORCE_INC_MAX_BYTES) { - SSH_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); + SSH_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); } // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) else if(keyword == kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) { - SSH_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + SSH_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) { - SSH_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + SSH_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) { - SSH_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + SSH_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, nullptr); } else if(keyword == kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) { - SSH_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 10); - } + SSH_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, nullptr); + } // ********************* // ******* RDP ********* // ********************* else if(keyword == kw_RDP_LIST_SIZE) { - RDP_LIST_SIZE = strtoul(value.c_str(), NULL, 10); + RDP_LIST_SIZE = std::stoul(value, nullptr); } else if(keyword == kw_RDP_LIST_THRESHOLD) { - RDP_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); + RDP_LIST_THRESHOLD = std::stoul(value, nullptr); } + else if(keyword == kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD) + { + RDP_LIST_SIZE_BOTTOM_THRESHOLD = std::stoul(value, nullptr); + } else if(keyword == kw_RDP_ATTACK_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_RDP_RECORD_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_RDP_HOST_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_RDP_REPORT_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); RDP_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) else if(keyword == kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) { - RDP_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + RDP_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) { - RDP_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + RDP_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_RDP_BRUTEFORCE_INC_MIN_BYTES) { - RDP_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + RDP_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); } else if(keyword == kw_RDP_BRUTEFORCE_INC_MAX_BYTES) { - RDP_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); + RDP_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); } // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) else if(keyword == kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) { - RDP_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + RDP_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) { - RDP_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + RDP_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) { - RDP_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + RDP_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, nullptr); } else if(keyword == kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) { - RDP_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 10); - } + RDP_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, nullptr); + } // ********************* // ****** TELNET ******* // ********************* else if(keyword == kw_TELNET_LIST_SIZE) { - TELNET_LIST_SIZE = strtoul(value.c_str(), NULL, 10); + TELNET_LIST_SIZE = std::stoul(value, nullptr); } else if(keyword == kw_TELNET_LIST_THRESHOLD) { - TELNET_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); + TELNET_LIST_THRESHOLD = std::stoul(value, nullptr); } + else if(keyword == kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD) + { + TELNET_LIST_SIZE_BOTTOM_THRESHOLD = std::stoul(value, nullptr); + } else if(keyword == kw_TELNET_ATTACK_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_TELNET_RECORD_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_TELNET_HOST_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_TELNET_REPORT_TIMEOUT) { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + uint32_t sec = std::stoul(value, nullptr); TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if(keyword == kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) { - TELNET_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + TELNET_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) { - TELNET_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + TELNET_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); } else if(keyword == kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) { - TELNET_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + TELNET_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); } else if(keyword == kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) { - TELNET_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); + TELNET_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); } // ********************* // ******* UNKNOWN ***** diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index 29fff9c5..5bb1aaf7 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -56,7 +56,7 @@ class Config { public: - bool initFromFile(std::string path); + bool initFromFile(const std::string& path); inline ur_time_t getGlobalTimerForReportCheck() const {return GENERAL_CHECK_FOR_REPORT_TIMEOUT;} inline ur_time_t getGlobalTimerForDeleteCheck() const {return GENERAL_CHECK_FOR_DELETE_TIMEOUT;} @@ -64,10 +64,11 @@ class Config { inline double getGlobalAttackMinRatioToKeepTrackingHost() const {return GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST;} inline int getGlobalIgnoreFirstSend() const {return GENERAL_IGNORE_FIRST_SEND;} - + inline double getGlobalMatchedFlowRatio() const {return GENERAL_MATCHED_FLOW_RATIO;} + //SSH inline uint16_t getSSHMaxListSize() const {return SSH_LIST_SIZE;} - inline uint16_t getSSHListBottomSize() const {return SSH_LIST_SIZE_BOTTOM_TRESHOLD;} + inline uint16_t getSSHListBottomSize() const {return SSH_LIST_SIZE_BOTTOM_THRESHOLD;} inline uint16_t getSSHListThreshold() const {return SSH_LIST_THRESHOLD;} inline ur_time_t getSSHRecordTimeout() const {return SSH_RECORD_TIMEOUT;} @@ -88,7 +89,7 @@ class Config { inline uint16_t getSSHBFOutMaxBytes() const {return SSH_BRUTEFORCE_OUT_MAX_BYTES;} //RDP - inline uint16_t getRDPListBottomSize() const {return RDP_LIST_SIZE_BOTTOM_TRESHOLD;} + inline uint16_t getRDPListBottomSize() const {return RDP_LIST_SIZE_BOTTOM_THRESHOLD;} inline uint16_t getRDPMaxListSize() const {return RDP_LIST_SIZE;} inline uint16_t getRDPListThreshold() const {return RDP_LIST_THRESHOLD;} inline ur_time_t getRDPRecordTimeout() const {return RDP_RECORD_TIMEOUT;} @@ -109,7 +110,7 @@ class Config { inline uint32_t getRDPBFOutMaxBytes() const {return RDP_BRUTEFORCE_OUT_MAX_BYTES;} //TELNET - inline uint16_t getTELNETListBottomSize() const {return TELNET_LIST_SIZE_BOTTOM_TRESHOLD;} + inline uint16_t getTELNETListBottomSize() const {return TELNET_LIST_SIZE_BOTTOM_THRESHOLD;} inline uint16_t getTELNETMaxListSize() const {return TELNET_LIST_SIZE;} inline uint16_t getTELNETListThreshold() const {return TELNET_LIST_THRESHOLD;} inline ur_time_t getTELNETRecordTimeout() const {return TELNET_RECORD_TIMEOUT;} @@ -140,17 +141,19 @@ class Config { uint16_t GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; double GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; uint8_t GENERAL_IGNORE_FIRST_SEND; + float GENERAL_MATCHED_FLOW_RATIO; std::string kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT; std::string kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT; std::string kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; std::string kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; std::string kw_GENERAL_IGNORE_FIRST_SEND; + std::string kw_GENERAL_MATCHED_FLOW_RATIO; //SSH uint16_t SSH_LIST_SIZE; uint16_t SSH_LIST_THRESHOLD; - uint16_t SSH_LIST_SIZE_BOTTOM_TRESHOLD; + uint16_t SSH_LIST_SIZE_BOTTOM_THRESHOLD; ur_time_t SSH_RECORD_TIMEOUT; ur_time_t SSH_HOST_TIMEOUT; @@ -170,6 +173,7 @@ class Config { //SSH keywords std::string kw_SSH_LIST_SIZE; std::string kw_SSH_LIST_THRESHOLD; + std::string kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD; std::string kw_SSH_RECORD_TIMEOUT; std::string kw_SSH_HOST_TIMEOUT; std::string kw_SSH_BRUTEFORCE_INC_MIN_PACKETS; @@ -184,35 +188,9 @@ class Config { std::string kw_SSH_ATTACK_TIMEOUT; - //TELNET - uint16_t TELNET_LIST_SIZE; - uint16_t TELNET_LIST_SIZE_BOTTOM_TRESHOLD; - uint16_t TELNET_LIST_THRESHOLD; - ur_time_t TELNET_RECORD_TIMEOUT; - ur_time_t TELNET_HOST_TIMEOUT; - ur_time_t TELNET_REPORT_TIMEOUT; - ur_time_t TELNET_ATTACK_TIMEOUT; - - uint16_t TELNET_BRUTEFORCE_INC_MIN_PACKETS; - uint16_t TELNET_BRUTEFORCE_INC_MAX_PACKETS; - uint16_t TELNET_BRUTEFORCE_INC_MIN_BYTES; - uint16_t TELNET_BRUTEFORCE_INC_MAX_BYTES; - - //TELNET keywords - std::string kw_TELNET_LIST_SIZE; - std::string kw_TELNET_LIST_THRESHOLD; - std::string kw_TELNET_RECORD_TIMEOUT; - std::string kw_TELNET_HOST_TIMEOUT; - std::string kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS; - std::string kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS; - std::string kw_TELNET_BRUTEFORCE_INC_MIN_BYTES; - std::string kw_TELNET_BRUTEFORCE_INC_MAX_BYTES; - std::string kw_TELNET_REPORT_TIMEOUT; - std::string kw_TELNET_ATTACK_TIMEOUT; - //RDP uint16_t RDP_LIST_SIZE; - uint16_t RDP_LIST_SIZE_BOTTOM_TRESHOLD; + uint16_t RDP_LIST_SIZE_BOTTOM_THRESHOLD; uint16_t RDP_LIST_THRESHOLD; ur_time_t RDP_RECORD_TIMEOUT; ur_time_t RDP_HOST_TIMEOUT; @@ -232,6 +210,7 @@ class Config { //RDP keywords std::string kw_RDP_LIST_SIZE; std::string kw_RDP_LIST_THRESHOLD; + std::string kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD; std::string kw_RDP_RECORD_TIMEOUT; std::string kw_RDP_HOST_TIMEOUT; std::string kw_RDP_BRUTEFORCE_INC_MIN_PACKETS; @@ -244,6 +223,36 @@ class Config { std::string kw_RDP_BRUTEFORCE_OUT_MAX_BYTES; std::string kw_RDP_REPORT_TIMEOUT; std::string kw_RDP_ATTACK_TIMEOUT; + + + //TELNET + uint16_t TELNET_LIST_SIZE; + uint16_t TELNET_LIST_SIZE_BOTTOM_THRESHOLD; + uint16_t TELNET_LIST_THRESHOLD; + ur_time_t TELNET_RECORD_TIMEOUT; + ur_time_t TELNET_HOST_TIMEOUT; + ur_time_t TELNET_REPORT_TIMEOUT; + ur_time_t TELNET_ATTACK_TIMEOUT; + + uint16_t TELNET_BRUTEFORCE_INC_MIN_PACKETS; + uint16_t TELNET_BRUTEFORCE_INC_MAX_PACKETS; + uint16_t TELNET_BRUTEFORCE_INC_MIN_BYTES; + uint16_t TELNET_BRUTEFORCE_INC_MAX_BYTES; + + //TELNET keywords + std::string kw_TELNET_LIST_SIZE; + std::string kw_TELNET_LIST_THRESHOLD; + std::string kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD; + + std::string kw_TELNET_RECORD_TIMEOUT; + std::string kw_TELNET_HOST_TIMEOUT; + std::string kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS; + std::string kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS; + std::string kw_TELNET_BRUTEFORCE_INC_MIN_BYTES; + std::string kw_TELNET_BRUTEFORCE_INC_MAX_BYTES; + std::string kw_TELNET_REPORT_TIMEOUT; + std::string kw_TELNET_ATTACK_TIMEOUT; + }; -#endif \ No newline at end of file +#endif diff --git a/brute_force_detector/config/config.conf b/brute_force_detector/config/config.conf index 67f011dd..1625ead9 100644 --- a/brute_force_detector/config/config.conf +++ b/brute_force_detector/config/config.conf @@ -8,35 +8,44 @@ ######################## ####### GENERAL ######## ######################## -## Every x seconds check for report timeout -#GENERAL_CHECK_FOR_REPORT_TIMEOUT = 60 -## Every x seconds check all Hosts/Records for host/record timeout -#GENERAL_CHECK_FOR_DELETE_TIMEOUT = 60 +## Every n seconds check for report timeout +# GENERAL_CHECK_FOR_REPORT_TIMEOUT = 60 +## +## Every n seconds check all Hosts/Records for host/record timeout +# GENERAL_CHECK_FOR_DELETE_TIMEOUT = 60 +## ## Minimum number of suspicious flows to report (continuous detection [not first detection]) ## Lower value can report more slow attacks -#GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10 +# GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10 +## ## Percentage threshold between suspicious and benign flows to keep track host ## If below threshold and after protocol_REPORT_TIMEOUT report end of attack -#GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0 +# GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0 +## ## Suppress reporting of first detection ## If set, attack scale will have to pass threshold ## "GENERAL_ATTACK_MIN_EVENTS_TO_REPORT". This option may decrease number of the ## false positive detections. 0/1 = false/true -#GENERAL_IGNORE_FIRST_SEND = 0 +# GENERAL_IGNORE_FIRST_SEND = 0 +## +## How much of the flow has to be suspicious to report an attack (sensitivity) +## In the range of (0;1]. (0 would mean everything is considered an attack) +# GENERAL_MATCHED_FLOW_RATIO = 0.9 ####################################### -## PROTOCOL X KEYWORDS INFORMATION ## -## -## X_ATTACK_TIMEOUT - After x seconds from last report set attack by given host +## PROTOCOL (X) KEYWORDS INFORMATION ## +## X -> SSH/RDP/TELNET +## +## X_ATTACK_TIMEOUT - After n seconds from last report set attack by given host ## as finished ## X_LIST_SIZE - Set number of max records(flows) that each host can store ## X_LIST_THRESHOLD - Set threshold for number of suspicious flows -## X_REPORT_TIMEOUT - Attacker can be reported again after x seconds. +## X_REPORT_TIMEOUT - Attacker can be reported again after n seconds. ## During this entire period attack information is agregated. ## X_ATTACK_TIMEOUT > X_REPORT_TIMEOUT ## -## X_RECORD_TIMEOUT - Delete record from memory after x seconds -## X_HOST_TIMEOUT - Delete host from memory after x seconds of inactivity +## X_RECORD_TIMEOUT - Delete record from memory after n seconds +## X_HOST_TIMEOUT - Delete host from memory after n seconds of inactivity ## Shorter timeout means smaller memory usage of these two ## aforementioned keywords. On the other hand detection of ## slower attacks could be worse @@ -99,4 +108,4 @@ #TELNET_BRUTEFORCE_INC_MIN_BYTES = 450 #TELNET_BRUTEFORCE_INC_MAX_BYTES = 3000 ## Outgoing version is not supported -#TELNET_REPORT_TIMEOUT = 300 \ No newline at end of file +#TELNET_REPORT_TIMEOUT = 300 diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index b6981dd8..7c6d191e 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -71,28 +71,21 @@ bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { - uint16_t numOfCurrentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t numOfCurrentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); + uint16_t currentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); + uint16_t currentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); if(!isReported()) { //no attack yet uint16_t actualListSizeInc = recordListIncoming.getActualNumOfListSize(); uint16_t actualListSizeOut = recordListOutgoing.getActualNumOfListSize(); - /* - if (actualListSizeInc > 50 || actualListSizeOut > 50) { - cout << "First Seen " << std::endl; - cout << "Actual list size incoming: " << actualListSizeInc << std::endl; - cout << "Actual list size outgoing: " << actualListSizeOut << std::endl; - cout << "Number of matched incoming flows: " << numOfCurrentIncomingMF << std::endl; - cout << "Number of matched outgoing flows: " << numOfCurrentOutgoingMF << std::endl; - }*/ - - //Number of records in list is lower than BottomSize, 50 ussually + + + //Number of records in list is lower than BottomSize (set to 50 by default) if ( actualListSizeInc <= Config::getInstance().getSSHListBottomSize() || actualListSizeOut <= Config::getInstance().getSSHListBottomSize()) { - if( numOfCurrentIncomingMF >= Config::getInstance().getSSHListThreshold() || - numOfCurrentOutgoingMF >= Config::getInstance().getSSHListThreshold()) { + if( currentIncomingMF >= Config::getInstance().getSSHListThreshold() || + currentOutgoingMF >= Config::getInstance().getSSHListThreshold()) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -104,25 +97,11 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } //Number of records is between bottom size and max size } else { - uint16_t SSH_LIST_TOP_TRESHOLD = 0; - - if (actualListSizeInc > actualListSizeOut) { - if (actualListSizeInc < 100) { - double tmpRatio = ( actualListSizeInc % 100 ) * 0.9; - SSH_LIST_TOP_TRESHOLD = tmpRatio; - } else { - SSH_LIST_TOP_TRESHOLD = (actualListSizeInc / 100) * 90; - } - } else { - if (actualListSizeOut < 100) { - double tmpRatio = ( actualListSizeOut % 100 ) * 0.9; - SSH_LIST_TOP_TRESHOLD = tmpRatio; - } else { - SSH_LIST_TOP_TRESHOLD = (actualListSizeOut / 100) * 90; - } - } - if(numOfCurrentIncomingMF >= SSH_LIST_TOP_TRESHOLD || numOfCurrentOutgoingMF >= SSH_LIST_TOP_TRESHOLD) { + auto SSH_LIST_TOP_THRESHOLD = (uint16_t) (std::max(actualListSizeInc, actualListSizeOut) * + Config::getInstance().getGlobalMatchedFlowRatio()); + + if(currentIncomingMF >= SSH_LIST_TOP_THRESHOLD || currentOutgoingMF >= SSH_LIST_TOP_THRESHOLD) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); @@ -134,9 +113,9 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } } else - { //host is attacking, check for report timeout + { //host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) - //timeout nevyprsel, report pripadne pozdeji + return SSHHost::ATTACK_REPORT_WAIT; else { @@ -146,8 +125,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) uint32_t outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); - if(numOfCurrentIncomingMF == 0 && incomingAttackScale == 0 && - numOfCurrentOutgoingMF == 0 && outgoingAttackScale == 0) + if(currentIncomingMF == 0 && incomingAttackScale == 0 && + currentOutgoingMF == 0 && outgoingAttackScale == 0) return SSHHost::END_OF_ATTACK; double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); @@ -201,8 +180,8 @@ bool RDPHost::addRecord(RDPRecord *record, void *structure, uint8_t direction) RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { - uint16_t numOfCurrentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t numOfCurrentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); + uint16_t currentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); + uint16_t currentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); if(!isReported()) { //no attack yet @@ -212,8 +191,8 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) if (actualListSizeInc <= Config::getInstance().getRDPListBottomSize() || actualListSizeOut <= Config::getInstance().getRDPListBottomSize()) { - if(numOfCurrentIncomingMF >= Config::getInstance().getRDPListThreshold() || - numOfCurrentOutgoingMF >= Config::getInstance().getRDPListThreshold()) { + if(currentIncomingMF >= Config::getInstance().getRDPListThreshold() || + currentOutgoingMF >= Config::getInstance().getRDPListThreshold()) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -224,25 +203,10 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) } //Number of records is between bottom size and max size } else { - uint16_t RDP_LIST_TOP_TRESHOLD = 0; - - if (actualListSizeInc > actualListSizeOut) { - if (actualListSizeInc < 100) { - double tmpRatio = ( actualListSizeInc % 100 ) * 0.9; - RDP_LIST_TOP_TRESHOLD = tmpRatio; - } else { - RDP_LIST_TOP_TRESHOLD = (actualListSizeInc / 100) * 90; - } - } else { - if (actualListSizeOut < 100) { - double tmpRatio = ( actualListSizeOut % 100 ) * 0.9; - RDP_LIST_TOP_TRESHOLD = tmpRatio; - } else { - RDP_LIST_TOP_TRESHOLD = (actualListSizeOut / 100) * 90; - } - } + auto RDP_LIST_TOP_THRESHOLD = (uint16_t) (std::max(actualListSizeInc, actualListSizeOut) * + Config::getInstance().getGlobalMatchedFlowRatio()); - if (numOfCurrentIncomingMF >= RDP_LIST_TOP_TRESHOLD || numOfCurrentOutgoingMF >= RDP_LIST_TOP_TRESHOLD) { + if (currentIncomingMF >= RDP_LIST_TOP_THRESHOLD || currentOutgoingMF >= RDP_LIST_TOP_THRESHOLD) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); @@ -253,9 +217,9 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) } } else - { //host is attacking, check for report timeout + { //host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) - //timeout nevyprsel, report pripadne pozdeji + return RDPHost::ATTACK_REPORT_WAIT; else { @@ -265,8 +229,8 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) uint32_t outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); - if(numOfCurrentIncomingMF == 0 && incomingAttackScale == 0 && - numOfCurrentOutgoingMF == 0 && outgoingAttackScale == 0) + if(currentIncomingMF == 0 && incomingAttackScale == 0 && + currentOutgoingMF == 0 && outgoingAttackScale == 0) return RDPHost::END_OF_ATTACK; double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); @@ -320,8 +284,8 @@ bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direct TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { - uint16_t numOfCurrentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t numOfCurrentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); + uint16_t currentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); + uint16_t currentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); if(!isReported()) { //no attack yet @@ -331,8 +295,8 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) if (actualListSizeInc <= Config::getInstance().getTELNETListBottomSize() || actualListSizeOut <= Config::getInstance().getTELNETListBottomSize()) { - if(numOfCurrentIncomingMF >= Config::getInstance().getTELNETListThreshold() || - numOfCurrentOutgoingMF >= Config::getInstance().getTELNETListThreshold()) { + if(currentIncomingMF >= Config::getInstance().getTELNETListThreshold() || + currentOutgoingMF >= Config::getInstance().getTELNETListThreshold()) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); @@ -342,25 +306,11 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) } //Number of records is between bottom size and max size } else { - uint16_t TELNET_LIST_TOP_TRESHOLD = 0; - - if (actualListSizeInc > actualListSizeOut) { - if (actualListSizeInc < 100) { - double tmpRatio = ( actualListSizeInc % 100 ) * 0.9; - TELNET_LIST_TOP_TRESHOLD = tmpRatio; - } else { - TELNET_LIST_TOP_TRESHOLD = (actualListSizeInc / 100) * 90; - } - } else { - if (actualListSizeOut < 100) { - double tmpRatio = ( actualListSizeOut % 100 ) * 0.9; - TELNET_LIST_TOP_TRESHOLD = tmpRatio; - } else { - TELNET_LIST_TOP_TRESHOLD = (actualListSizeOut / 100) * 90; - } - } - if(numOfCurrentIncomingMF >= TELNET_LIST_TOP_TRESHOLD || numOfCurrentOutgoingMF >= TELNET_LIST_TOP_TRESHOLD) { + auto TELNET_LIST_TOP_THRESHOLD = (uint16_t) (std::max(actualListSizeInc, actualListSizeOut) * + Config::getInstance().getGlobalMatchedFlowRatio()); + + if(currentIncomingMF >= TELNET_LIST_TOP_THRESHOLD || currentOutgoingMF >= TELNET_LIST_TOP_THRESHOLD) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); @@ -371,9 +321,9 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) } } else - { //host is attacking, check for report timeout + { //host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) - //timeout nevyprsel, report pripadne pozdeji + return TELNETHost::ATTACK_REPORT_WAIT; else { @@ -383,18 +333,18 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) uint32_t outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); - if(numOfCurrentIncomingMF == 0 && incomingAttackScale == 0 && - numOfCurrentOutgoingMF == 0 && outgoingAttackScale == 0) + if(currentIncomingMF == 0 && incomingAttackScale == 0 && + currentOutgoingMF == 0 && outgoingAttackScale == 0) return TELNETHost::END_OF_ATTACK; double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); double incomingPer = 0.0; - if(incomingTotalFlows > 0.0) + if(incomingTotalFlows > 0) incomingPer = (100.0 / incomingTotalFlows) * incomingAttackScale; double outgoingPer = 0.0; - if(outgoingTotalFlows > 0.0) + if(outgoingTotalFlows > 0) outgoingPer = (100.0 / outgoingTotalFlows) * outgoingAttackScale; if (incomingPer < configRatio && outgoingPer < configRatio) @@ -427,7 +377,7 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct else ip = structure->dstIp; //attacker is now destination address - std::map::iterator it = hostMap.find(ip); + auto it = hostMap.find(ip); SSHHost *host; @@ -444,9 +394,9 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for (std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) + for (const auto & it : hostMap) { - SSHHost *host = it->second; + SSHHost *host = it.second; if(host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getNumOfMatchedFlowsSinceLastReport(); @@ -477,7 +427,7 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct else ip = structure->dstIp; //attacker is now destination address - std::map::iterator it = hostMap.find(ip); + auto it = hostMap.find(ip); RDPHost *host; @@ -494,9 +444,9 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for(std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) + for(const auto & it : hostMap) { - RDPHost *host = it->second; + RDPHost *host = it.second; if(host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getNumOfMatchedFlowsSinceLastReport(); @@ -527,7 +477,7 @@ TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t else ip = structure->dstIp; //attacker is now destination address - std::map::iterator it = hostMap.find(ip); + auto it = hostMap.find(ip); TELNETHost *host; @@ -544,9 +494,9 @@ TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for(std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) + for(const auto & it : hostMap) { - TELNETHost *host = it->second; + TELNETHost *host = it.second; if(host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getNumOfMatchedFlowsSinceLastReport(); diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 7836e9ed..5540256e 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -71,7 +71,7 @@ class IHost { scanned = false; } - virtual ~IHost() {} + virtual ~IHost() = default; enum ATTACK_STATE { NO_ATTACK, NEW_ATTACK, ATTACK_REPORT_WAIT, ATTACK, ATTACK_MIN_EVENTS_WAIT, END_OF_ATTACK, REPORT_END_OF_ATTACK}; @@ -79,14 +79,14 @@ class IHost { inline ip_addr_t getHostIp() { return hostIp; } inline ur_time_t getTimeOfLastReport() { return timeOfLastReport; } inline bool isReported() { return timeOfLastReport != 0; } - inline void setReportTime(ur_time_t actualTime) { timeOfLastReport = actualTime; } + inline void setReportTime(ur_time_t actualTime) { timeOfLastReport = actualTime; } inline void setNotReported() { timeOfLastReport = 0; recordListIncoming.clearNumOfTotalTargetsSinceAttack(); recordListOutgoing.clearNumOfTotalTargetsSinceAttack(); } - + inline bool getHostScannedNetwork() { return scanned; } virtual bool addRecord(T record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) @@ -145,7 +145,7 @@ class IHost { virtual void clearAllRecords() { recordListIncoming.clearAllRecords(); recordListOutgoing.clearAllRecords();} - bool isFlowScan(uint32_t *packets, uint8_t *flags) + bool isFlowScan(const uint32_t *packets, const uint8_t *flags) { if((*packets == 1 && *flags == 0b00000010) //SYN || (*packets == 2 && *flags == 0b00000010) //SYN @@ -183,11 +183,11 @@ class SSHHost : public IHost { public: SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} - virtual bool addRecord(SSHRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - virtual ATTACK_STATE checkForAttack(ur_time_t actualTime); - virtual ur_time_t getHostDeleteTimeout() { return Config::getInstance().getSSHHostTimeout(); } - virtual ur_time_t getHostReportTimeout() { return Config::getInstance().getSSHReportTimeout(); } - virtual ur_time_t getHostAttackTimeout() { return Config::getInstance().getSSHAttackTimeout(); } + bool addRecord(SSHRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostTimeout(); } + ur_time_t getHostReportTimeout() override { return Config::getInstance().getSSHReportTimeout(); } + ur_time_t getHostAttackTimeout() override { return Config::getInstance().getSSHAttackTimeout(); } }; class RDPHost : public IHost { @@ -195,11 +195,11 @@ class RDPHost : public IHost { public: RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} - virtual bool addRecord(RDPRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - virtual ATTACK_STATE checkForAttack(ur_time_t actualTime); - virtual ur_time_t getHostDeleteTimeout() { return Config::getInstance().getRDPHostTimeout(); } - virtual ur_time_t getHostReportTimeout() { return Config::getInstance().getRDPReportTimeout(); } - virtual ur_time_t getHostAttackTimeout() { return Config::getInstance().getRDPAttackTimeout(); } + bool addRecord(RDPRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostTimeout(); } + ur_time_t getHostReportTimeout() override { return Config::getInstance().getRDPReportTimeout(); } + ur_time_t getHostAttackTimeout() override { return Config::getInstance().getRDPAttackTimeout(); } }; class TELNETHost : public IHost { @@ -207,11 +207,11 @@ class TELNETHost : public IHost { public: TELNETHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} - virtual bool addRecord(TELNETRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - virtual ATTACK_STATE checkForAttack(ur_time_t actualTime); - virtual ur_time_t getHostDeleteTimeout() { return Config::getInstance().getTELNETHostTimeout(); } - virtual ur_time_t getHostReportTimeout() { return Config::getInstance().getTELNETReportTimeout(); } - virtual ur_time_t getHostAttackTimeout() { return Config::getInstance().getTELNETAttackTimeout(); } + bool addRecord(TELNETRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostTimeout(); } + ur_time_t getHostReportTimeout() override { return Config::getInstance().getTELNETReportTimeout(); } + ur_time_t getHostAttackTimeout() override { return Config::getInstance().getTELNETAttackTimeout(); } }; @@ -222,8 +222,8 @@ class TELNETHost : public IHost { class IHostMap { public: - IHostMap() {} - ~IHostMap() {} + IHostMap() = default; + ~IHostMap() = default; virtual void clear() = 0; virtual inline uint16_t size() = 0; @@ -273,18 +273,18 @@ class SSHHostMap : public IHostMap { SSHHostMap() = default; ~SSHHostMap() = default; - virtual void clear() + void clear() override { IHostMap::clearMap(&hostMap); } - virtual inline uint16_t size() + inline uint16_t size() override { return hostMap.size(); } SSHHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - virtual void deleteOldRecordAndHosts(ur_time_t actualTime); - virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: map hostMap; @@ -296,19 +296,19 @@ class RDPHostMap: public IHostMap { RDPHostMap() = default; ~RDPHostMap() = default; - virtual void clear() + void clear() override { IHostMap::clearMap(&hostMap); } - virtual inline uint16_t size() + inline uint16_t size() override { return hostMap.size(); } RDPHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - virtual void deleteOldRecordAndHosts(ur_time_t actualTime); - virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: map hostMap; @@ -321,19 +321,19 @@ class TELNETHostMap: public IHostMap { TELNETHostMap() = default; ~TELNETHostMap() = default; - virtual void clear() + void clear() override { IHostMap::clearMap(&hostMap); } - virtual inline uint16_t size() + inline uint16_t size() override { return hostMap.size(); } TELNETHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - virtual void deleteOldRecordAndHosts(ur_time_t actualTime); - virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: map hostMap; diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 6cce7376..5301c2c6 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -177,14 +177,11 @@ class RecordList { std::set hashedDstIPSet; std::set hashedDstTotalIPSet; - char str[46]; + char str[46]; // TODO annotate bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) { - if(flowTime + timer <= actualTime) - return true; - else - return false; + return flowTime + timer <= actualTime; } }; diff --git a/brute_force_detector/sender.cpp b/brute_force_detector/sender.cpp index e06e5401..9b4464cf 100644 --- a/brute_force_detector/sender.cpp +++ b/brute_force_detector/sender.cpp @@ -59,8 +59,8 @@ Sender::Sender(bool *success) { std::string unirecSpecifier = "DETECTION_TIME,WARDEN_TYPE,SRC_IP,PROTOCOL,DST_PORT,EVENT_SCALE,NOTE"; - outTemplate = ur_create_output_template(0, unirecSpecifier.c_str(), NULL); - if(outTemplate == NULL) + outTemplate = ur_create_output_template(0, unirecSpecifier.c_str(), nullptr); + if(outTemplate == nullptr) { *success = false; return; @@ -70,7 +70,7 @@ Sender::Sender(bool *success) Sender::~Sender() { - if(outTemplate != NULL) + if(outTemplate != nullptr) ur_free_template (outTemplate); } diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index 97b0689a..913321b2 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -71,7 +71,7 @@ using namespace std; class Sender { public: - Sender(bool *success); + explicit Sender(bool *success); ~Sender(); template @@ -113,7 +113,7 @@ class Sender ur_template_t *outTemplate; template - int send(Host *host, uint16_t dstPort, ur_time_t actualTime, uint32_t intensity, bool endOfAttack = false, string stringNote = string()) + int send(Host *host, uint16_t dstPort, ur_time_t actualTime, uint32_t intensity, bool endOfAttack = false, const string& stringNote = string()) { vector incIpsVictims = host->getPointerToIncomingRecordList()->getIpsOfVictims(); vector outIpsVictims = host->getPointerToOutgoingRecordList()->getIpsOfVictims(); @@ -127,15 +127,15 @@ class Sender //Incoming note.append("I:"); - for (unsigned int i = 0; i < incIpsVictims.size(); i++) { - note.append(incIpsVictims.at(i)); + for (const auto & incIpsVictim : incIpsVictims) { + note.append(incIpsVictim); note.append(","); } //Outgoing note.append("O:"); - for (unsigned int i = 0; i < outIpsVictims.size(); i++) { - note.append(outIpsVictims.at(i)); + for (const auto & outIpsVictim : outIpsVictims) { + note.append(outIpsVictim); note.append(","); } note.erase(note.length(),1); diff --git a/brute_force_detector/telnet_server_profile.cpp b/brute_force_detector/telnet_server_profile.cpp index b9de4a98..0e464df1 100644 --- a/brute_force_detector/telnet_server_profile.cpp +++ b/brute_force_detector/telnet_server_profile.cpp @@ -120,9 +120,9 @@ TelnetServerProfile * TelnetServerProfileMap::createProfile(ip_addr_t ip, ur_tim TelnetServerProfile * TelnetServerProfileMap::findProfile(ip_addr_t & hostIp) const { - std::map::const_iterator it = TSPMap.find(hostIp); + auto it = TSPMap.find(hostIp); if(it == TSPMap.end()) - return NULL; + return nullptr; return it->second; } diff --git a/brute_force_detector/whitelist_unit_test.cpp b/brute_force_detector/whitelist_unit_test.cpp index 15334feb..a034c9d5 100644 --- a/brute_force_detector/whitelist_unit_test.cpp +++ b/brute_force_detector/whitelist_unit_test.cpp @@ -49,12 +49,12 @@ using namespace std; //init and delete WL for new test instance #define WL() { \ - if(wl!=NULL) \ + if(wl!=nullptr) \ { \ delete wl; \ - wl = NULL; \ + wl = nullptr; \ } \ - if(wl == NULL) \ + if(wl == nullptr) \ wl = new Whitelist(); \ parser = wl->getPointerToParser(); \ } @@ -67,7 +67,7 @@ uint16_t getRandomPort(){return rand() % 65536;} int failCounter = 0; -void subTestRes(int testNum, string state) +void subTestRes(int testNum, const string& state) { //cout <<"Subtest "<< testNum <<": "<< state << endl; if (state == "fail") failCounter++; @@ -76,7 +76,7 @@ void subTestRes(int testNum, string state) int main() { - Whitelist *wl = NULL; + Whitelist *wl = nullptr; WhitelistParser *parser; srand(0); diff --git a/nemea-detectors.spec.in b/nemea-detectors.spec.in index ffca9ecf..07b2f9ef 100644 --- a/nemea-detectors.spec.in +++ b/nemea-detectors.spec.in @@ -1,13 +1,7 @@ -%if 0%{?el6} -%global python3_pkgversion 34 -%endif - %if x%{?python3_pkgversion} == x %global python3_pkgversion 3 %endif - - Summary: Package with detection modules of the Nemea system Name: nemea-detectors Version: @PACKAGE_VERSION@ From 38c115f81c42162773268c14b7f45956deba264b Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Mon, 3 Jun 2019 12:10:33 +0200 Subject: [PATCH 06/40] Changes I did not make --- blacklistfilter/Makefile.am | 4 +- blacklistfilter/adaptive_filter/README.md | 122 +++++++++++- .../blacklist_aggregator.py | 0 .../blacklist_downloader/README.md | 177 +++++++++++++++++- blacklistfilter/dnsdetect/README.md | 109 +++++++++++ .../dnsdetect/dnsdetect_config.xml | 10 +- blacklistfilter/hostrecvwarden.pl | 42 ----- blacklistfilter/ipdetect/README.md | 70 ++++++- blacklistfilter/ipdetect/ipdetect_config.xml | 4 +- blacklistfilter/urldetect/README.md | 80 ++++++-- .../urldetect/urldetect_config.xml | 9 +- 11 files changed, 545 insertions(+), 82 deletions(-) rename blacklistfilter/{ => blacklist_aggregator}/blacklist_aggregator.py (100%) delete mode 100644 blacklistfilter/hostrecvwarden.pl diff --git a/blacklistfilter/Makefile.am b/blacklistfilter/Makefile.am index 908b9ca3..ad973e6d 100644 --- a/blacklistfilter/Makefile.am +++ b/blacklistfilter/Makefile.am @@ -38,7 +38,7 @@ urlblacklistfilter_CXXFLAGS=-std=c++11 -Wall -pedantic urlblacklistfiltersysconfdir=${sysconfdir}/blacklistfilter dist_urlblacklistfiltersysconf_DATA=urldetect/urldetect_config.xml -EXTRA_DIST=blacklist_aggregator.py \ +EXTRA_DIST=blacklist_aggregator/blacklist_aggregator.py \ blacklist_downloader/bl_downloader.py.in \ blacklist_downloader/bl_downloader_config.xml \ urldetect/patternstrings.h \ @@ -51,7 +51,7 @@ EXTRA_DIST=blacklist_aggregator.py \ dnsdetect/README.md \ dnsdetect/dnsdetect_config.xml -bin_SCRIPTS=blacklist_downloader/bl_downloader.py blacklist_aggregator.py +bin_SCRIPTS=blacklist_downloader/bl_downloader.py blacklist_aggregator/blacklist_aggregator.py dist_blacklistfilter_DATA=blacklist_downloader/bl_downloader_config.xml diff --git a/blacklistfilter/adaptive_filter/README.md b/blacklistfilter/adaptive_filter/README.md index df6b066d..2b7ec9ff 100644 --- a/blacklistfilter/adaptive_filter/README.md +++ b/blacklistfilter/adaptive_filter/README.md @@ -1,2 +1,120 @@ -## Adaptive filter -# TODO \ No newline at end of file +# Adaptive filter + +Adaptive filter is the heart of the [blacklistfilter suite](../README.md). It receives all the detected events from +detectors (IP/URL/DNS) and decides whether the detection event will be reported to the Warden, or whether the event +needs further analysis of the suspicious client's traffic (who communicated with blacklisted entity). This is achieved with +so called `scenarios`, where these situations are defined. + + +![Big picture](../doc/big_picture.png) + + +## Usage: + +``` +Usage: adaptive_filter -i [-c ] [-e ] [-p ] + [-l ] [-a ] +``` + +- **blacklist_config**: Path to config file of the blacklist downloader (default: /etc/nemea/blacklistfilter/bl_downloader_config.xml) +- **evidence_timeout**: Timeout in seconds, meaning how long shall be the client monitored when the some matches (default: 600) +- **process_interval**: Timeout in seconds, meaning how often the adaptive filter processes new scenario events (default: 30) +- **log_level**: Standard logging level, 10=DEBUG, 20=INFO, etc. (default: 20) +- **adaptive_blacklist**: Path to the adaptive blacklist (default: /tmp/blacklistfilter/adaptive.blist) + + +## Interfaces +Inputs + - 0: FMT_JSON - "aggregated_blacklist" - aggregated IP/URL events + - 1: DNS flows - non-aggregated flows from DNS detector + +Outputs + - 0: FMT_JSON - "aggregated_blacklist" - sending events to Reporter + - 1: FMT_JSON - "blacklist_evidence" - sending events to Evidence + +## Scenarios +The scenarios define what cases trigger further monitoring of clients' traffic. +Every scenario has its defining key and a set of matching conditions. There are 2 scenarios so far. +For future reference, the class is called _scenario_, the instance is then called _scenario event_. +Also, beware the difference between _scenario event_ and _grouped event_. + +![Scenario model](../doc/scenario.png) + +### Attributes +- ID: UUID of the scenario event +- event_type: Scenario event type (BotnetDetection, DNSDetection, ..) +- grouped_events: A list of the events with the same key (in the same evidence timeout window). E.g. two distinct events + coming from the blacklist aggregator, where the source of trouble is the same C&C server (BotnetDetection scenario) +- grouped_events_cnt: Count of the grouped events +- first_detections_ts: Timestamp of the first grouped event +- last_detections_ts: Timestamp of the last grouped event +- processed_ts: Timestamp of the last scenario event processing +- adaptive_entities: Adaptive entities for the scenario event. E.g. a list of IPs who communicated with the C&C + + +### BotnetDetection +This scenario aims to analyze traffic of the clients who communicated with some C&C server. + +Key: + - IP address of the C&C server + +Matching conditions: + - The detection came from the IP/URL interface ("aggregated_blacklist") + - The detection type is "ip" + - The blacklist has a category Intrusion.Botnet + +### DNSDetection +This scenario aims to catch the DNS queries to blacklisted domains, translate them to IP addresses and then analyze +traffic with these addresses and try to identify the originator of the query. This is necessary because we cannot +report directly the SRC_IP of the DNS query to the blacklisted domain, since the SRC_IP is a recursive DNS resolver. +Key: + - Domain name +Matching conditions: + - The detection came from the DNS interface + + +## Operation +### Recieving events +- Adaptive filter listens for detection events from IP/URL detectors (aggregated) and from DNS detector (non-aggregated) +- Upon each received detection event, it is checked against defined scenarios, whether there is a match +- If not, the event is only passed to the Reporter and nothing is stored +- If yes, new `scenario_event` is created or an existing is updated. These scenario events are stored internally + +### Processing events +- Every `process_interval`, all the stored scenario events are checked +- Processing event means: + - Ensuring all the adaptive entities are up to date (when there is a new grouped event) + - Exporting the scenario event to Evidence when evidence timeout expired + - Creating new detector file (adaptive blacklist) when any of the above two actions happened (adding/removing entries + in the adaptive blacklist) + +### Adaptive IP detector +Adaptive IP detector is a normal IP detector except it uses a different format of the detector file (adaptive_blacklist). +There is also an event ID for each entry. When new detector file is created by the adaptive filter. Adaptive IP detector reloads the entries and starts detection +(like the normal IP detector). But these detections are then stored in Evidence (see the "Big picture" above). + + +## Evidence +The Evidence consists of two files: +- `evidence_detection`: All the scenario events stored by the Adaptive filter. Every time the evidence timeout expires for +the current event, this event is exported to this file. +- `evidence_adaptive`: All the adaptive events corresponding to the scenario events. I.e. the traffic of the suspicious clients + +The scenario events and adaptive events can be paired using the event ID. + +### Evaluation (experimental) +The offline evaluation can be done using the Evaluator script. This script loads the two files and tries to find some +patterns in the communication, these are: +- Flow count of the client and the C&C communication +- Flow count of the client and some other C&Cs communication +- Count of flows with IRC ports +- Information about the client from the [NERD](nerd.cesnet.cz) system + + +``` +Usage: evaluator.py -i [-c ] [-4 ] [-n ] +``` + +#### Example output of Evaluator + +![Evaluator](../doc/evaluator.png) diff --git a/blacklistfilter/blacklist_aggregator.py b/blacklistfilter/blacklist_aggregator/blacklist_aggregator.py similarity index 100% rename from blacklistfilter/blacklist_aggregator.py rename to blacklistfilter/blacklist_aggregator/blacklist_aggregator.py diff --git a/blacklistfilter/blacklist_downloader/README.md b/blacklistfilter/blacklist_downloader/README.md index 6742d77e..a2dafd10 100644 --- a/blacklistfilter/blacklist_downloader/README.md +++ b/blacklistfilter/blacklist_downloader/README.md @@ -9,7 +9,7 @@ along with the list of blacklists to download. ## How it works By default, the downloader fetches the blacklists every 10 minutes. If there is an update of some -blacklist, it creates a new file for the detector. This file is preprocessed by the downloader, so that +blacklist, it creates a new file(s) for the detector(s). This file is preprocessed by the downloader, so that the detector can just read it and start the detection. Preprocessing means: one entity per line, adding blacklist indexes to the entities, trimming whitespaces, sorting the entities,.. @@ -17,4 +17,177 @@ There are 3 types of blacklists: IP/URL/DNS. However, the URL detector also dete ## Usage: -Just run the script without arguments +``` +Usage: bl_downloader.py [-c ] [-r ] [-l ] +``` + +## Configuration +Is done via configuration file (command-line options override config file). +Below is an example config + +```xml + + + + + 10 + + 5 + + + + /tmp/blacklistfilter/ip4.blist + /tmp/blacklistfilter/ip6.blist + /tmp/blacklistfilter/url.blist + /tmp/blacklistfilter/dns.blist + + + + + + + + 1 + + Intrusion.Botnet + + web + + ZeuS Tracker + + https://zeustracker.abuse.ch/blocklist.php?download=ipblocklist + + 10 + + 4 + + + + + + + 1 + + web + + Malware Domains + + http://mirror1.malwaredomains.com/files/justdomains + + Malware + + 10 + + URL,DNS + + + + 2 + web + http://data.phishtank.com/data/online-valid.csv + + 2 + PhishTank + Fraud.Phishing + 10 + URL,DNS + + + + + +``` + +- `repo_path` - path to GIT repo. Provides local versioning of all the blacklists. Upon module startup, if no GIT repo in this path is present, it is created. If the path is present, it continues versoning. +- `log_level` - standard level of logging (to stderr). 20 = INFO, 10 = DEBUG, etc. + + +## Operation + +- Module performs a check of all blacklists every `download_interval` (global/general one) +- Every blacklist can be also fetched at individual `download_interval` (preventing ban) +- The entities are extracted using regexps +- When there is a change in IP or URL/DNS blacklist + - new detector file is created + - changes are commited to GIT repo (when -r given) + +Demonstrated also by UML diagram below: + +![URL preprocessing](../doc/downloader_final.png) + +## About detector files + +Detector files are special files created by blacklist downloader for the detectors (ip/url/dns). +Every row contains an entity, separator and blacklist index. All the entities are sorted (especially useful for ip blacklistfilter, which uses binary search). When there is a change in any blacklist of a given type, new detector file is created (rewrites the old one). The detector listens for the file change (inotify's IN_CLOSE_WRITE flag) and reloads the file when +there is a change. The detector doesn't have to process the data, it just loads them and detects. All the preprocessing (sorting, case-insensitivying, ..) is done by the downloader. + +The blacklist index is a bitmap, so a value 9 means the entity is present on the blacklists with ID 1 and 4. + + +### Examples +*/tmp/blacklistfilter/ip4.blist* +``` +1.10.16.0/20,8 +1.19.0.0/16,8 +1.22.124.243,256 +1.22.180.84,256 +1.22.241.193,256 +``` + +*/tmp/blacklistfilter/ip6.blist* +``` +2401:c580:0000:0000:0000:0000:0000:0000/32,256 +2402:6680:0000:0000:0000:0000:0000:0000/32,256 +2405:b180:0000:0000:0000:0000:0000:0000/32,256 +``` + +*/tmp/blacklistfilter/url.blist* +``` +0632qyw.com\1 +06642.ir/wp-includes/fonts/chaseonline2019/ch1.1/07b2f33e388cf03a82397b057fb9e03b\4 +06works-plus.com\1 +071899.com\1 +``` + +*/tmp/blacklistfilter/dns.blist* +``` +dorothyn.com\1 +dorpk2sa2i.dayzcy3xae.madpendesign.com.au\1 +dortxn.com\1 +``` + +## Example module run +``` +alois@some_kinda_linux:~$ bl_downloader.py --repo-path /tmp/repicko +[2019-03-27 14:35:22,043] - INFO - Initialized empty Git repository in /tmp/repicko/.git/ +[2019-03-27 14:35:22,304] - INFO - Updated IPv4Blacklist: ZeuS Tracker +[2019-03-27 14:35:22,549] - INFO - Updated IPv4Blacklist: Feodo Tracker +[2019-03-27 14:35:22,761] - INFO - Updated IPv4Blacklist: Ransomware Tracker +[2019-03-27 14:35:22,920] - INFO - Updated IPv4Blacklist: Spamhaus Drop +[2019-03-27 14:35:23,036] - INFO - Updated IPv4Blacklist: Andoniaf Miners +[2019-03-27 14:35:24,202] - INFO - Updated IPv4Blacklist: SANS Miners +[2019-03-27 14:35:25,110] - INFO - Updated IPv4Blacklist: Cryptoioc Miners +[2019-03-27 14:35:26,794] - INFO - Updated IPv4Blacklist: CI Army - BadGuys +[2019-03-27 14:35:26,802] - WARNING - IPv4Blacklist, CZ.NIC Honeypot Cowrie: No valid entities found +[2019-03-27 14:35:26,995] - INFO - Updated IPv4Blacklist: CZ.NIC Honeypot Dionaea +[2019-03-27 14:35:27,616] - INFO - Updated IPv4Blacklist: Malc0de +[2019-03-27 14:35:27,938] - INFO - Updated IPv4Blacklist: URLVir +[2019-03-27 14:35:27,984] - INFO - Committed changes to GIT +[2019-03-27 14:35:28,146] - INFO - New IPv4 detector file created: /tmp/blacklistfilter/ip4.blist +[2019-03-27 14:35:28,249] - INFO - Updated IPv6Blacklist: Spamhaus Drop +[2019-03-27 14:35:28,264] - INFO - Committed changes to GIT +[2019-03-27 14:35:28,266] - INFO - New IPv6 detector file created: /tmp/blacklistfilter/ip6.blist +[2019-03-27 14:35:30,231] - INFO - Updated URLandDNSBlacklist: Malware Domains +[2019-03-27 14:35:30,414] - WARNING - Could not fetch blacklist: http://data.phishtank.com/data/online-valid.csv +Status code: 509 +[2019-03-27 14:35:31,269] - INFO - Updated URLandDNSBlacklist: OpenPhish +[2019-03-27 14:35:31,854] - INFO - Updated URLandDNSBlacklist: DisconnectMe +[2019-03-27 14:35:32,017] - INFO - Updated URLandDNSBlacklist: Booters +[2019-03-27 14:35:32,321] - INFO - Updated URLandDNSBlacklist: Zeus Tracker +[2019-03-27 14:35:32,560] - INFO - Updated URLandDNSBlacklist: Ransomware Tracker +[2019-03-27 14:35:32,656] - INFO - Committed changes to GIT +[2019-03-27 14:35:32,939] - INFO - New URL detector file created: /tmp/blacklistfilter/url.blist +[2019-03-27 14:35:32,939] - INFO - New DNS detector file created: /tmp/blacklistfilter/dns.blist +``` \ No newline at end of file diff --git a/blacklistfilter/dnsdetect/README.md b/blacklistfilter/dnsdetect/README.md index e69de29b..c1e12759 100644 --- a/blacklistfilter/dnsdetect/README.md +++ b/blacklistfilter/dnsdetect/README.md @@ -0,0 +1,109 @@ +# DNS blacklistfilter + +This module is a part of the blacklistfilter suite. For information about other modules, see the main [README](../README.md) + +## Goal + +Module receives the UniRec record and checks if the domain name (FQDN) is present in any DNS/FQDN blacklists +that are available. If the FQDN is present in any blacklist the record is changed by adding an index of the blacklist. +UniRec with this flag is then sent to the output interface. Blacklists are downloaded by a separate module +Blacklist downloader which saves blacklists to a file (specified in configuration) and blacklistfilter uses +this file to reload blacklists. + +## Input/Output + +``` +Input Interface: UniRec format (,) +Output Interface: UniRec format (,,BLACKLIST) +``` + +## Usage + +``` +Usage: dnsblacklistfilter -i [-c ] [-b ] +``` + +## Configuration +Is done via configuration file (command-line options override config file) + +```xml + + + + + + /tmp/blacklistfilter/dns.blist + + + + true + + + +``` + +- `blacklist_file`: A DNS file created by Blacklist downloader, containing (sorted) entries (FQDNs) from all blacklists + +- `watch_blacklists`: A flag indicating whether the blacklist file is being reloaded everytime the file changes. When set to false, +the blacklists are loaded only once at the startup of the module + +## Operation + +- Module reports every single flow (request and reply) with DNS present on some blacklist, it is checking DNS_NAME field (request and reply) +- If `watch_blacklists` flag is true, the module listens for changes (IN_CLOSE_WRITE events) in the file(s) and reloads +them everytime there is a change +- Detection of the FQDN is case-insensitive and deals with little nuances in the FQDNs (such as redundant backslashes). Following +domain names (DNS_NAME field) are treated the same: + +![URL preprocessing](../doc/url_dns.png) + +## Required data + +This module is implemented on TRAP platform, so it receives data on +TRAP input interface in UniRec format. + +UniRec fields required: + +- `DST_IP` (ipaddr): destination IP address of the flow +- `SRC_IP` (ipaddr): source IP address of the flow +- `DST_PORT` (uint16): destination port of the flow +- `SRC_PORT` (uint16): source port of the flow +- `PROTOCOL` (uint8): protocol used (TCP, UDP...) +- `PACKETS` (uint32): packets in the flow +- `BYTES` (uint32): bytes in the flow +- `TIME_FIRST` (time): time of the first packet in the flow +- `TIME_LAST` (time): time of the last packet in the flow +- `DNS_NAME` (string): requested FQDN + + +## Output data + +Upon detection, the input data are sent to the output, enriched with this value: + +- `BLACKLIST` (uint64): indexes of the blacklists (bitmap) which blacklisted the URL + +For example, when the `BLACKLIST` field contains number 9, it means the URL is present on +blacklists with ID 1 and 4 (in binary: 1001) + +## Compilation and linking + +This module requires compilation with `-std=c++11`, because of the usage of *std::vector, streams, etc.*. + +For linking add `-ltrap -lunirec -lnemea-common` +(the module must be compiled as a part of [NEMEA](https://github.com/CESNET/Nemea) repository or using installed libtrap-devel and unirec packages). + + +## Example detection +Below is an example output of this detector. IP addresses are made-up. +There are both requests and replies (can be identified with DNS_ID). DNS_RDATA field is the raw reply. + +``` +ipaddr DST_IP,ipaddr SRC_IP,uint64 BLACKLIST,uint64 BYTES,time TIME_FIRST,time TIME_LAST,uint32 DNS_RR_TTL,uint32 PACKETS,uint16 DNS_ANSWERS,uint16 DNS_CLASS,uint16 DNS_ID,uint16 DNS_PSIZE,uint16 DNS_QTYPE,uint16 DNS_RLENGTH,uint16 DST_PORT,uint16 SRC_PORT,uint8 DNS_DO,uint8 DNS_RCODE,uint8 PROTOCOL,string DNS_NAME,bytes DNS_RDATA +192.168.1.1,192.168.1.107,32,59,2018-09-28T14:16:28.552,2018-09-28T14:16:28.552,0,1,0,1,63445,0,1,0,53,57649,0,0,17,"zstresser.com", +192.168.1.107,192.168.1.1,32,75,2018-09-28T14:16:28.594,2018-09-28T14:16:28.594,300,1,1,1,63445,0,1,14,57649,53,0,0,17,"zstresser.com",3138352e31312e3134352e323439 +192.168.1.107,192.168.1.1,1,132,2018-09-28T14:17:23.677,2018-09-28T14:17:23.677,0,1,0,1,238,0,28,0,57649,53,0,0,17,"zverinova-kucharka.cz", +192.168.1.107,192.168.1.1,1,83,2018-09-28T14:17:23.677,2018-09-28T14:17:23.677,1800,1,1,1,44066,0,1,14,57649,53,0,0,17,"zverinova-kucharka.cz",33372e3135372e3139372e313231 +``` diff --git a/blacklistfilter/dnsdetect/dnsdetect_config.xml b/blacklistfilter/dnsdetect/dnsdetect_config.xml index df4cfe73..a11d1df3 100644 --- a/blacklistfilter/dnsdetect/dnsdetect_config.xml +++ b/blacklistfilter/dnsdetect/dnsdetect_config.xml @@ -1,15 +1,13 @@ - + /tmp/blacklistfilter/dns.blist - true diff --git a/blacklistfilter/hostrecvwarden.pl b/blacklistfilter/hostrecvwarden.pl deleted file mode 100644 index b11989a2..00000000 --- a/blacklistfilter/hostrecvwarden.pl +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/perl -w -# -# Copyright (C) 2011-2012 Cesnet z.s.p.o -# -# Use of this source is governed by a BSD-style license, see LICENSE file. - -use strict; - -#------------------------------------------------------------------------------ -# Warden 2.0 Client, Receiver, Example -# -# Simple use of warden-client receiver functionality to download new events -# from # Warden server. This code illustrates how to integrate warden-client -# receive functionality into local applications. -#------------------------------------------------------------------------------ - -#------------------------------------------------------------------------------ -# This code should developer add into his/her application. - -# Path to warden-client directory -my $warden_path = '/opt/warden-client'; - -# Inclusion of warden-client receiving functionality -require $warden_path . '/lib/WardenClientReceive.pm'; - -# Definition of requested event type. This attributes is also set on server -# and must not change. -my $requested_type = $ARGV[0]; - -# Download of new evetns from Warden server -my @new_events = WardenClientReceive::getNewEvents($warden_path, $requested_type); - -#------------------------------------------------------------------------------ -# Simple code that prints out new events obtained from Warden server. - -no warnings 'uninitialized'; - -foreach (@new_events) { - print join(',', @$_) . "\n"; -} - -exit 0; diff --git a/blacklistfilter/ipdetect/README.md b/blacklistfilter/ipdetect/README.md index ee116447..3f0f3517 100644 --- a/blacklistfilter/ipdetect/README.md +++ b/blacklistfilter/ipdetect/README.md @@ -1,5 +1,7 @@ # IP blacklistfilter +This module is a part of the blacklistfilter suite. For information about other modules, see the main [README](../README.md) + ## Goal Module receives the UniRec basic flow and checks if the stored source @@ -8,27 +10,65 @@ blacklist that are available. If any of the addresses is blacklisted, the record is changed by adding a number/index of the blacklists that contain this address. UniRec with this flag is then sent to the output interface. Blacklists are downloaded by a separate module -bl_downloader.py which saves blacklists to a file (specified in configuration) and blacklistfilter uses +Blacklist downloader which saves blacklists to a file (specified in configuration) and blacklistfilter uses this file to reload blacklists. ## Input/Output -Input Interface: UniRec format () +``` +Input Interface: UniRec format () Output Interface: UniRec format (,SRC_BLACKLIST,DST_BLACKLIST) +``` ## Usage ``` -Usage: ./ipblacklistfilter -u -i +Usage: ipblacklistfilter -i [-c ] [-4 ] [-6 ] ``` -# Blacklist downloader +## Configuration +Is done via configuration file (command-line options override config file) + +```xml + + + + + + /tmp/blacklistfilter/ip4.blist + + + + /tmp/blacklistfilter/ip6.blist + + + + true + + + +``` + + +- `{ipv4/ipv6}_blacklist_file`: An IPv4/IPv6 file created by Blacklist downloader, containing (sorted) entries from all blacklists + +- `watch_blacklists`: A flag indicating whether the blacklist file is being reloaded everytime the file changes. When set to false, +the blacklists are loaded only once at the startup of the module -IP blacklistfilter uses blacklist file which is handled by Python downloader (bl_downloader.py). -The downloader periodically checks for new blacklist updates and feeds it to the blacklistfilter -using inotify mechanism. The data are preprocessed by the downloader (sorted, trimmed whitespaces etc.) -See "TODO: downloader README ref" +## Operation + +- Upon startup, if the module can not find/read `ipv4_blacklist_file`, it immediately exits with an error. +The `ipv6_blacklist_file` is optional and its absence only produces a warning. +- Module reports every single flow with src/dst address present on some blacklist, +the only exception is a flow with src/dst port 53 (DNS queries). +- If `watch_blacklists` flag is true, the module listens for changes (IN_CLOSE_WRITE events) in the files and reloads +them everytime there is a change ## Required data @@ -55,9 +95,23 @@ Upon detection, the input data are sent to the output, enriched with these value - `DST_BLACKLIST` (uint64): indexes of the blacklists (bitmap) which blacklisted `DST_IP`, zero if not blacklisted - `SRC_BLACKLIST` (uint64): indexes of the blacklists (bitmap) which blacklisted `SRC_IP`, zero if not blacklisted +For example, when the `DST_BLACKLIST` field contains number 9, it means the DST_IP is present on +blacklists with ID 1 and 4 (in binary: 1001) + +The very rare situation, when both addresses are present on some blacklist, is not handled. There is always just one +non-zero value for `{DST,SRC}_BLACKLIST` (either DST or SRC is blacklisted, not both). + ## Compilation and linking This module requires compilation with `-std=c++11`, because of the usage of *std::vector, streams, etc.*. For linking add `-ltrap -lunirec -lnemea-common` (the module must be compiled as a part of [NEMEA](https://github.com/CESNET/Nemea) repository or using installed libtrap-devel and unirec packages). + +## Example detection +``` +ipaddr DST_IP,ipaddr SRC_IP,uint64 BYTES,uint64 DST_BLACKLIST,uint64 SRC_BLACKLIST,time TIME_FIRST,time TIME_LAST,uint32 PACKETS,uint16 DST_PORT,uint8 PROTOCOL +192.168.1.1,192.168.1.2,123,0,8,2017-08-18T14:16:08.256,2017-08-18T14:16:13.177,3,1433,6 +192.168.1.1,192.168.1.2,41,0,8,2017-08-18T14:16:13.405,2017-08-18T14:16:13.405,1,1433,6 +192.168.1.1,192.168.1.2,404,8,0,2017-08-18T14:16:10.106,2017-08-18T14:16:25.100,8,25,6 +``` diff --git a/blacklistfilter/ipdetect/ipdetect_config.xml b/blacklistfilter/ipdetect/ipdetect_config.xml index f46261f4..10929a94 100644 --- a/blacklistfilter/ipdetect/ipdetect_config.xml +++ b/blacklistfilter/ipdetect/ipdetect_config.xml @@ -12,8 +12,8 @@ /tmp/blacklistfilter/ip6.blist - true diff --git a/blacklistfilter/urldetect/README.md b/blacklistfilter/urldetect/README.md index d2327e2f..e0346861 100644 --- a/blacklistfilter/urldetect/README.md +++ b/blacklistfilter/urldetect/README.md @@ -1,5 +1,7 @@ # URL blacklistfilter +This module is a part of the blacklistfilter suite. For information about other modules, see the main [README](../README.md) + ## Goal Module receives the UniRec HTTP flow records and checks if the HTTP PATH (`HTTP_HOST` + `HTTP_URL`) is present in any @@ -7,29 +9,59 @@ blacklist that are available. If any of the addresses is blacklisted, the record is changed by adding a number/index of the blacklists that contain this URL. UniRec with this flag is then sent to the output interface. Blacklists are downloaded by a separate module -`bl_downloader.py` which saves blacklists to a file (specified in configuration) and blacklistfilter uses +Blacklist downloader which saves blacklists to a file (specified in configuration) and blacklistfilter uses this file to reload blacklists. ## Input/Output -Input Interface: UniRec format (``) - -Output Interface: UniRec format (``, `BLACKLIST`) +``` +Input Interface: UniRec format (,) +Output Interface: UniRec format (,,BLACKLIST) +``` ## Usage ``` -Usage: ./urlblacklistfilter -u -i +Usage: urlblacklistfilter -i [-c ] [-b ] ``` -# Blacklist downloader +## Configuration +Is done via configuration file (command-line options override config file) + +```xml + + + + + + /tmp/blacklistfilter/url.blist + + + + true + + + +``` + +- `blacklist_file`: An URL file created by Blacklist downloader, containing (sorted) entries (FQDNs and URLs) from all blacklists + +- `watch_blacklists`: A flag indicating whether the blacklist file is being reloaded everytime the file changes. When set to false, +the blacklists are loaded only once at the startup of the module -URL blacklistfilter uses blacklist file which is handled by Python downloader (bl_downloader.py). -The downloader periodically checks for new blacklist updates and feeds it to the blacklistfilter -using inotify mechanism. The data are preprocessed by the downloader (sorted, trimmed whitespaces etc.) +## Operation -See "TODO: downloader README ref" +- Module reports every single flow with URL present on some blacklist +- If `watch_blacklists` flag is true, the module listens for changes (IN_CLOSE_WRITE events) in the file(s) and reloads +them everytime there is a change +- Detection of the URL is case-insensitive and deals with little nuances in the URLs (such as redundant backslashes). Following +domain names (HTTP_HOST) are treated the same: +![URL preprocessing](../doc/url_dns.png) ## Required data @@ -42,11 +74,14 @@ UniRec fields required: - `SRC_IP` (ipaddr): source IP address of the flow - `DST_PORT` (uint16): destination port of the flow - `SRC_PORT` (uint16): source port of the flow +- `PROTOCOL` (uint8): protocol used (TCP, UDP...) +- `PACKETS` (uint32): packets in the flow +- `BYTES` (uint32): bytes in the flow - `TIME_FIRST` (time): time of the first packet in the flow - `TIME_LAST` (time): time of the last packet in the flow -- `HTTP_HOST` (string): HTTP Host header -- `HTTP_REFERER` (string): HTTP Referer header -- `HTTP_URL` (string): HTTP URL +- `HTTP_REQUEST_HOST` (string): HTTP Host header +- `HTTP_REQUEST_REFERER` (string): HTTP Referer header +- `HTTP_REQUEST_URL` (string): HTTP URL ## Output data @@ -55,9 +90,28 @@ Upon detection, the input data are sent to the output, enriched with this value: - `BLACKLIST` (uint64): indexes of the blacklists (bitmap) which blacklisted the URL +For example, when the `BLACKLIST` field contains number 9, it means the URL is present on +blacklists with ID 1 and 4 (in binary: 1001) + ## Compilation and linking This module requires compilation with `-std=c++11`, because of the usage of *std::vector, streams, etc.*. For linking add `-ltrap -lunirec -lnemea-common` (the module must be compiled as a part of [NEMEA](https://github.com/CESNET/Nemea) repository or using installed libtrap-devel and unirec packages). + + +## Example detection +Below is an example output of this detector. IP addresses are made-up. +When dealing with HTTPS, only domain name is visible to the module (through SNI header during TLS handshake), +so only domain names can be blacklisted when using HTTPS. With HTTP it can be either a domain or the entire URL. + +``` +ipaddr DST_IP,ipaddr SRC_IP,uint64 BLACKLIST,uint64 BYTES,time TIME_FIRST,time TIME_LAST,uint32 PACKETS,uint16 DST_PORT,uint16 SRC_PORT,uint8 PROTOCOL,string HTTP_REQUEST_HOST,string HTTP +_REQUEST_REFERER,string HTTP_REQUEST_URL + +192.168.1.1,192.168.1.2,8,3331,2018-09-11T10:16:54.549,2018-09-11T10:18:24.750,19,443,54174,6,"e.mail.ru","","" +192.168.1.1,192.168.1.2,4,450,2018-09-16T23:05:56.197,2018-09-16T23:05:57.481,6,80,48196,6,"112.e-democracy.bg","","/fre/verification/15d0e09cmbmm1b38nm5n/access.php" +192.168.1.1,192.168.1.2,17,446,2018-09-16T23:08:45.119,2018-09-16T23:08:45.837,7,80,48910,6,"029999.com","","/" +192.168.1.1,192.168.1.2,4,465,2018-09-16T23:09:37.086,2018-09-16T23:09:37.662,6,80,56802,6,"ang.angelflightmidatlantic.org","","/~mercymed/wp-content/uploads/2011/image/dhl/dhl/dhl" +``` diff --git a/blacklistfilter/urldetect/urldetect_config.xml b/blacklistfilter/urldetect/urldetect_config.xml index 4bcfc5b5..305d39a2 100644 --- a/blacklistfilter/urldetect/urldetect_config.xml +++ b/blacklistfilter/urldetect/urldetect_config.xml @@ -1,15 +1,14 @@ - + --> /tmp/blacklistfilter/url.blist - true From 49d3df54fd9667a842471107223c95096a329532 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 6 Jun 2019 14:46:27 +0200 Subject: [PATCH 07/40] Readability changes --- brute_force_detector/brute_force_detector.cpp | 156 ++++++++-------- brute_force_detector/host.cpp | 175 +++++++++--------- brute_force_detector/host.h | 6 +- brute_force_detector/record.cpp | 2 +- brute_force_detector/record.h | 78 ++++---- brute_force_detector/sender.h | 20 +- 6 files changed, 220 insertions(+), 217 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index cdfd155c..5688d73e 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -97,7 +97,6 @@ UR_FIELDS( // Struct with information about module trap_module_info_t *module_info = nullptr; -TelnetServerProfileMap TELNETRecord::TSPMap; #define MODULE_BASIC_INFO(BASIC) \ BASIC("brute_force_detector","A module used for detecting brute force dictionary attacks on SSH, RDP and Telnet protocols. For detection is used window with N last flows and if threshold of a suspicious flows (packet and byte range is checked) is reached, alarm is triggered.",1,1) @@ -111,6 +110,9 @@ TelnetServerProfileMap TELNETRecord::TSPMap; PARAM('W', "verbose", "Set whitelist parser to verbose mode.", no_argument, "none") static int stop = 0; + + // TODO consider changing globals +TelnetServerProfileMap TELNETRecord::TSPMap; Whitelist whitelist; void signalHandler(int signal) @@ -155,9 +157,13 @@ void printFlowPercent(uint64_t b, uint64_t p) << 100.0 / b * p << "%)"; cout.flags(f); - } else { + } + /* + else { cerr << "Attempted division by zero in printFlowPercent." << endl; } + // error output not necessary + */ } @@ -351,24 +357,16 @@ int main(int argc, char **argv) direction = FLOW_OUTGOING_DIRECTION; // Process rest of new data - ip_addr_t srcIp = ur_get(tmplt, data, F_SRC_IP); - ip_addr_t dstIp = ur_get(tmplt, data, F_DST_IP); - uint8_t tcpFlags = ur_get(tmplt, data, F_TCP_FLAGS); - uint32_t packets = ur_get(tmplt, data, F_PACKETS); - uint64_t bytes = ur_get(tmplt, data, F_BYTES); - ur_time_t flowFirstSeen = ur_get(tmplt, data, F_TIME_FIRST); - ur_time_t flowLastSeen = ur_get(tmplt, data, F_TIME_LAST); - - IRecord::MatchStructure structure{ - .flags = tcpFlags, - .packets = packets, - .bytes = bytes, - .srcIp = srcIp, - .dstIp = dstIp, + IRecord::MatchStructure structure { // TODO proper name + .flags = ur_get(tmplt, data, F_TCP_FLAGS), + .packets = ur_get(tmplt, data, F_PACKETS), + .bytes = ur_get(tmplt, data, F_BYTES), + .srcIp = ur_get(tmplt, data, F_SRC_IP), + .dstIp = ur_get(tmplt, data, F_DST_IP), .srcPort = srcPort, .dstPort = dstPort, - .flowFirstSeen = flowFirstSeen, - .flowLastSeen = flowLastSeen, + .flowFirstSeen = ur_get(tmplt, data, F_TIME_FIRST), + .flowLastSeen = ur_get(tmplt, data, F_TIME_LAST), }; ret = 0; @@ -376,42 +374,42 @@ int main(int argc, char **argv) // *** SSH *** if(SSH && (dstPort == TCP_SSH_PORT || srcPort == TCP_SSH_PORT)) { - bool state; + bool is_matched; SSHRecord *record; if(direction == FLOW_INCOMING_DIRECTION) { - record = new SSHRecord(dstIp, flowLastSeen); - state = record->matchWithIncomingSignature(&structure, &whitelist); - if(state) + record = new SSHRecord(structure.dstIp, structure.flowLastSeen); + is_matched = record->matchWithIncomingSignature(&structure, &whitelist); + if(is_matched) ssh.matchedIncomingFlows++; ssh.incomingFlows++; } else - { // FLOW_OUTGOING_DIRECTION - record = new SSHRecord(srcIp, flowLastSeen); - state = record->matchWithOutgoingSignature(&structure, &whitelist); - if(state) + { // FLOW_OUTGOING_DIRECTIONstructu + record = new SSHRecord(structure.srcIp, structure.flowLastSeen); + is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); + if(is_matched) ssh.matchedOutgoingFlows++; ssh.outgoingFlows++; } - if(state) + if(is_matched) ssh.matchedFlows++; ssh.flows++; SSHHost *host = sshHostMap.findHost(&structure, direction); - state = host->addRecord(record, &structure, direction); - if(!state) + is_matched = host->addRecord(record, &structure, direction); + if(!is_matched) delete record; else { // check for attack - auto attackState = host->checkForAttack(flowLastSeen); + auto attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != SSHHost::NO_ATTACK) { if(attackState == SSHHost::NEW_ATTACK) - ret = sender->firstReport(host, TCP_SSH_PORT, flowLastSeen, Config::getInstance().getSSHListThreshold()); + ret = sender->firstReport(host, TCP_SSH_PORT, structure.flowLastSeen, Config::getInstance().getSSHListThreshold()); else if(attackState == SSHHost::ATTACK_REPORT_WAIT || attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report @@ -426,14 +424,14 @@ int main(int argc, char **argv) else if(attackState == SSHHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_SSH_PORT, flowLastSeen, true); + ret = sender->continuingReport(host, TCP_SSH_PORT, structure.flowLastSeen, true); host->clearAllRecords(); host->setNotReported(); } else if(attackState == SSHHost::ATTACK) { - ret = sender->continuingReport(host, TCP_SSH_PORT, flowLastSeen); + ret = sender->continuingReport(host, TCP_SSH_PORT, structure.flowLastSeen); } } } @@ -442,42 +440,42 @@ int main(int argc, char **argv) // *** RDP *** if(RDP && (dstPort == TCP_RDP_PORT || srcPort == TCP_RDP_PORT)) { - bool state; + bool is_matched; RDPRecord *record; if(direction == FLOW_INCOMING_DIRECTION) { - record = new RDPRecord(dstIp, flowLastSeen); - state = record->matchWithIncomingSignature(&structure, &whitelist); - if(state) + record = new RDPRecord(structure.dstIp, structure.flowLastSeen); + is_matched = record->matchWithIncomingSignature(&structure, &whitelist); + if(is_matched) rdp.matchedIncomingFlows++; rdp.incomingFlows++; } else { // FLOW_OUTGOING_DIRECTION - record = new RDPRecord(srcIp, flowLastSeen); - state = record->matchWithOutgoingSignature(&structure, &whitelist); - if(state) + record = new RDPRecord(structure.srcIp, structure.flowLastSeen); + is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); + if(is_matched) rdp.matchedOutgoingFlows++; rdp.outgoingFlows++; } - if(state) + if(is_matched) rdp.matchedFlows++; rdp.flows++; RDPHost *host = rdpHostMap.findHost(&structure, direction); - state = host->addRecord(record, &structure, direction); - if(!state) + is_matched = host->addRecord(record, &structure, direction); + if(!is_matched) delete record; else { // check for attack - RDPHost::ATTACK_STATE attackState = host->checkForAttack(flowLastSeen); + RDPHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != RDPHost::NO_ATTACK) { if(attackState == RDPHost::NEW_ATTACK) - ret = sender->firstReport(host, TCP_RDP_PORT, flowLastSeen, Config::getInstance().getRDPListThreshold()); + ret = sender->firstReport(host, TCP_RDP_PORT, structure.flowLastSeen, Config::getInstance().getRDPListThreshold()); else if(attackState == RDPHost::ATTACK_REPORT_WAIT || attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report @@ -491,14 +489,14 @@ int main(int argc, char **argv) else if(attackState == RDPHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_RDP_PORT, flowLastSeen, true); + ret = sender->continuingReport(host, TCP_RDP_PORT, structure.flowLastSeen, true); host->clearAllRecords(); host->setNotReported(); } else if(attackState == RDPHost::ATTACK) { - ret = sender->continuingReport(host, TCP_RDP_PORT, flowLastSeen); + ret = sender->continuingReport(host, TCP_RDP_PORT, structure.flowLastSeen); } } } @@ -507,42 +505,42 @@ int main(int argc, char **argv) // *** TELNET *** if(TELNET && (dstPort == TCP_TELNET_PORT || srcPort == TCP_TELNET_PORT)) { - bool state; + bool is_matched; TELNETRecord *record; if(direction == FLOW_INCOMING_DIRECTION) { - record = new TELNETRecord(dstIp, flowLastSeen); - state = record->matchWithIncomingSignature(&structure, &whitelist); - if(state) + record = new TELNETRecord(structure.dstIp, structure.flowLastSeen); + is_matched = record->matchWithIncomingSignature(&structure, &whitelist); + if(is_matched) telnet.matchedIncomingFlows++; telnet.incomingFlows++; } else { // FLOW_OUTGOING_DIRECTION - record = new TELNETRecord(srcIp, flowLastSeen); - state = record->matchWithOutgoingSignature(&structure, &whitelist); - if(state) + record = new TELNETRecord(structure.srcIp, structure.flowLastSeen); + is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); + if(is_matched) telnet.matchedOutgoingFlows++; telnet.outgoingFlows++; } - if(state) + if(is_matched) telnet.matchedFlows++; telnet.flows++; TELNETHost *host = telnetHostMap.findHost(&structure, direction); - state = host->addRecord(record, &structure, direction); - if(!state) + is_matched = host->addRecord(record, &structure, direction); + if(!is_matched) delete record; else { // check for attack - TELNETHost::ATTACK_STATE attackState = host->checkForAttack(flowLastSeen); + TELNETHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != TELNETHost::NO_ATTACK) { if(attackState == TELNETHost::NEW_ATTACK) - ret = sender->firstReport(host, TCP_TELNET_PORT, flowLastSeen, Config::getInstance().getTELNETListThreshold()); + ret = sender->firstReport(host, TCP_TELNET_PORT, structure.flowLastSeen, Config::getInstance().getTELNETListThreshold()); else if(attackState == TELNETHost::ATTACK_REPORT_WAIT || attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report @@ -556,41 +554,41 @@ int main(int argc, char **argv) else if(attackState == TELNETHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_TELNET_PORT, flowLastSeen, true); + ret = sender->continuingReport(host, TCP_TELNET_PORT, structure.flowLastSeen, true); host->clearAllRecords(); host->setNotReported(); } else if(attackState == TELNETHost::ATTACK) { - ret = sender->continuingReport(host, TCP_TELNET_PORT, flowLastSeen); + ret = sender->continuingReport(host, TCP_TELNET_PORT, structure.flowLastSeen); } } } } // check for timeout - if(checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flowLastSeen)) + if(checkForTimeout(timeOfLastReportCheck, timerForReportCheck, structure.flowLastSeen)) { - timeOfLastReportCheck = flowLastSeen; + timeOfLastReportCheck = structure.flowLastSeen; if(SSH) - sshHostMap.checkForAttackTimeout(flowLastSeen, sender); + sshHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); if(RDP) - rdpHostMap.checkForAttackTimeout(flowLastSeen, sender); + rdpHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); if(TELNET) - telnetHostMap.checkForAttackTimeout(flowLastSeen, sender); + telnetHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); } - if(checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, flowLastSeen)) + if(checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, structure.flowLastSeen)) { - timeOfLastDeleteCheck = flowLastSeen; + timeOfLastDeleteCheck = structure.flowLastSeen; if(SSH) - sshHostMap.deleteOldRecordAndHosts(flowLastSeen); + sshHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); if(RDP) - rdpHostMap.deleteOldRecordAndHosts(flowLastSeen); + rdpHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); if(TELNET) - telnetHostMap.deleteOldRecordAndHosts(flowLastSeen); + telnetHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); } // kontrola po odeslani @@ -598,22 +596,23 @@ int main(int argc, char **argv) } // ***** End of main processing loop ***** + // TODO how to pass Host Map base class to printLogInfo if(SSH) { ssh.printLogInfo(); - std::cout << "Host Map Size: " << sshHostMap.size() << std::endl; + std::cout << " Host Map Size: " << sshHostMap.size() << std::endl; sshHostMap.clear(); } if(RDP) { rdp.printLogInfo(); - std::cout << "Host Map Size: " << rdpHostMap.size() << std::endl; + std::cout << " Host Map Size: " << rdpHostMap.size() << std::endl; rdpHostMap.clear(); } if(TELNET) { telnet.printLogInfo(); - std::cout << "Host Map Size: " << telnetHostMap.size() << std::endl; + std::cout << " Host Map Size: " << telnetHostMap.size() << std::endl; telnetHostMap.clear(); } @@ -624,3 +623,12 @@ int main(int argc, char **argv) FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS); return 0; } +/* +void printHosts(IHostMap map) +{ + for(auto item : map) + { + + } +} +*/ diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 7c6d191e..3f7e601e 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -71,21 +71,21 @@ bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { - uint16_t currentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t currentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); + uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); + uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); if(!isReported()) { //no attack yet - uint16_t actualListSizeInc = recordListIncoming.getActualNumOfListSize(); - uint16_t actualListSizeOut = recordListOutgoing.getActualNumOfListSize(); + uint16_t incomingListSize = recordListIncoming.getActualListSize(); + uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); //Number of records in list is lower than BottomSize (set to 50 by default) - if ( actualListSizeInc <= Config::getInstance().getSSHListBottomSize() || - actualListSizeOut <= Config::getInstance().getSSHListBottomSize()) { + if ( incomingListSize <= Config::getInstance().getSSHListBottomSize() || + outgoingListSize <= Config::getInstance().getSSHListBottomSize()) { - if( currentIncomingMF >= Config::getInstance().getSSHListThreshold() || - currentOutgoingMF >= Config::getInstance().getSSHListThreshold()) { + if( incomingMatched >= Config::getInstance().getSSHListThreshold() || + outgoingMatched >= Config::getInstance().getSSHListThreshold()) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -98,10 +98,10 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) //Number of records is between bottom size and max size } else { - auto SSH_LIST_TOP_THRESHOLD = (uint16_t) (std::max(actualListSizeInc, actualListSizeOut) * + auto SSH_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * Config::getInstance().getGlobalMatchedFlowRatio()); - if(currentIncomingMF >= SSH_LIST_TOP_THRESHOLD || currentOutgoingMF >= SSH_LIST_TOP_THRESHOLD) { + if(incomingMatched >= SSH_LIST_TOP_THRESHOLD || outgoingMatched >= SSH_LIST_TOP_THRESHOLD) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); @@ -119,37 +119,37 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) return SSHHost::ATTACK_REPORT_WAIT; else { - uint32_t incomingAttackScale = recordListIncoming.getNumOfMatchedFlowsSinceLastReport(); - uint32_t incomingTotalFlows = recordListIncoming.getNumOfTotalFlowsSinceLastReport(); + uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); + uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); - uint32_t outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); + uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); + uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); - if(currentIncomingMF == 0 && incomingAttackScale == 0 && - currentOutgoingMF == 0 && outgoingAttackScale == 0) + if(incomingMatched == 0 && incomingMatchedNew == 0 && + outgoingMatched == 0 && outgoingMatchedNew == 0) return SSHHost::END_OF_ATTACK; - double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double incomingPer = 0.0; - if(incomingTotalFlows > 0.0) - incomingPer = (100.0 / incomingTotalFlows) * incomingAttackScale; + double incomingMatchedPercentage = 0.0; + if(incomingTotalNew > 0.0) + incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; - double outgoingPer = 0.0; - if(outgoingTotalFlows > 0.0) - outgoingPer = (100.0 / outgoingTotalFlows) * outgoingAttackScale; + double outgoingMatchedPercentage = 0.0; + if(outgoingTotalNew > 0.0) + outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; - if (incomingPer < configRatio && outgoingPer < configRatio) + if (incomingMatchedPercentage < keepTrackingHostRatio && outgoingMatchedPercentage < keepTrackingHostRatio) { - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || + outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) return SSHHost::REPORT_END_OF_ATTACK; else return SSHHost::END_OF_ATTACK; } - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || + outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) return SSHHost::ATTACK; else return SSHHost::ATTACK_MIN_EVENTS_WAIT; @@ -180,19 +180,19 @@ bool RDPHost::addRecord(RDPRecord *record, void *structure, uint8_t direction) RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { - uint16_t currentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t currentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); + uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); + uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); if(!isReported()) { //no attack yet - uint16_t actualListSizeInc = recordListIncoming.getActualNumOfListSize(); - uint16_t actualListSizeOut = recordListOutgoing.getActualNumOfListSize(); + uint16_t incomingListSize = recordListIncoming.getActualListSize(); + uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - if (actualListSizeInc <= Config::getInstance().getRDPListBottomSize() || - actualListSizeOut <= Config::getInstance().getRDPListBottomSize()) { + if (incomingListSize <= Config::getInstance().getRDPListBottomSize() || + outgoingListSize <= Config::getInstance().getRDPListBottomSize()) { - if(currentIncomingMF >= Config::getInstance().getRDPListThreshold() || - currentOutgoingMF >= Config::getInstance().getRDPListThreshold()) { + if(incomingMatched >= Config::getInstance().getRDPListThreshold() || + outgoingMatched >= Config::getInstance().getRDPListThreshold()) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -203,10 +203,10 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) } //Number of records is between bottom size and max size } else { - auto RDP_LIST_TOP_THRESHOLD = (uint16_t) (std::max(actualListSizeInc, actualListSizeOut) * + auto RDP_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * Config::getInstance().getGlobalMatchedFlowRatio()); - if (currentIncomingMF >= RDP_LIST_TOP_THRESHOLD || currentOutgoingMF >= RDP_LIST_TOP_THRESHOLD) { + if (incomingMatched >= RDP_LIST_TOP_THRESHOLD || outgoingMatched >= RDP_LIST_TOP_THRESHOLD) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); @@ -219,41 +219,40 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) else { //host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) - return RDPHost::ATTACK_REPORT_WAIT; else { - uint32_t incomingAttackScale = recordListIncoming.getNumOfMatchedFlowsSinceLastReport(); - uint32_t incomingTotalFlows = recordListIncoming.getNumOfTotalFlowsSinceLastReport(); + uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); + uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); - uint32_t outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); + uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); + uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); - if(currentIncomingMF == 0 && incomingAttackScale == 0 && - currentOutgoingMF == 0 && outgoingAttackScale == 0) + if(incomingMatched == 0 && incomingMatchedNew == 0 && + outgoingMatched == 0 && outgoingMatchedNew == 0) return RDPHost::END_OF_ATTACK; - double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double incomingPer = 0.0; - if(incomingTotalFlows > 0.0) - incomingPer = (100.0 / incomingTotalFlows) * incomingAttackScale; + double incomingMatchedPercentage = 0.0; + if(incomingTotalNew > 0.0) + incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; - double outgoingPer = 0.0; - if(outgoingTotalFlows > 0.0) - outgoingPer = (100.0 / outgoingTotalFlows) * outgoingAttackScale; + double outgoingMatchedPercentage = 0.0; + if(outgoingTotalNew > 0.0) + outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; - if (incomingPer < configRatio && outgoingPer < configRatio) + if (incomingMatchedPercentage < keepTrackingHostRatio && outgoingMatchedPercentage < keepTrackingHostRatio) { - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || + outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) return RDPHost::REPORT_END_OF_ATTACK; else return RDPHost::END_OF_ATTACK; } - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || + outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) return RDPHost::ATTACK; else return RDPHost::ATTACK_MIN_EVENTS_WAIT; @@ -284,19 +283,19 @@ bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direct TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { - uint16_t currentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t currentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); + uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); + uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); if(!isReported()) { //no attack yet - uint16_t actualListSizeInc = recordListIncoming.getActualNumOfListSize(); - uint16_t actualListSizeOut = recordListOutgoing.getActualNumOfListSize(); + uint16_t incomingListSize = recordListIncoming.getActualListSize(); + uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - if (actualListSizeInc <= Config::getInstance().getTELNETListBottomSize() || - actualListSizeOut <= Config::getInstance().getTELNETListBottomSize()) { + if (incomingListSize <= Config::getInstance().getTELNETListBottomSize() || + outgoingListSize <= Config::getInstance().getTELNETListBottomSize()) { - if(currentIncomingMF >= Config::getInstance().getTELNETListThreshold() || - currentOutgoingMF >= Config::getInstance().getTELNETListThreshold()) { + if(incomingMatched >= Config::getInstance().getTELNETListThreshold() || + outgoingMatched >= Config::getInstance().getTELNETListThreshold()) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); @@ -307,10 +306,10 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) //Number of records is between bottom size and max size } else { - auto TELNET_LIST_TOP_THRESHOLD = (uint16_t) (std::max(actualListSizeInc, actualListSizeOut) * + auto TELNET_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * Config::getInstance().getGlobalMatchedFlowRatio()); - if(currentIncomingMF >= TELNET_LIST_TOP_THRESHOLD || currentOutgoingMF >= TELNET_LIST_TOP_THRESHOLD) { + if(incomingMatched >= TELNET_LIST_TOP_THRESHOLD || outgoingMatched >= TELNET_LIST_TOP_THRESHOLD) { //crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); @@ -327,37 +326,37 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) return TELNETHost::ATTACK_REPORT_WAIT; else { - uint32_t incomingAttackScale = recordListIncoming.getNumOfMatchedFlowsSinceLastReport(); - uint32_t incomingTotalFlows = recordListIncoming.getNumOfTotalFlowsSinceLastReport(); + uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); + uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); - uint32_t outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); + uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); + uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); - if(currentIncomingMF == 0 && incomingAttackScale == 0 && - currentOutgoingMF == 0 && outgoingAttackScale == 0) + if(incomingMatched == 0 && incomingMatchedNew == 0 && + outgoingMatched == 0 && outgoingMatchedNew == 0) return TELNETHost::END_OF_ATTACK; - double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double incomingPer = 0.0; - if(incomingTotalFlows > 0) - incomingPer = (100.0 / incomingTotalFlows) * incomingAttackScale; + double incomingMatchedPercentage = 0.0; + if(incomingTotalNew > 0.0) + incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; - double outgoingPer = 0.0; - if(outgoingTotalFlows > 0) - outgoingPer = (100.0 / outgoingTotalFlows) * outgoingAttackScale; + double outgoingMatchedPercentage = 0.0; + if(outgoingTotalNew > 0.0) + outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; - if (incomingPer < configRatio && outgoingPer < configRatio) + if (incomingMatchedPercentage < keepTrackingHostRatio && outgoingMatchedPercentage < keepTrackingHostRatio) { - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || + outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) return TELNETHost::REPORT_END_OF_ATTACK; else return TELNETHost::END_OF_ATTACK; } - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || + outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) return TELNETHost::ATTACK; else return TELNETHost::ATTACK_MIN_EVENTS_WAIT; @@ -399,7 +398,7 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) SSHHost *host = it.second; if(host->isReported() && host->checkForAttackTimeout(actualTime)) { - uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getNumOfMatchedFlowsSinceLastReport(); + uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_SSH_PORT, actualTime, true); @@ -449,7 +448,7 @@ void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) RDPHost *host = it.second; if(host->isReported() && host->checkForAttackTimeout(actualTime)) { - uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getNumOfMatchedFlowsSinceLastReport(); + uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_RDP_PORT, actualTime, true); @@ -499,7 +498,7 @@ void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) TELNETHost *host = it.second; if(host->isReported() && host->checkForAttackTimeout(actualTime)) { - uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getNumOfMatchedFlowsSinceLastReport(); + uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_TELNET_PORT, actualTime, true); diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 5540256e..d3c60bdd 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -83,8 +83,8 @@ class IHost { inline void setNotReported() { timeOfLastReport = 0; - recordListIncoming.clearNumOfTotalTargetsSinceAttack(); - recordListOutgoing.clearNumOfTotalTargetsSinceAttack(); + recordListIncoming.clearTotalTargetsSinceAttack(); + recordListOutgoing.clearTotalTargetsSinceAttack(); } inline bool getHostScannedNetwork() { return scanned; } @@ -236,7 +236,7 @@ class IHostMap { template void clearMap(Container *c) { - typename Container::iterator it = c->begin(); + auto it = c->begin(); while(it != c->end()) { //if(it->second) diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 2388327a..602f9d33 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -295,7 +295,7 @@ bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) return false; TelnetServerProfile * TSPProfile = TSPMap.findProfile(st.srcIp); - if(TSPProfile == NULL) + if(TSPProfile == nullptr) TSPProfile = TSPMap.createProfile(st.srcIp, st.flowFirstSeen); TSPProfile->profileWithNewData(packets, bytes); diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 5301c2c6..6eadd68f 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -70,7 +70,7 @@ class IRecord { public: IRecord () : signatureMatched(false) {} - virtual ~IRecord() {} + virtual ~IRecord() = default; virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl) = 0; virtual bool matchWithOutgoingSignature(void *structure, Whitelist *wl) = 0; @@ -98,11 +98,11 @@ class SSHRecord : public IRecord { public: SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl); - virtual bool matchWithOutgoingSignature(void *structure, Whitelist *wl); - virtual ur_time_t getRecordTimeout() { return Config::getInstance().getSSHRecordTimeout(); } + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getSSHRecordTimeout(); } - ip_addr_t dstIp; + ip_addr_t dstIp{}; ur_time_t flowLastSeen; }; @@ -110,11 +110,11 @@ class RDPRecord : public IRecord { public: RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl); - virtual bool matchWithOutgoingSignature(void *structure, Whitelist *wl); - virtual ur_time_t getRecordTimeout() { return Config::getInstance().getRDPRecordTimeout(); } + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } - ip_addr_t dstIp; + ip_addr_t dstIp{}; ur_time_t flowLastSeen; }; @@ -122,11 +122,11 @@ class TELNETRecord : public IRecord { public: TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl); - virtual bool matchWithOutgoingSignature(void *structure, Whitelist *wl); - virtual ur_time_t getRecordTimeout() { return Config::getInstance().getTELNETRecordTimeout(); } + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getTELNETRecordTimeout(); } - ip_addr_t dstIp; + ip_addr_t dstIp{}; ur_time_t flowLastSeen; private: @@ -146,20 +146,20 @@ class RecordList { void clearAllRecords(); ur_time_t getTimeOfLastRecord(); - inline uint16_t getActualNumOfListSize() { return actualListSize; }; - inline uint16_t getActualNumOfMatchedFlows() { return actualListMatchedFlows; } - inline uint32_t getNumOfMatchedFlowsSinceLastReport() { return matchedFlowsSinceLastReport; } - inline uint32_t getNumOfTotalFlowsSinceLastReport() { return totalFlowsSinceLastReport; } - inline void clearNumOfMatchedFlowsSinceLastReport() { matchedFlowsSinceLastReport = 0; } - inline void clearNumOTotalFlowsSinceLastReport() { totalFlowsSinceLastReport = 0; } + inline uint16_t getActualListSize() { return actualListSize; }; + inline uint16_t getActualMatchedFlows() { return actualListMatchedFlows; } + inline uint32_t getMatchedFlowsSinceLastReport() { return matchedFlowsSinceLastReport; } + inline uint32_t getTotalFlowsSinceLastReport() { return totalFlowsSinceLastReport; } + inline void clearMatchedFlowsSinceLastReport() { matchedFlowsSinceLastReport = 0; } + inline void clearTotalFlowsSinceLastReport() { totalFlowsSinceLastReport = 0; } - inline uint16_t getNumOfTargetsSinceLastReport() { return hashedDstIPSet.size(); } - inline void clearNumOfTargetsSinceLastReport() { hashedDstIPSet.clear(); } + inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } + inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } - inline uint16_t getNumOfCurrentTargets(); + inline uint16_t getCurrentTargets(); // TODO does this need implementation? - inline uint32_t getNumOfTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } - inline void clearNumOfTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } + inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } + inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } inline void initTotalTargetsSet(); std::vector getIpsOfVictims(); @@ -177,7 +177,7 @@ class RecordList { std::set hashedDstIPSet; std::set hashedDstTotalIPSet; - char str[46]; // TODO annotate + char victimIP[46]; bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) { @@ -238,7 +238,7 @@ void RecordList::clearAllRecords() matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; - clearNumOfTargetsSinceLastReport(); + clearTargetsSinceLastReport(); } @@ -344,15 +344,14 @@ ur_time_t RecordList::getTimeOfLastRecord() } template -uint16_t RecordList::getNumOfCurrentTargets() +uint16_t RecordList::getCurrentTargets() { std::set dstIpSet; - for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) + for(auto it : list) { - if((*it)->isMatched()) + if(it->isMatched()) { - ip_addr_t dstIp = (*it)->dstIp; - dstIpSet.insert(dstIp); + dstIpSet.insert(it->dstIp); } } return dstIpSet.size(); @@ -361,13 +360,11 @@ uint16_t RecordList::getNumOfCurrentTargets() template void RecordList::initTotalTargetsSet() { - for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) + for(auto it : list) { - if((*it)->isMatched()) + if(it->isMatched()) { - ip_addr_t dstIp = (*it)->dstIp; - - hashedDstTotalIPSet.insert(dstIp); + hashedDstTotalIPSet.insert(it->dstIp); } } } @@ -377,14 +374,13 @@ std::vector RecordList::getIpsOfVictims() { std::vector tmpIpsOfVictims; - for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) + for(auto& it : list) { - if((*it)->isMatched()) + if(it->isMatched()) { - ip_addr_t dstIp = (*it)->dstIp; - ip_to_str(&dstIp, str); + ip_to_str(&(it->dstIp), victimIP); - tmpIpsOfVictims.push_back(std::string(str)); + tmpIpsOfVictims.push_back(std::string(victimIP)); } } diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index 913321b2..32260c3c 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -91,22 +91,22 @@ class Sender template int continuingReport(Host *host, uint16_t dstPort, ur_time_t actualTime, bool endOfAttack = false) { - uint32_t incomingAttackScale = host->getPointerToIncomingRecordList()->getNumOfMatchedFlowsSinceLastReport(); - uint32_t outgoingAttackScale = host->getPointerToOutgoingRecordList()->getNumOfMatchedFlowsSinceLastReport(); + uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); + uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); string sNote; +% + host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearTotalFlowsSinceLastReport(); - host->getPointerToIncomingRecordList()->clearNumOfTargetsSinceLastReport(); - host->getPointerToIncomingRecordList()->clearNumOfMatchedFlowsSinceLastReport(); - host->getPointerToIncomingRecordList()->clearNumOTotalFlowsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearTotalFlowsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearNumOfTargetsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearNumOfMatchedFlowsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearNumOTotalFlowsSinceLastReport(); - - return send(host, dstPort, actualTime, incomingAttackScale > outgoingAttackScale ? incomingAttackScale : outgoingAttackScale, endOfAttack, sNote); + return send(host, dstPort, actualTime, incomingMatched > outgoingMatched ? incomingMatched : outgoingMatched, endOfAttack, sNote); } private: From 56f8898413a47e79eb72e84197ed581b45051d76 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Mon, 10 Jun 2019 14:26:36 +0200 Subject: [PATCH 08/40] Minor changes --- brute_force_detector/brute_force_detector.cpp | 4 ++-- brute_force_detector/brute_force_detector.h | 10 +++++----- brute_force_detector/config.cpp | 2 +- brute_force_detector/sender.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 5688d73e..66b8ffbd 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -148,14 +148,14 @@ bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t actualTime) } -void printFlowPercent(uint64_t b, uint64_t p) +void printFlowPercent(uint64_t b, uint64_t p, std::string comment /* optional, implicitly set to "" */) { if (b && p) { ios::fmtflags f(cout.flags()); cout << " (" << std::fixed << std::setprecision(2) << 100.0 / b * p - << "%)"; + << "%" << comment << ")"; cout.flags(f); } /* diff --git a/brute_force_detector/brute_force_detector.h b/brute_force_detector/brute_force_detector.h index 48463e3b..200e4799 100644 --- a/brute_force_detector/brute_force_detector.h +++ b/brute_force_detector/brute_force_detector.h @@ -57,7 +57,7 @@ const static uint16_t TCP_RDP_PORT = 3389; const static uint8_t FLOW_INCOMING_DIRECTION = 1; const static uint8_t FLOW_OUTGOING_DIRECTION = 2; -void printFlowPercent(uint64_t b, uint64_t p); +void printFlowPercent(uint64_t b, uint64_t p, std::string comment = ""); //ip address comparison for std::map and std::set struct cmpByIpAddr { @@ -101,12 +101,12 @@ class logInfo { printFlowPercent(this->flows, this->matchedFlows); std::cout << std::endl; std::cout << " Matched Incoming Flows: " << this->matchedIncomingFlows; - printFlowPercent(this->matchedFlows, this->matchedIncomingFlows); - printFlowPercent(this->flows, this->matchedIncomingFlows); + printFlowPercent(this->matchedFlows, this->matchedIncomingFlows, " from matched"); + printFlowPercent(this->flows, this->matchedIncomingFlows, " from all flows"); std::cout << std::endl; std::cout << " Matched Outgoing Flows: " << this->matchedOutgoingFlows; - printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows); - printFlowPercent(this->flows, this->matchedOutgoingFlows); + printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows, " from matched"); + printFlowPercent(this->flows, this->matchedOutgoingFlows, " from all flows"); std::cout << std::endl; } diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index 97e16e14..c51b3da3 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -55,7 +55,7 @@ Config::Config() GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0f; GENERAL_IGNORE_FIRST_SEND = 0; - GENERAL_MATCHED_FLOW_RATIO = 0.9f; + GENERAL_MATCHED_FLOW_RATIO = 0.9f; //TODO change back to 0.9f //SSH SSH_LIST_SIZE = 1000; diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index 32260c3c..c715529c 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -95,7 +95,7 @@ class Sender uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); string sNote; -% + host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToIncomingRecordList()->clearTotalFlowsSinceLastReport(); From 182a6f6e412a14e7dd2abfd9fa09d446f0853a21 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Mon, 10 Jun 2019 15:47:10 +0200 Subject: [PATCH 09/40] Refactoring --- brute_force_detector/brute_force_detector.cpp | 3 +- brute_force_detector/brute_force_detector.h | 2 +- brute_force_detector/host.cpp | 2 +- brute_force_detector/record.cpp | 160 ++++++++++-------- brute_force_detector/record.h | 27 +-- 5 files changed, 112 insertions(+), 82 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 66b8ffbd..e93d9f19 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -148,7 +148,7 @@ bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t actualTime) } -void printFlowPercent(uint64_t b, uint64_t p, std::string comment /* optional, implicitly set to "" */) +void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment /* optional, implicitly set to "" (see .h) */) { if (b && p) { ios::fmtflags f(cout.flags()); @@ -398,6 +398,7 @@ int main(int argc, char **argv) ssh.matchedFlows++; ssh.flows++; + // host is the source of current flow/connection SSHHost *host = sshHostMap.findHost(&structure, direction); is_matched = host->addRecord(record, &structure, direction); diff --git a/brute_force_detector/brute_force_detector.h b/brute_force_detector/brute_force_detector.h index 200e4799..97a4fbe3 100644 --- a/brute_force_detector/brute_force_detector.h +++ b/brute_force_detector/brute_force_detector.h @@ -57,7 +57,7 @@ const static uint16_t TCP_RDP_PORT = 3389; const static uint8_t FLOW_INCOMING_DIRECTION = 1; const static uint8_t FLOW_OUTGOING_DIRECTION = 2; -void printFlowPercent(uint64_t b, uint64_t p, std::string comment = ""); +void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment = ""); //ip address comparison for std::map and std::set struct cmpByIpAddr { diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 3f7e601e..72ba71f5 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -374,7 +374,7 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct if(direction == FLOW_INCOMING_DIRECTION) ip = structure->srcIp; else - ip = structure->dstIp; //attacker is now destination address + ip = structure->dstIp; // auto it = hostMap.find(ip); diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 602f9d33..05963734 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -57,21 +57,25 @@ SSHRecord::SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set signatureMatched = false; - if((flags & signatureFlags) != signatureFlags) - return false; + if((st.flags & signatureFlags) != signatureFlags) + { + return false; + } - if(packets > Config::getInstance().getSSHBFIncMaxPackets() || packets < Config::getInstance().getSSHBFIncMinPackets()) - return false; - if(bytes > Config::getInstance().getSSHBFIncMaxBytes() || bytes < Config::getInstance().getSSHBFIncMinBytes()) - return false; + if(st.packets > Config::getInstance().getSSHBFIncMaxPackets() || st.packets < Config::getInstance().getSSHBFIncMinPackets()) + { + return false; + } + + if(st.bytes > Config::getInstance().getSSHBFIncMaxBytes() || st.bytes < Config::getInstance().getSSHBFIncMinBytes()) + { + return false; + } if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { @@ -85,21 +89,25 @@ bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set - if((flags & signatureFlags) != signatureFlags) - return false; + if((st.flags & signatureFlags) != signatureFlags) + { + return false; + } - if(packets > Config::getInstance().getSSHBFOutMaxPackets() || packets < Config::getInstance().getSSHBFOutMinPackets()) - return false; - if(bytes > Config::getInstance().getSSHBFOutMaxBytes() || bytes < Config::getInstance().getSSHBFOutMinBytes()) - return false; + if(st.packets > Config::getInstance().getSSHBFOutMaxPackets() || st.packets < Config::getInstance().getSSHBFOutMinPackets()) + { + return false; + } - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swap src/dst ip/port + if(st.bytes > Config::getInstance().getSSHBFOutMaxBytes() || st.bytes < Config::getInstance().getSSHBFOutMinBytes()) + { + return false; + } + + if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -122,19 +130,16 @@ RDPRecord::RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; signatureMatched = false; //win8 manual input uint8_t signatureFlagsWin8ManualCon = 0b00011110; //SYN + ACK + PSH + RST - if((flags & signatureFlagsWin8ManualCon) == signatureFlagsWin8ManualCon) + if((st.flags & signatureFlagsWin8ManualCon) == signatureFlagsWin8ManualCon) { // s port, d port, packets, bytes, flags // 42315, 3389, 8, 1691, 30 // 42345, 3389, 9, 1747, 30 - if(packets >= 7 && packets <= 11 && bytes >= 1500 && bytes <= 2000) + if(st.packets >= 7 && st.packets <= 11 && st.bytes >= 1500 && st.bytes <= 2000) { if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { @@ -147,10 +152,10 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) //Ncrack/thc hydra to win8 unsuccessful connection uint8_t signatureFlagsWin8FailedCon = 0b00011010; //SYN + ACK + PSH - if((flags & signatureFlagsWin8FailedCon) == signatureFlagsWin8FailedCon) + if((st.flags & signatureFlagsWin8FailedCon) == signatureFlagsWin8FailedCon) { // s port, d port, packets, bytes, flags // 37501, 3389, 3, 165, 26 - if(packets == 3 && ( bytes >= 100 && bytes <= 200)) + if(st.packets == 3 && ( st.bytes >= 100 && st.bytes <= 200)) { if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { @@ -163,13 +168,19 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH - if((flags & signatureFlags) != signatureFlags) - return false; + if((st.flags & signatureFlags) != signatureFlags) + { + return false; + } - if(packets > Config::getInstance().getRDPBFIncMaxPackets() || packets < Config::getInstance().getRDPBFIncMinPackets()) - return false; - if(bytes > Config::getInstance().getRDPBFIncMaxBytes() || bytes < Config::getInstance().getRDPBFIncMinBytes()) - return false; + if(st.packets > Config::getInstance().getRDPBFIncMaxPackets() || st.packets < Config::getInstance().getRDPBFIncMinPackets()) + { + return false; + } + if(st.bytes > Config::getInstance().getRDPBFIncMaxBytes() || st.bytes < Config::getInstance().getRDPBFIncMinBytes()) + { + return false; + } if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { @@ -183,21 +194,18 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; signatureMatched = false; //win8 manual input uint8_t signatureFlagsWin8ManualCon = 0b00011010; //SYN + ACK + PSH - if((flags & signatureFlagsWin8ManualCon) == signatureFlagsWin8ManualCon) + if((st.flags & signatureFlagsWin8ManualCon) == signatureFlagsWin8ManualCon) { // s port, d port, packets, bytes, flags // 3389, 42320, 7, 1882, 26 // 3389, 42303, 7, 1951, 26 - if(packets == 7 && bytes >= 1700 && bytes <= 2200) + if(st.packets == 7 && st.bytes >= 1700 && st.bytes <= 2200) { - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swap src/dst ip/port + if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -208,12 +216,12 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) //Ncrack/thc hydra to win8 unsuccessful connection uint8_t signatureFlagsWin8FailedCon = 0b00011010; //SYN + ACK + RST - if((flags & signatureFlagsWin8FailedCon) == signatureFlagsWin8FailedCon) + if((st.flags & signatureFlagsWin8FailedCon) == signatureFlagsWin8FailedCon) { // s port, d port, packets, bytes, flags // 3389, 37639, 2, 92, 22 - if(packets == 2 && ( bytes > 80 && bytes < 120)) + if(st.packets == 2 && ( st.bytes > 80 && st.bytes < 120)) { - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swap src/dst ip/port + if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -223,16 +231,22 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) } uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH + RST - if((flags & signatureFlags) != signatureFlags) - return false; + if((st.flags & signatureFlags) != signatureFlags) + { + return false; + } - if(packets > Config::getInstance().getRDPBFOutMaxPackets() || packets < Config::getInstance().getRDPBFOutMinPackets()) - return false; - if(bytes > Config::getInstance().getRDPBFOutMaxBytes() || bytes < Config::getInstance().getRDPBFOutMinBytes()) - return false; + if(st.packets > Config::getInstance().getRDPBFOutMaxPackets() || st.packets < Config::getInstance().getRDPBFOutMinPackets()) + { + return false; + } + if(st.bytes > Config::getInstance().getRDPBFOutMaxBytes() || st.bytes < Config::getInstance().getRDPBFOutMinBytes()) + { + return false; + } - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swap src/dst ip/port + if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -255,21 +269,24 @@ TELNETRecord::TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set signatureMatched = false; - if((flags & signatureFlags) != signatureFlags) - return false; + if((st.flags & signatureFlags) != signatureFlags) + { + return false; + } - if(packets > Config::getInstance().getTELNETBFIncMaxPackets() || packets < Config::getInstance().getTELNETBFIncMinPackets()) - return false; - if(bytes > Config::getInstance().getTELNETBFIncMaxBytes() || bytes < Config::getInstance().getTELNETBFIncMinBytes()) - return false; + if(st.packets > Config::getInstance().getTELNETBFIncMaxPackets() || st.packets < Config::getInstance().getTELNETBFIncMinPackets()) + { + return false; + } + if(st.bytes > Config::getInstance().getTELNETBFIncMaxBytes() || st.bytes < Config::getInstance().getTELNETBFIncMinBytes()) + { + return false; + } if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { @@ -283,35 +300,42 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; - + uint8_t signatureFlags = 0b00011011; //SYN + ACK + PSH set + FIN signatureMatched = false; - if((flags & signatureFlags) != signatureFlags) + if((st.flags & signatureFlags) != signatureFlags) + { return false; - + } + TelnetServerProfile * TSPProfile = TSPMap.findProfile(st.srcIp); if(TSPProfile == nullptr) + { TSPProfile = TSPMap.createProfile(st.srcIp, st.flowFirstSeen); + } + + TSPProfile->profileWithNewData(st.packets, st.bytes); - TSPProfile->profileWithNewData(packets, bytes); - - if(packets < 6) + if(st.packets < 6) + { return false; + } //for max range only if(TSPProfile->isProfiled()) { - if(packets > TSPProfile->getMaxPackets() || bytes > TSPProfile->getMaxBytes()) + if(st.packets > TSPProfile->getMaxPackets() || st.bytes > TSPProfile->getMaxBytes()) + { return false; + } } else + { return false; - + } + signatureMatched = true; return true; } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 6eadd68f..c044f497 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -90,6 +90,11 @@ class IRecord { ur_time_t flowLastSeen; }; + // TODO Why is it even here? + ip_addr_t dstIp{}; + ur_time_t flowLastSeen{}; + + protected: bool signatureMatched; }; @@ -101,9 +106,7 @@ class SSHRecord : public IRecord { bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getSSHRecordTimeout(); } - - ip_addr_t dstIp{}; - ur_time_t flowLastSeen; + }; class RDPRecord : public IRecord { @@ -114,8 +117,6 @@ class RDPRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } - ip_addr_t dstIp{}; - ur_time_t flowLastSeen; }; class TELNETRecord : public IRecord { @@ -126,8 +127,6 @@ class TELNETRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getTELNETRecordTimeout(); } - ip_addr_t dstIp{}; - ur_time_t flowLastSeen; private: static TelnetServerProfileMap TSPMap; @@ -177,7 +176,7 @@ class RecordList { std::set hashedDstIPSet; std::set hashedDstTotalIPSet; - char victimIP[46]; + char victimIP[46]{}; bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) { @@ -251,7 +250,9 @@ void RecordList::addRecord(T record, bool isHostReported) { //list is full //delete first record if((*list.begin())->isMatched()) - actualListMatchedFlows--; + { + actualListMatchedFlows--; + } T recToDelete = list.front(); delete recToDelete; list.pop_front(); @@ -338,9 +339,13 @@ template ur_time_t RecordList::getTimeOfLastRecord() { if(!list.empty()) - return list.back()->flowLastSeen; + { + return list.back()->flowLastSeen; + } else - return 0; + { + return 0; + } } template From 716654b2d27b37c6ec03a02291266d5fc559e843 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Mon, 10 Jun 2019 16:08:38 +0200 Subject: [PATCH 10/40] More refactoring, signature flags now in record.h --- brute_force_detector/brute_force_detector.cpp | 2 +- brute_force_detector/config.cpp | 2 - brute_force_detector/config.h | 2 + brute_force_detector/record.cpp | 62 +++++++++---------- brute_force_detector/record.h | 20 +++++- 5 files changed, 51 insertions(+), 37 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index e93d9f19..b71c4d0c 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -386,7 +386,7 @@ int main(int argc, char **argv) ssh.incomingFlows++; } else - { // FLOW_OUTGOING_DIRECTIONstructu + { // FLOW_OUTGOING_DIRECTION record = new SSHRecord(structure.srcIp, structure.flowLastSeen); is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); if(is_matched) diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index c51b3da3..08ed8a96 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -114,7 +114,6 @@ Config::Config() TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(300, 0); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(600, 0); - //init keywords kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT = "GENERAL_CHECK_FOR_REPORT_TIMEOUT"; kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT = "GENERAL_CHECK_FOR_DELETE_TIMEOUT"; @@ -177,7 +176,6 @@ Config::Config() kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS = "TELNET_BRUTEFORCE_INC_MAX_PACKETS"; kw_TELNET_BRUTEFORCE_INC_MIN_BYTES = "TELNET_BRUTEFORCE_INC_MIN_BYTES"; kw_TELNET_BRUTEFORCE_INC_MAX_BYTES = "TELNET_BRUTEFORCE_INC_MAX_BYTES"; - } void Config::reloadConfig() diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index 5bb1aaf7..a47adbcf 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -150,6 +150,8 @@ class Config { std::string kw_GENERAL_IGNORE_FIRST_SEND; std::string kw_GENERAL_MATCHED_FLOW_RATIO; + + //SSH uint16_t SSH_LIST_SIZE; uint16_t SSH_LIST_THRESHOLD; diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 05963734..f7b7bc02 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -58,11 +58,9 @@ bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set - signatureMatched = false; - if((st.flags & signatureFlags) != signatureFlags) + if((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { return false; } @@ -90,9 +88,7 @@ bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set - - if((st.flags & signatureFlags) != signatureFlags) + if((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { return false; } @@ -133,12 +129,14 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) signatureMatched = false; - //win8 manual input - uint8_t signatureFlagsWin8ManualCon = 0b00011110; //SYN + ACK + PSH + RST - if((st.flags & signatureFlagsWin8ManualCon) == signatureFlagsWin8ManualCon) - { // s port, d port, packets, bytes, flags + // Win8 manual input + + if((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) + { + // s port, d port, packets, bytes, flags // 42315, 3389, 8, 1691, 30 // 42345, 3389, 9, 1747, 30 + if(st.packets >= 7 && st.packets <= 11 && st.bytes >= 1500 && st.bytes <= 2000) { if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) @@ -150,11 +148,13 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) } } - //Ncrack/thc hydra to win8 unsuccessful connection - uint8_t signatureFlagsWin8FailedCon = 0b00011010; //SYN + ACK + PSH - if((st.flags & signatureFlagsWin8FailedCon) == signatureFlagsWin8FailedCon) - { // s port, d port, packets, bytes, flags + // Ncrack/thc hydra to win8 unsuccessful connection + + if((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) + { + // s port, d port, packets, bytes, flags // 37501, 3389, 3, 165, 26 + if(st.packets == 3 && ( st.bytes >= 100 && st.bytes <= 200)) { if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) @@ -166,9 +166,8 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) } } - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH - if((st.flags & signatureFlags) != signatureFlags) + if((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { return false; } @@ -197,12 +196,14 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) signatureMatched = false; - //win8 manual input - uint8_t signatureFlagsWin8ManualCon = 0b00011010; //SYN + ACK + PSH - if((st.flags & signatureFlagsWin8ManualCon) == signatureFlagsWin8ManualCon) - { // s port, d port, packets, bytes, flags + // Win8 manual input + + if((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) + { + // s port, d port, packets, bytes, flags // 3389, 42320, 7, 1882, 26 // 3389, 42303, 7, 1951, 26 + if(st.packets == 7 && st.bytes >= 1700 && st.bytes <= 2200) { if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port @@ -214,11 +215,13 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) } } - //Ncrack/thc hydra to win8 unsuccessful connection - uint8_t signatureFlagsWin8FailedCon = 0b00011010; //SYN + ACK + RST - if((st.flags & signatureFlagsWin8FailedCon) == signatureFlagsWin8FailedCon) - { // s port, d port, packets, bytes, flags + // Ncrack/thc hydra to win8 unsuccessful connection + + if((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) + { + // s port, d port, packets, bytes, flags // 3389, 37639, 2, 92, 22 + if(st.packets == 2 && ( st.bytes > 80 && st.bytes < 120)) { if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port @@ -230,8 +233,7 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) } } - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH + RST - if((st.flags & signatureFlags) != signatureFlags) + if((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { return false; } @@ -270,11 +272,9 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set - signatureMatched = false; - if((st.flags & signatureFlags) != signatureFlags) + if((st.flags & TELNETRecord::signatureFlags) != TELNETRecord::signatureFlags) { return false; } @@ -301,11 +301,9 @@ bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - uint8_t signatureFlags = 0b00011011; //SYN + ACK + PSH set + FIN - signatureMatched = false; - if((st.flags & signatureFlags) != signatureFlags) + if((st.flags & TELNETRecord::signatureFlagsFin) != TELNETRecord::signatureFlagsFin) { return false; } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index c044f497..6d94d1e6 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -60,8 +60,10 @@ #include #include "config.h" +// TODO Is this relevant? //If we don't have a lot of memory use hash -//#define USE_HASH +//#define USE_HASH + /** * Interface for record @@ -107,6 +109,9 @@ class SSHRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getSSHRecordTimeout(); } + const static uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set + + }; class RDPRecord : public IRecord { @@ -117,6 +122,12 @@ class RDPRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } + const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; //SYN + ACK + PSH + RST + const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; //SYN + ACK + PSH + const static uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH + + + }; class TELNETRecord : public IRecord { @@ -127,6 +138,9 @@ class TELNETRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getTELNETRecordTimeout(); } + const static uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set + const static uint8_t signatureFlagsFin = 0b00011011; //SYN + ACK + PSH set + FIN + private: static TelnetServerProfileMap TSPMap; @@ -331,7 +345,9 @@ void RecordList::clearOldRecords(ur_time_t actualTime) list.erase(it++); } else - break; + { + break; + } } } From 79f6c605b549b1fa2eff9a82ab410aa3fa351074 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Mon, 10 Jun 2019 16:20:10 +0200 Subject: [PATCH 11/40] Bit more cleaning up --- brute_force_detector/host.cpp | 14 +++++--- brute_force_detector/host.h | 18 ++++++----- brute_force_detector/record.h | 61 +++++++++++++++++++---------------- 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 72ba71f5..d31f0f6c 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -164,16 +164,22 @@ bool RDPHost::addRecord(RDPRecord *record, void *structure, uint8_t direction) { IRecord::MatchStructure st = *(IRecord::MatchStructure*) (structure); - //scan => SKIP!!! + // ignore port-scans if(isFlowScan(&st.packets, &st.flags)) - return false; + { + return false; + } else { timeOfLastReceivedRecord = st.flowLastSeen; if(direction == FLOW_INCOMING_DIRECTION) - recordListIncoming.addRecord(record, isReported()); + { + recordListIncoming.addRecord(record, isReported()); + } else - recordListOutgoing.addRecord(record, isReported()); + { + recordListOutgoing.addRecord(record, isReported()); + } return true; } } diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index d3c60bdd..441db784 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -105,6 +105,7 @@ class IHost { virtual bool canDeleteHost(ur_time_t actualTime) { + // TODO investigate this /* ur_time_t timeOfLastIncomingRecord = recordListIncoming.getTimeOfLastRecord(); ur_time_t timeOfLastOutgoingRecord = recordListOutgoing.getTimeOfLastRecord(); @@ -116,10 +117,9 @@ class IHost { ur_time_t timeOfLastRecord = timeOfLastIncomingRecord > timeOfLastOutgoingRecord ? timeOfLastIncomingRecord : timeOfLastOutgoingRecord; */ ur_time_t timer = getHostDeleteTimeout(); - //return checkForTimeout(timeOfLastRecord, timer, actualTime); + // return checkForTimeout(timeOfLastRecord, timer, actualTime); return checkForTimeout(timeOfLastReceivedRecord, timer, actualTime); - } virtual ur_time_t getHostReportTimeout() = 0; @@ -140,8 +140,8 @@ class IHost { virtual ATTACK_STATE checkForAttack(ur_time_t actualTime) = 0; - RecordList* getPointerToIncomingRecordList() {return &recordListIncoming; } - RecordList* getPointerToOutgoingRecordList() {return &recordListOutgoing; } + RecordList* getPointerToIncomingRecordList() { return &recordListIncoming; } + RecordList* getPointerToOutgoingRecordList() { return &recordListOutgoing; } virtual void clearAllRecords() { recordListIncoming.clearAllRecords(); recordListOutgoing.clearAllRecords();} @@ -158,7 +158,9 @@ class IHost { return true; } else - return false; + { + return false; + } } protected: @@ -173,7 +175,7 @@ class IHost { ur_time_t firstSeen; ur_time_t timeOfLastReport; ur_time_t timeOfLastReceivedRecord; - RecordList recordListIncoming; //incoming direction to victim (attacker -> victim) + RecordList recordListIncoming; // direction to victim (attacker -> victim) RecordList recordListOutgoing; }; @@ -181,7 +183,7 @@ class IHost { class SSHHost : public IHost { public: - SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} + SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} bool addRecord(SSHRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; ATTACK_STATE checkForAttack(ur_time_t actualTime) override; @@ -193,7 +195,7 @@ class SSHHost : public IHost { class RDPHost : public IHost { public: - RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} + RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} bool addRecord(RDPRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; ATTACK_STATE checkForAttack(ur_time_t actualTime) override; diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 6d94d1e6..45ec23ee 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -46,23 +46,24 @@ #define RECORD_H #include -//class TelnetServerProfileMap; -#include "telnet_server_profile.h" +#include +#include +#include +#include +#include #include //ip_addr_t #include //ur_time_t -#include -#include #include "brute_force_detector.h" #include "whitelist.h" -#include -#include -#include #include "config.h" +// class TelnetServerProfileMap; +#include "telnet_server_profile.h" + // TODO Is this relevant? -//If we don't have a lot of memory use hash -//#define USE_HASH +// If we don't have a lot of memory use hash +// #define USE_HASH /** @@ -109,7 +110,7 @@ class SSHRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getSSHRecordTimeout(); } - const static uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH }; @@ -122,9 +123,9 @@ class RDPRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } - const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; //SYN + ACK + PSH + RST - const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; //SYN + ACK + PSH - const static uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH + const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; // SYN + ACK + PSH + RST + const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; // SYN + ACK + PSH + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH @@ -138,8 +139,8 @@ class TELNETRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getTELNETRecordTimeout(); } - const static uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set - const static uint8_t signatureFlagsFin = 0b00011011; //SYN + ACK + PSH set + FIN + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH + const static uint8_t signatureFlagsFin = 0b00011011; // SYN + ACK + PSH + FIN private: @@ -160,7 +161,7 @@ class RecordList { ur_time_t getTimeOfLastRecord(); inline uint16_t getActualListSize() { return actualListSize; }; - inline uint16_t getActualMatchedFlows() { return actualListMatchedFlows; } + inline uint16_t getActualMatchedFlows() { return actualMatchedFlows; } inline uint32_t getMatchedFlowsSinceLastReport() { return matchedFlowsSinceLastReport; } inline uint32_t getTotalFlowsSinceLastReport() { return totalFlowsSinceLastReport; } inline void clearMatchedFlowsSinceLastReport() { matchedFlowsSinceLastReport = 0; } @@ -180,7 +181,7 @@ class RecordList { std::list list; uint16_t maxListSize; uint16_t actualListSize; - uint16_t actualListMatchedFlows; + uint16_t actualMatchedFlows; uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; @@ -202,7 +203,7 @@ template RecordList::RecordList() { actualListSize = 0; - actualListMatchedFlows = 0; + actualMatchedFlows = 0; flowCounter = 0; flowMatchedCounter = 0; @@ -210,14 +211,20 @@ RecordList::RecordList() totalFlowsSinceLastReport = 0; if(typeid(T) == typeid(SSHRecord*)) - maxListSize = Config::getInstance().getSSHMaxListSize(); + { + maxListSize = Config::getInstance().getSSHMaxListSize(); + } else if(typeid(T) == typeid(RDPRecord*)) - maxListSize = Config::getInstance().getRDPMaxListSize(); + { + maxListSize = Config::getInstance().getRDPMaxListSize(); + } else if(typeid(T) == typeid(TELNETRecord*)) - maxListSize = Config::getInstance().getTELNETMaxListSize(); + { + maxListSize = Config::getInstance().getTELNETMaxListSize(); + } else { - std::cerr<<"Error record.h: Max list size for class "<::clearAllRecords() } actualListSize = 0; - actualListMatchedFlows = 0; + actualMatchedFlows = 0; flowCounter = 0; flowMatchedCounter = 0; @@ -265,7 +272,7 @@ void RecordList::addRecord(T record, bool isHostReported) //delete first record if((*list.begin())->isMatched()) { - actualListMatchedFlows--; + actualMatchedFlows--; } T recToDelete = list.front(); delete recToDelete; @@ -276,7 +283,7 @@ void RecordList::addRecord(T record, bool isHostReported) if(record->isMatched()) { flowMatchedCounter++; - actualListMatchedFlows++; + actualMatchedFlows++; } if(isHostReported) @@ -308,7 +315,7 @@ void RecordList::setNewMaxListSize(uint16_t newMaxListSize) T recToDelete = list.front(); if (recToDelete->isMatched()) - actualListMatchedFlows--; + actualMatchedFlows--; delete recToDelete; list.pop_front(); @@ -336,7 +343,7 @@ void RecordList::clearOldRecords(ur_time_t actualTime) { if ((*it)->isMatched()) { - actualListMatchedFlows--; + actualMatchedFlows--; } actualListSize--; From 51f5ed5fd59f6241f45e27603f8294c51d9d0ef5 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Wed, 12 Jun 2019 12:23:08 +0200 Subject: [PATCH 12/40] Aesthetic changes --- brute_force_detector/brute_force_detector.cpp | 102 +++++++++++++----- brute_force_detector/sender.h | 22 ++-- brute_force_detector/whitelist.h | 2 +- brute_force_detector/whitelist_unit_test.cpp | 13 ++- 4 files changed, 93 insertions(+), 46 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index b71c4d0c..372e562f 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -382,15 +382,20 @@ int main(int argc, char **argv) record = new SSHRecord(structure.dstIp, structure.flowLastSeen); is_matched = record->matchWithIncomingSignature(&structure, &whitelist); if(is_matched) - ssh.matchedIncomingFlows++; + { + ssh.matchedIncomingFlows++; + } ssh.incomingFlows++; } - else - { // FLOW_OUTGOING_DIRECTION + else // FLOW_OUTGOING_DIRECTION + { + record = new SSHRecord(structure.srcIp, structure.flowLastSeen); is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); if(is_matched) - ssh.matchedOutgoingFlows++; + { + ssh.matchedOutgoingFlows++; + } ssh.outgoingFlows++; } @@ -403,14 +408,19 @@ int main(int argc, char **argv) is_matched = host->addRecord(record, &structure, direction); if(!is_matched) - delete record; + { + delete record; + } else - { // check for attack + { + // check for attack auto attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != SSHHost::NO_ATTACK) { if(attackState == SSHHost::NEW_ATTACK) - ret = sender->firstReport(host, TCP_SSH_PORT, structure.flowLastSeen, Config::getInstance().getSSHListThreshold()); + { + ret = sender->firstReport(host, TCP_SSH_PORT, structure.flowLastSeen, Config::getInstance().getSSHListThreshold()); + } else if(attackState == SSHHost::ATTACK_REPORT_WAIT || attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report @@ -449,7 +459,9 @@ int main(int argc, char **argv) record = new RDPRecord(structure.dstIp, structure.flowLastSeen); is_matched = record->matchWithIncomingSignature(&structure, &whitelist); if(is_matched) - rdp.matchedIncomingFlows++; + { + rdp.matchedIncomingFlows++; + } rdp.incomingFlows++; } else @@ -457,26 +469,34 @@ int main(int argc, char **argv) record = new RDPRecord(structure.srcIp, structure.flowLastSeen); is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); if(is_matched) - rdp.matchedOutgoingFlows++; + { + rdp.matchedOutgoingFlows++; + } rdp.outgoingFlows++; } if(is_matched) - rdp.matchedFlows++; + { + rdp.matchedFlows++; + } rdp.flows++; RDPHost *host = rdpHostMap.findHost(&structure, direction); is_matched = host->addRecord(record, &structure, direction); if(!is_matched) - delete record; + { + delete record; + } else { // check for attack RDPHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != RDPHost::NO_ATTACK) { if(attackState == RDPHost::NEW_ATTACK) - ret = sender->firstReport(host, TCP_RDP_PORT, structure.flowLastSeen, Config::getInstance().getRDPListThreshold()); + { + ret = sender->firstReport(host, TCP_RDP_PORT, structure.flowLastSeen, Config::getInstance().getRDPListThreshold()); + } else if(attackState == RDPHost::ATTACK_REPORT_WAIT || attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report @@ -514,34 +534,45 @@ int main(int argc, char **argv) record = new TELNETRecord(structure.dstIp, structure.flowLastSeen); is_matched = record->matchWithIncomingSignature(&structure, &whitelist); if(is_matched) - telnet.matchedIncomingFlows++; + { + telnet.matchedIncomingFlows++; + } telnet.incomingFlows++; } else - { // FLOW_OUTGOING_DIRECTION + { + // FLOW_OUTGOING_DIRECTION record = new TELNETRecord(structure.srcIp, structure.flowLastSeen); is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); if(is_matched) - telnet.matchedOutgoingFlows++; + { + telnet.matchedOutgoingFlows++; + } telnet.outgoingFlows++; } if(is_matched) - telnet.matchedFlows++; + { + telnet.matchedFlows++; + } telnet.flows++; TELNETHost *host = telnetHostMap.findHost(&structure, direction); is_matched = host->addRecord(record, &structure, direction); if(!is_matched) - delete record; + { + delete record; + } else { // check for attack TELNETHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != TELNETHost::NO_ATTACK) { if(attackState == TELNETHost::NEW_ATTACK) - ret = sender->firstReport(host, TCP_TELNET_PORT, structure.flowLastSeen, Config::getInstance().getTELNETListThreshold()); + { + ret = sender->firstReport(host, TCP_TELNET_PORT, structure.flowLastSeen, Config::getInstance().getTELNETListThreshold()); + } else if(attackState == TELNETHost::ATTACK_REPORT_WAIT || attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report @@ -574,22 +605,34 @@ int main(int argc, char **argv) timeOfLastReportCheck = structure.flowLastSeen; if(SSH) - sshHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); + { + sshHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); + } if(RDP) - rdpHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); + { + rdpHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); + } if(TELNET) - telnetHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); + { + telnetHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); + } } if(checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, structure.flowLastSeen)) { timeOfLastDeleteCheck = structure.flowLastSeen; if(SSH) - sshHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); + { + sshHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); + } if(RDP) - rdpHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); + { + rdpHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); + } if(TELNET) - telnetHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); + { + telnetHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); + } } // kontrola po odeslani @@ -624,12 +667,13 @@ int main(int argc, char **argv) FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS); return 0; } -/* -void printHosts(IHostMap map) + +void printHosts(IHostMap& obj) { - for(auto item : map) + auto hostMap = obj.hostMap; + for(auto & item : obj) { - + cout << item.value << ", "; } } -*/ + diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index c715529c..61b64901 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -62,7 +62,7 @@ extern "C" { #include using namespace std; -//WARDEN_TYPE +// WARDEN_TYPE #define WT_BRUTEFORCE 2 /** @@ -78,7 +78,7 @@ class Sender int firstReport(Host *host, uint16_t dstPort, ur_time_t actualTime, uint16_t detectionThreshold) { if(Config::getInstance().getGlobalIgnoreFirstSend()) - { ///Ignore first report + { // /Ignore first report host->setReportTime(actualTime); return TRAP_E_OK; } @@ -125,14 +125,14 @@ class Sender sort(outIpsVictims.begin(), outIpsVictims.end()); outIpsVictims.erase(unique(outIpsVictims.begin(), outIpsVictims.end()), outIpsVictims.end()); - //Incoming + // Incoming note.append("I:"); for (const auto & incIpsVictim : incIpsVictims) { note.append(incIpsVictim); note.append(","); } - //Outgoing + // Outgoing note.append("O:"); for (const auto & outIpsVictim : outIpsVictims) { note.append(outIpsVictim); @@ -140,14 +140,14 @@ class Sender } note.erase(note.length(),1); - //get size of note - uint16_t noteSize = note.size() + 1; //plus '\0' + // get size of note + uint16_t noteSize = note.size() + 1; // plus '\0' void *rec = ur_create_record(outTemplate, noteSize); - //@WARDEN_REPORT=DETECTION_TIME,WARDEN_TYPE,SRC_IP,PROTOCOL,DST_PORT,EVENT_SCALE, - // NOTE (IP addresses of victims) - //set fields + // @WARDEN_REPORT=DETECTION_TIME,WARDEN_TYPE,SRC_IP,PROTOCOL,DST_PORT,EVENT_SCALE, + // NOTE (IP addresses of victims) + // set fields ur_set(outTemplate, rec, F_DETECTION_TIME, actualTime); ur_set(outTemplate, rec, F_WARDEN_TYPE, WT_BRUTEFORCE); ur_set(outTemplate, rec, F_SRC_IP, host->getHostIp()); @@ -155,10 +155,10 @@ class Sender ur_set(outTemplate, rec, F_PROTOCOL, TCP_PROTOCOL_NUM); ur_set(outTemplate, rec, F_EVENT_SCALE, intensity); - //set dynamic field + // set dynamic field ur_set_string(outTemplate, rec, F_NOTE, note.c_str()); - //send + // send int sendState = trap_send(0, rec, ur_rec_size(outTemplate, rec)); host->setReportTime(actualTime); diff --git a/brute_force_detector/whitelist.h b/brute_force_detector/whitelist.h index ad96f861..f8483e21 100644 --- a/brute_force_detector/whitelist.h +++ b/brute_force_detector/whitelist.h @@ -263,4 +263,4 @@ class Whitelist { char *wlFileName; }; -#endif \ No newline at end of file +#endif // WHITELIST_H diff --git a/brute_force_detector/whitelist_unit_test.cpp b/brute_force_detector/whitelist_unit_test.cpp index a034c9d5..dd85324b 100644 --- a/brute_force_detector/whitelist_unit_test.cpp +++ b/brute_force_detector/whitelist_unit_test.cpp @@ -52,10 +52,12 @@ using namespace std; if(wl!=nullptr) \ { \ delete wl; \ - wl = nullptr; \ + wl = nullptr; \ } \ - if(wl == nullptr) \ - wl = new Whitelist(); \ + if(wl == nullptr) \ + { \ + wl = new Whitelist(); \ + } \ parser = wl->getPointerToParser(); \ } //parser->setVerbose(); @@ -70,7 +72,8 @@ int failCounter = 0; void subTestRes(int testNum, const string& state) { //cout <<"Subtest "<< testNum <<": "<< state << endl; - if (state == "fail") failCounter++; + if (state == "fail") + failCounter++; } @@ -79,7 +82,7 @@ int main() Whitelist *wl = nullptr; WhitelistParser *parser; - srand(0); + srand(0); // TODO constant value as random seed //add rules using: //parser->addSelectedPortRule(ip_addr_t, direction, prefix, string ports); From 7018a3fa8d4e2452fbf17e0043d5dba88d0ea174 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Wed, 12 Jun 2019 13:27:45 +0200 Subject: [PATCH 13/40] Aesthetic changes, host.cpp if conditions simplified --- brute_force_detector/host.cpp | 330 ++++++++++++++++++++++------------ brute_force_detector/host.h | 26 +-- brute_force_detector/sender.h | 23 +-- 3 files changed, 243 insertions(+), 136 deletions(-) diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index d31f0f6c..c283451b 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -51,20 +51,30 @@ bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) { IRecord::MatchStructure st = *(IRecord::MatchStructure*) (structure); - //scan => SKIP!!! + // scan => SKIP!!! if(isFlowScan(&st.packets, &st.flags)) - return false; - else if(st.packets == 1 && st.flags == 0b00010000) //skip ack only packet - return false; - else if(st.packets == 4 && st.flags == 0b00000010) //4 packet SYN request - return false; + { + return false; + } + else if(st.packets == 1 && st.flags == 0b00010000) // skip ack only packet + { + return false; + } + else if(st.packets == 4 && st.flags == 0b00000010) // 4 packet SYN request + { + return false; + } else { timeOfLastReceivedRecord = st.flowLastSeen; if(direction == FLOW_INCOMING_DIRECTION) - recordListIncoming.addRecord(record, isReported()); + { + recordListIncoming.addRecord(record, isReported()); + } else - recordListOutgoing.addRecord(record, isReported()); + { + recordListOutgoing.addRecord(record, isReported()); + } return true; } } @@ -75,48 +85,55 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); if(!isReported()) - { //no attack yet + { + // no attack yet uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - //Number of records in list is lower than BottomSize (set to 50 by default) - if ( incomingListSize <= Config::getInstance().getSSHListBottomSize() || - outgoingListSize <= Config::getInstance().getSSHListBottomSize()) { - - if( incomingMatched >= Config::getInstance().getSSHListThreshold() || - outgoingMatched >= Config::getInstance().getSSHListThreshold()) { - - //crossed threshold, new attack detected + // Number of records in list is lower than BottomSize (set to 50 by default) + if ( std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getSSHListBottomSize()) + { + if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold()) + { + // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return SSHHost::NEW_ATTACK; - } else { + } + else + { return SSHHost::NO_ATTACK; } - //Number of records is between bottom size and max size - } else { - auto SSH_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * + } + else + { + // Number of records is between bottom size and max size + + auto SSH_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * Config::getInstance().getGlobalMatchedFlowRatio()); - if(incomingMatched >= SSH_LIST_TOP_THRESHOLD || outgoingMatched >= SSH_LIST_TOP_THRESHOLD) { - //crossed threshold, new attack detected + if(std::max(incomingMatched, outgoingMatched) >= SSH_LIST_TOP_THRESHOLD) + { + // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); - return SSHHost::NEW_ATTACK; - } else { + } + else + { return SSHHost::NO_ATTACK; } } } else - { //host is attacking, wait for timeout to report again + { // host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) - - return SSHHost::ATTACK_REPORT_WAIT; + { + return SSHHost::ATTACK_REPORT_WAIT; + } else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); @@ -127,32 +144,44 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) if(incomingMatched == 0 && incomingMatchedNew == 0 && outgoingMatched == 0 && outgoingMatchedNew == 0) - return SSHHost::END_OF_ATTACK; + { + return SSHHost::END_OF_ATTACK; + } double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); double incomingMatchedPercentage = 0.0; if(incomingTotalNew > 0.0) - incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; + { + incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; + } double outgoingMatchedPercentage = 0.0; if(outgoingTotalNew > 0.0) - outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; + { + outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; + } - if (incomingMatchedPercentage < keepTrackingHostRatio && outgoingMatchedPercentage < keepTrackingHostRatio) + if (std::max(incomingMatchedPercentage, outgoingMatchedPercentage) < keepTrackingHostRatio) { - if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) - return SSHHost::REPORT_END_OF_ATTACK; + if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) + { + return SSHHost::REPORT_END_OF_ATTACK; + } else - return SSHHost::END_OF_ATTACK; + { + return SSHHost::END_OF_ATTACK; + } } - if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) - return SSHHost::ATTACK; + if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) + { + return SSHHost::ATTACK; + } else - return SSHHost::ATTACK_MIN_EVENTS_WAIT; + { + return SSHHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -190,42 +219,52 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); if(!isReported()) - { //no attack yet + { + // no attack yet uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - if (incomingListSize <= Config::getInstance().getRDPListBottomSize() || - outgoingListSize <= Config::getInstance().getRDPListBottomSize()) { + if (std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getRDPListBottomSize()) + { - if(incomingMatched >= Config::getInstance().getRDPListThreshold() || - outgoingMatched >= Config::getInstance().getRDPListThreshold()) { - - //crossed threshold, new attack detected + if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold()) + { + // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return RDPHost::NEW_ATTACK; - } else { - return RDPHost::NO_ATTACK; } - //Number of records is between bottom size and max size - } else { - auto RDP_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * + else + { + return RDPHost::NO_ATTACK; + } + } + else + { + // Number of records is between bottom size and max size + + auto RDP_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * Config::getInstance().getGlobalMatchedFlowRatio()); - if (incomingMatched >= RDP_LIST_TOP_THRESHOLD || outgoingMatched >= RDP_LIST_TOP_THRESHOLD) { - //crossed threshold, new attack detected + if (std::max(incomingMatched, outgoingMatched) >= RDP_LIST_TOP_THRESHOLD) { + // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return RDPHost::NEW_ATTACK; - } else { + } + else + { return RDPHost::NO_ATTACK; } } } else - { //host is attacking, wait for timeout to report again + { + // host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) - return RDPHost::ATTACK_REPORT_WAIT; + { + return RDPHost::ATTACK_REPORT_WAIT; + } else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); @@ -242,26 +281,36 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) double incomingMatchedPercentage = 0.0; if(incomingTotalNew > 0.0) - incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; + { + incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; + } double outgoingMatchedPercentage = 0.0; if(outgoingTotalNew > 0.0) - outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; + { + outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; + } - if (incomingMatchedPercentage < keepTrackingHostRatio && outgoingMatchedPercentage < keepTrackingHostRatio) + if (std::max(incomingMatchedPercentage, outgoingMatchedPercentage) < keepTrackingHostRatio) { - if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) - return RDPHost::REPORT_END_OF_ATTACK; + if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) + { + return RDPHost::REPORT_END_OF_ATTACK; + } else - return RDPHost::END_OF_ATTACK; + { + return RDPHost::END_OF_ATTACK; + } } - if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) - return RDPHost::ATTACK; + if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) + { + return RDPHost::ATTACK; + } else - return RDPHost::ATTACK_MIN_EVENTS_WAIT; + { + return RDPHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -273,16 +322,22 @@ bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direct { IRecord::MatchStructure st = *(IRecord::MatchStructure*) (structure); - //scan => SKIP!!! + // scan => SKIP if(isFlowScan(&st.packets, &st.flags)) - return false; + { + return false; + } else { timeOfLastReceivedRecord = st.flowLastSeen; if(direction == FLOW_INCOMING_DIRECTION) - recordListIncoming.addRecord(record, isReported()); + { + recordListIncoming.addRecord(record, isReported()); + } else - recordListOutgoing.addRecord(record, isReported()); + { + recordListOutgoing.addRecord(record, isReported()); + } return true; } } @@ -293,43 +348,53 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); if(!isReported()) - { //no attack yet + { + // no attack yet uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - if (incomingListSize <= Config::getInstance().getTELNETListBottomSize() || - outgoingListSize <= Config::getInstance().getTELNETListBottomSize()) { + if (std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getTELNETListBottomSize()) + { - if(incomingMatched >= Config::getInstance().getTELNETListThreshold() || - outgoingMatched >= Config::getInstance().getTELNETListThreshold()) { - //crossed threshold, new attack detected + if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold()) + { + // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return TELNETHost::NEW_ATTACK; - } else { + } + else + { return TELNETHost::NO_ATTACK; } - //Number of records is between bottom size and max size - } else { + } + else + { + // Number of records is between bottom size and max size auto TELNET_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * Config::getInstance().getGlobalMatchedFlowRatio()); - if(incomingMatched >= TELNET_LIST_TOP_THRESHOLD || outgoingMatched >= TELNET_LIST_TOP_THRESHOLD) { - //crossed threshold, new attack detected + if(incomingMatched >= TELNET_LIST_TOP_THRESHOLD || outgoingMatched >= TELNET_LIST_TOP_THRESHOLD) + { + // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return TELNETHost::NEW_ATTACK; - } else { + } + else + { return TELNETHost::NO_ATTACK; } } } else - { //host is attacking, wait for timeout to report again + { + // host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) - - return TELNETHost::ATTACK_REPORT_WAIT; + { + return TELNETHost::ATTACK_REPORT_WAIT; + } else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); @@ -340,32 +405,44 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) if(incomingMatched == 0 && incomingMatchedNew == 0 && outgoingMatched == 0 && outgoingMatchedNew == 0) - return TELNETHost::END_OF_ATTACK; + { + return TELNETHost::END_OF_ATTACK; + } double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); double incomingMatchedPercentage = 0.0; if(incomingTotalNew > 0.0) - incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; + { + incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; + } double outgoingMatchedPercentage = 0.0; if(outgoingTotalNew > 0.0) - outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; + { + outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; + } if (incomingMatchedPercentage < keepTrackingHostRatio && outgoingMatchedPercentage < keepTrackingHostRatio) { - if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) - return TELNETHost::REPORT_END_OF_ATTACK; + if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) + { + return TELNETHost::REPORT_END_OF_ATTACK; + } else - return TELNETHost::END_OF_ATTACK; + { + return TELNETHost::END_OF_ATTACK; + } } - if(incomingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingMatchedNew >= Config::getInstance().getGlobalAttackMinEvToReport()) - return TELNETHost::ATTACK; - else - return TELNETHost::ATTACK_MIN_EVENTS_WAIT; + if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) + { + return TELNETHost::ATTACK; + } + else + { + return TELNETHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -378,21 +455,28 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct { ip_addr_t ip; if(direction == FLOW_INCOMING_DIRECTION) - ip = structure->srcIp; + { + ip = structure->srcIp; + } else - ip = structure->dstIp; // + { + ip = structure->dstIp; + } auto it = hostMap.find(ip); SSHHost *host; if(it == hostMap.end()) - { //not found, create new host + { + // not found, create new host host = new SSHHost(ip, structure->flowFirstSeen); hostMap.insert(std::pair(ip, host)); } else - host = it->second; + { + host = it->second; + } return host; } @@ -405,6 +489,7 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) if(host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); + if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_SSH_PORT, actualTime, true); @@ -417,7 +502,7 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { - IHostMap::clearOldRecAHost(&hostMap, actualTime); + IHostMap::clearOldRecAndHost(&hostMap, actualTime); } // ************************************************************/ @@ -428,21 +513,28 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct { ip_addr_t ip; if(direction == FLOW_INCOMING_DIRECTION) - ip = structure->srcIp; + { + ip = structure->srcIp; + } else - ip = structure->dstIp; //attacker is now destination address + { + ip = structure->dstIp; // attacker is now destination address + } auto it = hostMap.find(ip); RDPHost *host; if (it == hostMap.end()) - { //not found, create new host + { + // not found, create new host host = new RDPHost(ip, structure->flowFirstSeen); hostMap.insert(std::pair(ip, host)); } else - host = it->second; + { + host = it->second; + } return host; } @@ -455,6 +547,7 @@ void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) if(host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); + if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_RDP_PORT, actualTime, true); @@ -467,7 +560,7 @@ void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) void RDPHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { - IHostMap::clearOldRecAHost(&hostMap, actualTime); + IHostMap::clearOldRecAndHost(&hostMap, actualTime); } // ************************************************************/ @@ -478,21 +571,28 @@ TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t { ip_addr_t ip; if(direction == FLOW_INCOMING_DIRECTION) - ip = structure->srcIp; + { + ip = structure->srcIp; + } else - ip = structure->dstIp; //attacker is now destination address + { + ip = structure->dstIp; // attacker is now destination address + } auto it = hostMap.find(ip); TELNETHost *host; if(it == hostMap.end()) - { //not found, create new host + { + // not found, create new host host = new TELNETHost(ip, structure->flowFirstSeen); hostMap.insert(std::pair(ip, host)); } else - host = it->second; + { + host = it->second; + } return host; } @@ -505,10 +605,12 @@ void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) if(host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); + if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_TELNET_PORT, actualTime, true); } + host->setNotReported(); host->clearAllRecords(); } @@ -517,5 +619,5 @@ void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) void TELNETHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { - IHostMap::clearOldRecAHost(&hostMap, actualTime); + IHostMap::clearOldRecAndHost(&hostMap, actualTime); } diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 441db784..6d60ba4d 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -147,12 +147,12 @@ class IHost { bool isFlowScan(const uint32_t *packets, const uint8_t *flags) { - if((*packets == 1 && *flags == 0b00000010) //SYN - || (*packets == 2 && *flags == 0b00000010) //SYN - || (*packets == 2 && *flags == 0b00000110) //SYN + RST - || (*packets == 1 && *flags == 0b00010010) //SYN + ACK - || (*packets == 1 && *flags == 0b00010100) //RST + ACK - || (*packets == 3 && *flags == 0b00000010))//3-syn packets + if((*packets == 1 && *flags == 0b00000010) // SYN + || (*packets == 2 && *flags == 0b00000010) // SYN + || (*packets == 2 && *flags == 0b00000110) // SYN + RST + || (*packets == 1 && *flags == 0b00010010) // SYN + ACK + || (*packets == 1 && *flags == 0b00010100) // RST + ACK + || (*packets == 3 && *flags == 0b00000010)) // 3 SYN packets { scanned = true; return true; @@ -172,7 +172,7 @@ class IHost { bool scanned; ip_addr_t hostIp; - ur_time_t firstSeen; + ur_time_t firstSeen; // TODO purpose? ur_time_t timeOfLastReport; ur_time_t timeOfLastReceivedRecord; RecordList recordListIncoming; // direction to victim (attacker -> victim) @@ -192,6 +192,7 @@ class SSHHost : public IHost { ur_time_t getHostAttackTimeout() override { return Config::getInstance().getSSHAttackTimeout(); } }; + class RDPHost : public IHost { public: @@ -216,7 +217,6 @@ class TELNETHost : public IHost { ur_time_t getHostAttackTimeout() override { return Config::getInstance().getTELNETAttackTimeout(); } }; - ////////////////////////////////////////////////////////////////////////////////////// /************************************************************************************/ ////////////////////////////////////////////////////////////////////////////////////// @@ -241,7 +241,7 @@ class IHostMap { auto it = c->begin(); while(it != c->end()) { - //if(it->second) + // if(it->second) delete it->second; it++; @@ -250,7 +250,7 @@ class IHostMap { } template - void clearOldRecAHost(Container *c, ur_time_t actualTime) + void clearOldRecAndHost(Container *c, ur_time_t actualTime) { typename Container::iterator it = c->begin(); while(it != c->end()) @@ -264,7 +264,9 @@ class IHostMap { c->erase(it++); } else - it++; + { + it++; + } } } }; @@ -341,4 +343,4 @@ class TELNETHostMap: public IHostMap { map hostMap; }; -#endif +#endif // HOST_H diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index 61b64901..d93ec297 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -45,20 +45,24 @@ #ifndef SENDER_H #define SENDER_H -#include - -#include -#include "brute_force_detector.h" #include #include +#include + +#include +#include "brute_force_detector.h" #include "config.h" + #ifdef __cplusplus extern "C" { -#endif +#endif // __cplusplus + #include "fields.h" + #ifdef __cplusplus } -#endif +#endif // __cplusplus + #include using namespace std; @@ -78,7 +82,8 @@ class Sender int firstReport(Host *host, uint16_t dstPort, ur_time_t actualTime, uint16_t detectionThreshold) { if(Config::getInstance().getGlobalIgnoreFirstSend()) - { // /Ignore first report + { + // Ignore first report host->setReportTime(actualTime); return TRAP_E_OK; } @@ -104,8 +109,6 @@ class Sender host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToOutgoingRecordList()->clearTotalFlowsSinceLastReport(); - - return send(host, dstPort, actualTime, incomingMatched > outgoingMatched ? incomingMatched : outgoingMatched, endOfAttack, sNote); } @@ -168,4 +171,4 @@ class Sender } }; -#endif +#endif // SENDER_H From e56e806ee4108118cf1d3e1e8f25b03de3fafa66 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Wed, 12 Jun 2019 14:41:26 +0200 Subject: [PATCH 14/40] Aesthetic changes - renaming --- brute_force_detector/brute_force_detector.cpp | 4 +- brute_force_detector/config.h | 40 +++++++++---------- brute_force_detector/host.cpp | 3 +- brute_force_detector/record.cpp | 26 +++++++----- brute_force_detector/record.h | 21 +++++----- 5 files changed, 51 insertions(+), 43 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 372e562f..e5ca3a62 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -667,7 +667,7 @@ int main(int argc, char **argv) FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS); return 0; } - +/* void printHosts(IHostMap& obj) { auto hostMap = obj.hostMap; @@ -676,4 +676,4 @@ void printHosts(IHostMap& obj) cout << item.value << ", "; } } - +*/ diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index a47adbcf..9941e3c4 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -77,16 +77,16 @@ class Config { inline ur_time_t getSSHAttackTimeout() const {return SSH_ATTACK_TIMEOUT;} // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) - inline uint16_t getSSHBFIncMinPackets() const {return SSH_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getSSHBFIncMaxPackets() const {return SSH_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getSSHBFIncMinBytes() const {return SSH_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getSSHBFIncMaxBytes() const {return SSH_BRUTEFORCE_INC_MAX_BYTES;} + inline uint16_t getSSHIncMinPackets() const {return SSH_BRUTEFORCE_INC_MIN_PACKETS;} + inline uint16_t getSSHIncMaxPackets() const {return SSH_BRUTEFORCE_INC_MAX_PACKETS;} + inline uint16_t getSSHIncMinBytes() const {return SSH_BRUTEFORCE_INC_MIN_BYTES;} + inline uint16_t getSSHIncMaxBytes() const {return SSH_BRUTEFORCE_INC_MAX_BYTES;} // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) - inline uint16_t getSSHBFOutMinPackets() const {return SSH_BRUTEFORCE_OUT_MIN_PACKETS;} - inline uint16_t getSSHBFOutMaxPackets() const {return SSH_BRUTEFORCE_OUT_MAX_PACKETS;} - inline uint16_t getSSHBFOutMinBytes() const {return SSH_BRUTEFORCE_OUT_MIN_BYTES;} - inline uint16_t getSSHBFOutMaxBytes() const {return SSH_BRUTEFORCE_OUT_MAX_BYTES;} + inline uint16_t getSSHOutMinPackets() const {return SSH_BRUTEFORCE_OUT_MIN_PACKETS;} + inline uint16_t getSSHOutMaxPackets() const {return SSH_BRUTEFORCE_OUT_MAX_PACKETS;} + inline uint16_t getSSHOutMinBytes() const {return SSH_BRUTEFORCE_OUT_MIN_BYTES;} + inline uint16_t getSSHOutMaxBytes() const {return SSH_BRUTEFORCE_OUT_MAX_BYTES;} //RDP inline uint16_t getRDPListBottomSize() const {return RDP_LIST_SIZE_BOTTOM_THRESHOLD;} @@ -98,16 +98,16 @@ class Config { inline ur_time_t getRDPAttackTimeout() const {return RDP_ATTACK_TIMEOUT;} // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) - inline uint16_t getRDPBFIncMinPackets() const {return RDP_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getRDPBFIncMaxPackets() const {return RDP_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getRDPBFIncMinBytes() const {return RDP_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getRDPBFIncMaxBytes() const {return RDP_BRUTEFORCE_INC_MAX_BYTES;} + inline uint16_t getRDPIncMinPackets() const {return RDP_BRUTEFORCE_INC_MIN_PACKETS;} + inline uint16_t getRDPIncMaxPackets() const {return RDP_BRUTEFORCE_INC_MAX_PACKETS;} + inline uint16_t getRDPIncMinBytes() const {return RDP_BRUTEFORCE_INC_MIN_BYTES;} + inline uint16_t getRDPIncMaxBytes() const {return RDP_BRUTEFORCE_INC_MAX_BYTES;} // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) - inline uint16_t getRDPBFOutMinPackets() const {return RDP_BRUTEFORCE_OUT_MIN_PACKETS;} - inline uint16_t getRDPBFOutMaxPackets() const {return RDP_BRUTEFORCE_OUT_MAX_PACKETS;} - inline uint16_t getRDPBFOutMinBytes() const {return RDP_BRUTEFORCE_OUT_MIN_BYTES;} - inline uint32_t getRDPBFOutMaxBytes() const {return RDP_BRUTEFORCE_OUT_MAX_BYTES;} + inline uint16_t getRDPOutMinPackets() const {return RDP_BRUTEFORCE_OUT_MIN_PACKETS;} + inline uint16_t getRDPOutMaxPackets() const {return RDP_BRUTEFORCE_OUT_MAX_PACKETS;} + inline uint16_t getRDPOutMinBytes() const {return RDP_BRUTEFORCE_OUT_MIN_BYTES;} + inline uint32_t getRDPOutMaxBytes() const {return RDP_BRUTEFORCE_OUT_MAX_BYTES;} //TELNET inline uint16_t getTELNETListBottomSize() const {return TELNET_LIST_SIZE_BOTTOM_THRESHOLD;} @@ -118,10 +118,10 @@ class Config { inline ur_time_t getTELNETReportTimeout() const {return TELNET_REPORT_TIMEOUT;} inline ur_time_t getTELNETAttackTimeout() const {return TELNET_ATTACK_TIMEOUT;} - inline uint16_t getTELNETBFIncMinPackets() const {return TELNET_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getTELNETBFIncMaxPackets() const {return TELNET_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getTELNETBFIncMinBytes() const {return TELNET_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getTELNETBFIncMaxBytes() const {return TELNET_BRUTEFORCE_INC_MAX_BYTES;} + inline uint16_t getTELNETIncMinPackets() const {return TELNET_BRUTEFORCE_INC_MIN_PACKETS;} + inline uint16_t getTELNETIncMaxPackets() const {return TELNET_BRUTEFORCE_INC_MAX_PACKETS;} + inline uint16_t getTELNETIncMinBytes() const {return TELNET_BRUTEFORCE_INC_MIN_BYTES;} + inline uint16_t getTELNETIncMaxBytes() const {return TELNET_BRUTEFORCE_INC_MAX_BYTES;} static Config& getInstance() { diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index c283451b..22750ca3 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -92,14 +92,13 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) // Number of records in list is lower than BottomSize (set to 50 by default) - if ( std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getSSHListBottomSize()) + if (std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getSSHListBottomSize()) { if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold()) { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); - return SSHHost::NEW_ATTACK; } else diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index f7b7bc02..0804f6f9 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -65,12 +65,13 @@ bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getSSHBFIncMaxPackets() || st.packets < Config::getInstance().getSSHBFIncMinPackets()) + if(st.packets > Config::getInstance().getSSHIncMaxPackets() || st.packets < + Config::getInstance().getSSHIncMinPackets()) { return false; } - if(st.bytes > Config::getInstance().getSSHBFIncMaxBytes() || st.bytes < Config::getInstance().getSSHBFIncMinBytes()) + if(st.bytes > Config::getInstance().getSSHIncMaxBytes() || st.bytes < Config::getInstance().getSSHIncMinBytes()) { return false; } @@ -93,12 +94,13 @@ bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getSSHBFOutMaxPackets() || st.packets < Config::getInstance().getSSHBFOutMinPackets()) + if(st.packets > Config::getInstance().getSSHOutMaxPackets() || st.packets < + Config::getInstance().getSSHOutMinPackets()) { return false; } - if(st.bytes > Config::getInstance().getSSHBFOutMaxBytes() || st.bytes < Config::getInstance().getSSHBFOutMinBytes()) + if(st.bytes > Config::getInstance().getSSHOutMaxBytes() || st.bytes < Config::getInstance().getSSHOutMinBytes()) { return false; } @@ -172,11 +174,12 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getRDPBFIncMaxPackets() || st.packets < Config::getInstance().getRDPBFIncMinPackets()) + if(st.packets > Config::getInstance().getRDPIncMaxPackets() || st.packets < + Config::getInstance().getRDPIncMinPackets()) { return false; } - if(st.bytes > Config::getInstance().getRDPBFIncMaxBytes() || st.bytes < Config::getInstance().getRDPBFIncMinBytes()) + if(st.bytes > Config::getInstance().getRDPIncMaxBytes() || st.bytes < Config::getInstance().getRDPIncMinBytes()) { return false; } @@ -238,11 +241,12 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getRDPBFOutMaxPackets() || st.packets < Config::getInstance().getRDPBFOutMinPackets()) + if(st.packets > Config::getInstance().getRDPOutMaxPackets() || st.packets < + Config::getInstance().getRDPOutMinPackets()) { return false; } - if(st.bytes > Config::getInstance().getRDPBFOutMaxBytes() || st.bytes < Config::getInstance().getRDPBFOutMinBytes()) + if(st.bytes > Config::getInstance().getRDPOutMaxBytes() || st.bytes < Config::getInstance().getRDPOutMinBytes()) { return false; } @@ -279,11 +283,13 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getTELNETBFIncMaxPackets() || st.packets < Config::getInstance().getTELNETBFIncMinPackets()) + if(st.packets > Config::getInstance().getTELNETIncMaxPackets() || st.packets < + Config::getInstance().getTELNETIncMinPackets()) { return false; } - if(st.bytes > Config::getInstance().getTELNETBFIncMaxBytes() || st.bytes < Config::getInstance().getTELNETBFIncMinBytes()) + if(st.bytes > Config::getInstance().getTELNETIncMaxBytes() || st.bytes < + Config::getInstance().getTELNETIncMinBytes()) { return false; } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 45ec23ee..61f3122b 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -52,8 +52,8 @@ #include #include -#include //ip_addr_t -#include //ur_time_t +#include // ip_addr_t +#include // ur_time_t #include "brute_force_detector.h" #include "whitelist.h" #include "config.h" @@ -188,12 +188,12 @@ class RecordList { uint32_t flowCounter; uint32_t flowMatchedCounter; - std::set hashedDstIPSet; - std::set hashedDstTotalIPSet; + std::set hashedDstIPSet; // TODO WHAT ARE THOSE? + std::set hashedDstTotalIPSet; // AND WHY ARE NEITHER EVER USED ANYWHERE ELSE? char victimIP[46]{}; - bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) + static inline bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) { return flowTime + timer <= actualTime; } @@ -267,15 +267,18 @@ void RecordList::addRecord(T record, bool isHostReported) { flowCounter++; actualListSize++; + if(actualListSize > maxListSize) - { //list is full - //delete first record + { + // list is full + // delete first record if((*list.begin())->isMatched()) { actualMatchedFlows--; } T recToDelete = list.front(); delete recToDelete; + list.pop_front(); actualListSize--; } @@ -299,7 +302,7 @@ void RecordList::addRecord(T record, bool isHostReported) } } - list.push_back(record); //finally push record to a list + list.push_back(record); // finally push record to a list } template @@ -311,7 +314,7 @@ void RecordList::setNewMaxListSize(uint16_t newMaxListSize) { while (actualListSize > newMaxListSize) { - //delete first record + // delete first record T recToDelete = list.front(); if (recToDelete->isMatched()) From dad4092845779ac47f7619d7669441689493dc17 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Wed, 12 Jun 2019 15:19:59 +0200 Subject: [PATCH 15/40] Switched calculating target matched/total ratio, !review truncation err! --- brute_force_detector/host.cpp | 41 ++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 22750ca3..d9637034 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -79,6 +79,7 @@ bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) } } + SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); @@ -93,6 +94,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) // Number of records in list is lower than BottomSize (set to 50 by default) if (std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getSSHListBottomSize()) + /// possible bug: lot of flows in one direction (50%), few flows in opposite direction -> passes as attack FIXME { if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold()) { @@ -109,12 +111,11 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } else { - // Number of records is between bottom size and max size + // Number of records is between bottom size and max size TODO What max size -max list size? - auto SSH_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * - Config::getInstance().getGlobalMatchedFlowRatio()); + auto top_matched_ratio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); - if(std::max(incomingMatched, outgoingMatched) >= SSH_LIST_TOP_THRESHOLD) + if(top_matched_ratio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -128,7 +129,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } } else - { // host is attacking, wait for timeout to report again + { + // host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) { return SSHHost::ATTACK_REPORT_WAIT; @@ -150,13 +152,13 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); double incomingMatchedPercentage = 0.0; - if(incomingTotalNew > 0.0) + if(incomingTotalNew > 0) { incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; } double outgoingMatchedPercentage = 0.0; - if(outgoingTotalNew > 0.0) + if(outgoingTotalNew > 0) { outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; } @@ -231,6 +233,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); + return RDPHost::NEW_ATTACK; } else @@ -242,13 +245,14 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max size - auto RDP_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * - Config::getInstance().getGlobalMatchedFlowRatio()); + auto top_matched_ratio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); - if (std::max(incomingMatched, outgoingMatched) >= RDP_LIST_TOP_THRESHOLD) { + if(top_matched_ratio >= Config::getInstance().getGlobalMatchedFlowRatio()) + { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); + return RDPHost::NEW_ATTACK; } else @@ -274,18 +278,20 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) if(incomingMatched == 0 && incomingMatchedNew == 0 && outgoingMatched == 0 && outgoingMatchedNew == 0) - return RDPHost::END_OF_ATTACK; + { + return RDPHost::END_OF_ATTACK; + } double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); double incomingMatchedPercentage = 0.0; - if(incomingTotalNew > 0.0) + if(incomingTotalNew > 0) { incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; } double outgoingMatchedPercentage = 0.0; - if(outgoingTotalNew > 0.0) + if(outgoingTotalNew > 0) { outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; } @@ -371,10 +377,9 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max size - auto TELNET_LIST_TOP_THRESHOLD = (uint16_t) (std::max(incomingListSize, outgoingListSize) * - Config::getInstance().getGlobalMatchedFlowRatio()); + auto top_matched_ratio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); - if(incomingMatched >= TELNET_LIST_TOP_THRESHOLD || outgoingMatched >= TELNET_LIST_TOP_THRESHOLD) + if(top_matched_ratio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -411,13 +416,13 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); double incomingMatchedPercentage = 0.0; - if(incomingTotalNew > 0.0) + if(incomingTotalNew > 0) { incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; } double outgoingMatchedPercentage = 0.0; - if(outgoingTotalNew > 0.0) + if(outgoingTotalNew > 0) { outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; } From 7630306c53a1e9903edc5c5420ba654923e43d67 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 13 Jun 2019 14:38:11 +0200 Subject: [PATCH 16/40] Aesthetic changes --- brute_force_detector/brute_force_detector.cpp | 4 +++- brute_force_detector/record.cpp | 18 ++++++------------ brute_force_detector/record.h | 11 +++-------- brute_force_detector/sender.cpp | 18 ++++++++++-------- 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index e5ca3a62..3b85e280 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -400,7 +400,9 @@ int main(int argc, char **argv) } if(is_matched) - ssh.matchedFlows++; + { + ssh.matchedFlows++; + } ssh.flows++; // host is the source of current flow/connection diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 0804f6f9..10c6df49 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -65,8 +65,7 @@ bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getSSHIncMaxPackets() || st.packets < - Config::getInstance().getSSHIncMinPackets()) + if(st.packets > Config::getInstance().getSSHIncMaxPackets() || st.packets < Config::getInstance().getSSHIncMinPackets()) { return false; } @@ -94,8 +93,7 @@ bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getSSHOutMaxPackets() || st.packets < - Config::getInstance().getSSHOutMinPackets()) + if(st.packets > Config::getInstance().getSSHOutMaxPackets() || st.packets < Config::getInstance().getSSHOutMinPackets()) { return false; } @@ -174,8 +172,7 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getRDPIncMaxPackets() || st.packets < - Config::getInstance().getRDPIncMinPackets()) + if(st.packets > Config::getInstance().getRDPIncMaxPackets() || st.packets < Config::getInstance().getRDPIncMinPackets()) { return false; } @@ -241,8 +238,7 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getRDPOutMaxPackets() || st.packets < - Config::getInstance().getRDPOutMinPackets()) + if(st.packets > Config::getInstance().getRDPOutMaxPackets() || st.packets < Config::getInstance().getRDPOutMinPackets()) { return false; } @@ -283,13 +279,11 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return false; } - if(st.packets > Config::getInstance().getTELNETIncMaxPackets() || st.packets < - Config::getInstance().getTELNETIncMinPackets()) + if(st.packets > Config::getInstance().getTELNETIncMaxPackets() || st.packets < Config::getInstance().getTELNETIncMinPackets()) { return false; } - if(st.bytes > Config::getInstance().getTELNETIncMaxBytes() || st.bytes < - Config::getInstance().getTELNETIncMinBytes()) + if(st.bytes > Config::getInstance().getTELNETIncMaxBytes() || st.bytes < Config::getInstance().getTELNETIncMinBytes()) { return false; } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 61f3122b..6ad81a08 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -93,7 +93,7 @@ class IRecord { ur_time_t flowLastSeen; }; - // TODO Why is it even here? + // May seem unused, actually are passed to reporting functions ip_addr_t dstIp{}; ur_time_t flowLastSeen{}; @@ -111,8 +111,6 @@ class SSHRecord : public IRecord { ur_time_t getRecordTimeout() override { return Config::getInstance().getSSHRecordTimeout(); } const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH - - }; class RDPRecord : public IRecord { @@ -126,11 +124,9 @@ class RDPRecord : public IRecord { const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; // SYN + ACK + PSH + RST const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; // SYN + ACK + PSH const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH - - - }; + class TELNETRecord : public IRecord { public: @@ -142,7 +138,6 @@ class TELNETRecord : public IRecord { const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH const static uint8_t signatureFlagsFin = 0b00011011; // SYN + ACK + PSH + FIN - private: static TelnetServerProfileMap TSPMap; }; @@ -301,7 +296,6 @@ void RecordList::addRecord(T record, bool isHostReported) hashedDstTotalIPSet.insert(record->dstIp); } } - list.push_back(record); // finally push record to a list } @@ -395,6 +389,7 @@ void RecordList::initTotalTargetsSet() { if(it->isMatched()) { + // TODO Why is TotalIPSet filled with matched flows only? hashedDstTotalIPSet.insert(it->dstIp); } } diff --git a/brute_force_detector/sender.cpp b/brute_force_detector/sender.cpp index 9b4464cf..8d4553fb 100644 --- a/brute_force_detector/sender.cpp +++ b/brute_force_detector/sender.cpp @@ -45,13 +45,13 @@ #include "sender.h" UR_FIELDS( - time DETECTION_TIME, //Timestamp of the detection of some event - uint8 WARDEN_TYPE, //Type of event (see Warden README for more information) - ipaddr SRC_IP, //Source address of a flow - uint8 PROTOCOL, //L4 protocol (TCP, UDP, ICMP, etc.) - uint16 DST_PORT, //Destination transport-layer port - uint32 EVENT_SCALE, //Attack intensity - string NOTE, //Generic string note + time DETECTION_TIME, // Timestamp of the detection of some event + uint8 WARDEN_TYPE, // Type of event (see Warden README for more information) + ipaddr SRC_IP, // Source address of a flow + uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint16 DST_PORT, // Destination transport-layer port + uint32 EVENT_SCALE, // Attack intensity + string NOTE, // Generic string note ) @@ -71,7 +71,9 @@ Sender::Sender(bool *success) Sender::~Sender() { if(outTemplate != nullptr) - ur_free_template (outTemplate); + { + ur_free_template (outTemplate); + } } From 24be9c8e1f7266f8e6e6a8f944dfacb71ce5ab81 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 13 Jun 2019 14:39:17 +0200 Subject: [PATCH 17/40] Renamed HostTimeout, simplified keepTrackingHost of checkForAttack --- brute_force_detector/config.cpp | 8 ++- brute_force_detector/config.h | 6 +-- brute_force_detector/host.cpp | 88 +++++++++++---------------------- brute_force_detector/host.h | 6 +-- 4 files changed, 41 insertions(+), 67 deletions(-) diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index 08ed8a96..cd8fe83d 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -214,10 +214,14 @@ bool Config::initFromFile(const string& path) getline(configFile, line); if(line.empty()) - continue; //skip empty line + { + continue; //skip empty line + } if(line[0] == '#') - continue; //skip comment line + { + continue; //skip comment line + } size_t pos = line.find('='); // = delimiter if(pos == std::string::npos) diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index 9941e3c4..d99cd64c 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -72,7 +72,7 @@ class Config { inline uint16_t getSSHListThreshold() const {return SSH_LIST_THRESHOLD;} inline ur_time_t getSSHRecordTimeout() const {return SSH_RECORD_TIMEOUT;} - inline ur_time_t getSSHHostTimeout() const {return SSH_HOST_TIMEOUT;} + inline ur_time_t getSSHHostDeleteTimeout() const {return SSH_HOST_TIMEOUT;} inline ur_time_t getSSHReportTimeout() const {return SSH_REPORT_TIMEOUT;} inline ur_time_t getSSHAttackTimeout() const {return SSH_ATTACK_TIMEOUT;} @@ -93,7 +93,7 @@ class Config { inline uint16_t getRDPMaxListSize() const {return RDP_LIST_SIZE;} inline uint16_t getRDPListThreshold() const {return RDP_LIST_THRESHOLD;} inline ur_time_t getRDPRecordTimeout() const {return RDP_RECORD_TIMEOUT;} - inline ur_time_t getRDPHostTimeout() const {return RDP_HOST_TIMEOUT;} + inline ur_time_t getRDPHostDeleteTimeout() const {return RDP_HOST_TIMEOUT;} inline ur_time_t getRDPReportTimeout() const {return RDP_REPORT_TIMEOUT;} inline ur_time_t getRDPAttackTimeout() const {return RDP_ATTACK_TIMEOUT;} @@ -114,7 +114,7 @@ class Config { inline uint16_t getTELNETMaxListSize() const {return TELNET_LIST_SIZE;} inline uint16_t getTELNETListThreshold() const {return TELNET_LIST_THRESHOLD;} inline ur_time_t getTELNETRecordTimeout() const {return TELNET_RECORD_TIMEOUT;} - inline ur_time_t getTELNETHostTimeout() const {return TELNET_HOST_TIMEOUT;} + inline ur_time_t getTELNETHostDeleteTimeout() const {return TELNET_HOST_TIMEOUT;} inline ur_time_t getTELNETReportTimeout() const {return TELNET_REPORT_TIMEOUT;} inline ur_time_t getTELNETAttackTimeout() const {return TELNET_ATTACK_TIMEOUT;} diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index d9637034..92c6859e 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -51,7 +51,7 @@ bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) { IRecord::MatchStructure st = *(IRecord::MatchStructure*) (structure); - // scan => SKIP!!! + // ignore port-scans if(isFlowScan(&st.packets, &st.flags)) { return false; @@ -92,9 +92,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - // Number of records in list is lower than BottomSize (set to 50 by default) - if (std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getSSHListBottomSize()) - /// possible bug: lot of flows in one direction (50%), few flows in opposite direction -> passes as attack FIXME + // Number of records in list is lower than BottomSize (50 by default) + if (std::max(incomingListSize, outgoingListSize) <= Config::getInstance().getSSHListBottomSize()) { if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold()) { @@ -111,11 +110,11 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } else { - // Number of records is between bottom size and max size TODO What max size -max list size? + // Number of records is between bottom size and max size TODO What max size -max list size? per host or total max? - auto top_matched_ratio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); - if(top_matched_ratio >= Config::getInstance().getGlobalMatchedFlowRatio()) + if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -128,7 +127,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } } } - else + else // isReported { // host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) @@ -149,21 +148,11 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) return SSHHost::END_OF_ATTACK; } - double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - - double incomingMatchedPercentage = 0.0; - if(incomingTotalNew > 0) - { - incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; - } - - double outgoingMatchedPercentage = 0.0; - if(outgoingTotalNew > 0) - { - outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; - } - - if (std::max(incomingMatchedPercentage, outgoingMatchedPercentage) < keepTrackingHostRatio) + auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + + auto topNewMatchedRatio = std::max(incomingMatchedNew / incomingTotalNew, outgoingMatchedNew / outgoingTotalNew); + + if (topNewMatchedRatio < keepTrackingHostRatio) { if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { @@ -225,7 +214,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - if (std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getRDPListBottomSize()) + if (std::max(incomingListSize, outgoingListSize) <= Config::getInstance().getRDPListBottomSize()) { if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold()) @@ -245,9 +234,9 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max size - auto top_matched_ratio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); - if(top_matched_ratio >= Config::getInstance().getGlobalMatchedFlowRatio()) + if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -282,22 +271,12 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) return RDPHost::END_OF_ATTACK; } - double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double incomingMatchedPercentage = 0.0; - if(incomingTotalNew > 0) - { - incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; - } - - double outgoingMatchedPercentage = 0.0; - if(outgoingTotalNew > 0) + auto topNewMatchedRatio = std::max(incomingMatchedNew / incomingTotalNew, outgoingMatchedNew / outgoingTotalNew); + + if (topNewMatchedRatio < keepTrackingHostRatio) { - outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; - } - - if (std::max(incomingMatchedPercentage, outgoingMatchedPercentage) < keepTrackingHostRatio) - { if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return RDPHost::REPORT_END_OF_ATTACK; @@ -327,7 +306,7 @@ bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direct { IRecord::MatchStructure st = *(IRecord::MatchStructure*) (structure); - // scan => SKIP + // ignore port-scans if(isFlowScan(&st.packets, &st.flags)) { return false; @@ -358,7 +337,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - if (std::min(incomingListSize, outgoingListSize) <= Config::getInstance().getTELNETListBottomSize()) + if (std::max(incomingListSize, outgoingListSize) <= Config::getInstance().getTELNETListBottomSize()) { if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold()) @@ -366,6 +345,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); + return TELNETHost::NEW_ATTACK; } else @@ -377,9 +357,9 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max size - auto top_matched_ratio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); - if(top_matched_ratio >= Config::getInstance().getGlobalMatchedFlowRatio()) + if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); @@ -413,22 +393,12 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) return TELNETHost::END_OF_ATTACK; } - double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - - double incomingMatchedPercentage = 0.0; - if(incomingTotalNew > 0) - { - incomingMatchedPercentage = (100.0 / incomingTotalNew) * incomingMatchedNew; - } - - double outgoingMatchedPercentage = 0.0; - if(outgoingTotalNew > 0) + auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + + auto topNewMatchedRatio = std::max(incomingMatchedNew / incomingTotalNew, outgoingMatchedNew / outgoingTotalNew); + + if (topNewMatchedRatio < keepTrackingHostRatio) { - outgoingMatchedPercentage = (100.0 / outgoingTotalNew) * outgoingMatchedNew; - } - - if (incomingMatchedPercentage < keepTrackingHostRatio && outgoingMatchedPercentage < keepTrackingHostRatio) - { if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return TELNETHost::REPORT_END_OF_ATTACK; diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 6d60ba4d..56668609 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -187,7 +187,7 @@ class SSHHost : public IHost { bool addRecord(SSHRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostTimeout(); } + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getSSHReportTimeout(); } ur_time_t getHostAttackTimeout() override { return Config::getInstance().getSSHAttackTimeout(); } }; @@ -200,7 +200,7 @@ class RDPHost : public IHost { bool addRecord(RDPRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostTimeout(); } + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getRDPReportTimeout(); } ur_time_t getHostAttackTimeout() override { return Config::getInstance().getRDPAttackTimeout(); } }; @@ -212,7 +212,7 @@ class TELNETHost : public IHost { bool addRecord(TELNETRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostTimeout(); } + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getTELNETReportTimeout(); } ur_time_t getHostAttackTimeout() override { return Config::getInstance().getTELNETAttackTimeout(); } }; From 265fb34d2863182081af39f6dc195e7bf189c5ba Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 13 Jun 2019 14:47:28 +0200 Subject: [PATCH 18/40] Improvement on keepTrackingHost part of checkForAttack --- brute_force_detector/host.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 92c6859e..577e727d 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -150,9 +150,10 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - auto topNewMatchedRatio = std::max(incomingMatchedNew / incomingTotalNew, outgoingMatchedNew / outgoingTotalNew); + double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); + double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); - if (topNewMatchedRatio < keepTrackingHostRatio) + if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { @@ -272,10 +273,11 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) } auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - - auto topNewMatchedRatio = std::max(incomingMatchedNew / incomingTotalNew, outgoingMatchedNew / outgoingTotalNew); - if (topNewMatchedRatio < keepTrackingHostRatio) + double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); + double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); + + if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { @@ -395,9 +397,10 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - auto topNewMatchedRatio = std::max(incomingMatchedNew / incomingTotalNew, outgoingMatchedNew / outgoingTotalNew); + double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); + double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); - if (topNewMatchedRatio < keepTrackingHostRatio) + if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { From a033913401c85b5cce5e38629e9fc0ab3c909558 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Fri, 14 Jun 2019 14:00:12 +0200 Subject: [PATCH 19/40] Mostly aesthetic changes --- brute_force_detector/README.md | 5 +- brute_force_detector/brute_force_detector.cpp | 67 +++++++++++-------- brute_force_detector/config.h | 28 ++++---- brute_force_detector/host.cpp | 21 +++--- brute_force_detector/host.h | 26 ++++--- brute_force_detector/record.cpp | 37 +++++----- brute_force_detector/record.h | 34 +++++----- brute_force_detector/sender.h | 2 +- .../telnet_server_profile.cpp | 60 +++++++++-------- 9 files changed, 150 insertions(+), 130 deletions(-) diff --git a/brute_force_detector/README.md b/brute_force_detector/README.md index a6cc4815..9716fb4f 100644 --- a/brute_force_detector/README.md +++ b/brute_force_detector/README.md @@ -46,12 +46,13 @@ Unirec template for output interface is `DETECTION_TIME,WARDEN_TYPE,SRC_IP,PROTO * `PROTOCOL` : TCP protocol number * `DST_PORT` : Port of the attacked service * `EVENT_SCALE` : Scale of the detected event -* `NOTE` : This field contains (comma is used as separator): +* `NOTE` : This field contains (comma is used as separator): + 1. Total number of targets since start of the attack from both directions separated by a dash 2. Flag if the scan is performed 3. Number of suspicious flows from both directions and since -last report separated by a dash +last report separated by a dash How to use diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 3b85e280..ef67cc6e 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -129,16 +129,24 @@ void signalHandler(int signal) else if(signal == SIGUSR2) { if(!whitelist.isLockedForConfigurationReload()) - whitelist.reloadWhitelist(); + { + whitelist.reloadWhitelist(); + } else - alarm(1); // cannot reload now.. wait + { + alarm(1); // cannot reload now.. wait + } } else if(signal == SIGALRM) { if(!whitelist.isLockedForConfigurationReload()) - whitelist.reloadWhitelist(); + { + whitelist.reloadWhitelist(); + } else - alarm(1); // wait another second + { + alarm(1); // wait another second + } } } @@ -150,7 +158,8 @@ bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t actualTime) void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment /* optional, implicitly set to "" (see .h) */) { - if (b && p) { + if (b && p) + { ios::fmtflags f(cout.flags()); cout << " (" << std::fixed << std::setprecision(2) @@ -164,7 +173,6 @@ void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment /* opti } // error output not necessary */ - } @@ -275,9 +283,11 @@ int main(int argc, char **argv) char *errstr = nullptr; ur_template_t *tmplt = ur_create_input_template(0, unirecSpecifier.c_str(), &errstr); - if (tmplt == nullptr) { + if (tmplt == nullptr) + { cerr << "Error: Invalid UniRec specifier." << endl; - if(errstr != nullptr){ + if(errstr != nullptr) + { fprintf(stderr, "%s\n", errstr); free(errstr); } @@ -300,12 +310,11 @@ int main(int argc, char **argv) return 4; } - // ***** Main processing loop ***** SSHHostMap sshHostMap; RDPHostMap rdpHostMap; TELNETHostMap telnetHostMap; - + logInfo ssh("SSH"); logInfo rdp("RDP"); logInfo telnet("TELNET"); @@ -341,20 +350,28 @@ int main(int argc, char **argv) // Skip non TCP flows if(ur_get(tmplt, data, F_PROTOCOL) != TCP_PROTOCOL_NUM) // TCP flows only - continue; + { + continue; + } uint16_t dstPort = ur_get(tmplt, data, F_DST_PORT); uint16_t srcPort = ur_get(tmplt, data, F_SRC_PORT); if(dstPort != TCP_SSH_PORT && dstPort != TCP_TELNET_PORT && dstPort != TCP_RDP_PORT && srcPort != TCP_SSH_PORT && srcPort != TCP_TELNET_PORT && srcPort != TCP_RDP_PORT) - continue; + { + continue; + } uint8_t direction; if(dstPort == TCP_SSH_PORT || dstPort == TCP_TELNET_PORT || dstPort == TCP_RDP_PORT) - direction = FLOW_INCOMING_DIRECTION; + { + direction = FLOW_INCOMING_DIRECTION; + } else - direction = FLOW_OUTGOING_DIRECTION; + { + direction = FLOW_OUTGOING_DIRECTION; + } // Process rest of new data IRecord::MatchStructure structure { // TODO proper name @@ -389,7 +406,6 @@ int main(int argc, char **argv) } else // FLOW_OUTGOING_DIRECTION { - record = new SSHRecord(structure.srcIp, structure.flowLastSeen); is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); if(is_matched) @@ -467,7 +483,8 @@ int main(int argc, char **argv) rdp.incomingFlows++; } else - { // FLOW_OUTGOING_DIRECTION + { + // FLOW_OUTGOING_DIRECTION record = new RDPRecord(structure.srcIp, structure.flowLastSeen); is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); if(is_matched) @@ -491,7 +508,8 @@ int main(int argc, char **argv) delete record; } else - { // check for attack + { + // check for attack RDPHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != RDPHost::NO_ATTACK) { @@ -567,7 +585,8 @@ int main(int argc, char **argv) delete record; } else - { // check for attack + { + // check for attack TELNETHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != TELNETHost::NO_ATTACK) { @@ -638,7 +657,7 @@ int main(int argc, char **argv) } // kontrola po odeslani - TRAP_DEFAULT_SEND_DATA_ERROR_HANDLING(ret, continue, break); + TRAP_DEFAULT_SEND_ERROR_HANDLING(ret, continue, break); } // ***** End of main processing loop ***** @@ -669,13 +688,3 @@ int main(int argc, char **argv) FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS); return 0; } -/* -void printHosts(IHostMap& obj) -{ - auto hostMap = obj.hostMap; - for(auto & item : obj) - { - cout << item.value << ", "; - } -} -*/ diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index d99cd64c..5b8a7579 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -63,16 +63,16 @@ class Config { inline ur_time_t getGlobalAttackMinEvToReport() const {return GENERAL_ATTACK_MIN_EVENTS_TO_REPORT;} inline double getGlobalAttackMinRatioToKeepTrackingHost() const {return GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST;} - inline int getGlobalIgnoreFirstSend() const {return GENERAL_IGNORE_FIRST_SEND;} + inline int getGlobalIgnoreFirstSend() const {return GENERAL_IGNORE_FIRST_SEND;} inline double getGlobalMatchedFlowRatio() const {return GENERAL_MATCHED_FLOW_RATIO;} - //SSH - inline uint16_t getSSHMaxListSize() const {return SSH_LIST_SIZE;} + //SSH + inline uint16_t getSSHMaxListSize() const {return SSH_LIST_SIZE;} inline uint16_t getSSHListBottomSize() const {return SSH_LIST_SIZE_BOTTOM_THRESHOLD;} inline uint16_t getSSHListThreshold() const {return SSH_LIST_THRESHOLD;} inline ur_time_t getSSHRecordTimeout() const {return SSH_RECORD_TIMEOUT;} - inline ur_time_t getSSHHostDeleteTimeout() const {return SSH_HOST_TIMEOUT;} + inline ur_time_t getSSHHostDeleteTimeout() const {return SSH_HOST_TIMEOUT;} inline ur_time_t getSSHReportTimeout() const {return SSH_REPORT_TIMEOUT;} inline ur_time_t getSSHAttackTimeout() const {return SSH_ATTACK_TIMEOUT;} @@ -81,19 +81,19 @@ class Config { inline uint16_t getSSHIncMaxPackets() const {return SSH_BRUTEFORCE_INC_MAX_PACKETS;} inline uint16_t getSSHIncMinBytes() const {return SSH_BRUTEFORCE_INC_MIN_BYTES;} inline uint16_t getSSHIncMaxBytes() const {return SSH_BRUTEFORCE_INC_MAX_BYTES;} - + // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) inline uint16_t getSSHOutMinPackets() const {return SSH_BRUTEFORCE_OUT_MIN_PACKETS;} inline uint16_t getSSHOutMaxPackets() const {return SSH_BRUTEFORCE_OUT_MAX_PACKETS;} inline uint16_t getSSHOutMinBytes() const {return SSH_BRUTEFORCE_OUT_MIN_BYTES;} inline uint16_t getSSHOutMaxBytes() const {return SSH_BRUTEFORCE_OUT_MAX_BYTES;} - + //RDP inline uint16_t getRDPListBottomSize() const {return RDP_LIST_SIZE_BOTTOM_THRESHOLD;} inline uint16_t getRDPMaxListSize() const {return RDP_LIST_SIZE;} inline uint16_t getRDPListThreshold() const {return RDP_LIST_THRESHOLD;} inline ur_time_t getRDPRecordTimeout() const {return RDP_RECORD_TIMEOUT;} - inline ur_time_t getRDPHostDeleteTimeout() const {return RDP_HOST_TIMEOUT;} + inline ur_time_t getRDPHostDeleteTimeout() const {return RDP_HOST_TIMEOUT;} inline ur_time_t getRDPReportTimeout() const {return RDP_REPORT_TIMEOUT;} inline ur_time_t getRDPAttackTimeout() const {return RDP_ATTACK_TIMEOUT;} @@ -102,7 +102,7 @@ class Config { inline uint16_t getRDPIncMaxPackets() const {return RDP_BRUTEFORCE_INC_MAX_PACKETS;} inline uint16_t getRDPIncMinBytes() const {return RDP_BRUTEFORCE_INC_MIN_BYTES;} inline uint16_t getRDPIncMaxBytes() const {return RDP_BRUTEFORCE_INC_MAX_BYTES;} - + // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) inline uint16_t getRDPOutMinPackets() const {return RDP_BRUTEFORCE_OUT_MIN_PACKETS;} inline uint16_t getRDPOutMaxPackets() const {return RDP_BRUTEFORCE_OUT_MAX_PACKETS;} @@ -114,7 +114,7 @@ class Config { inline uint16_t getTELNETMaxListSize() const {return TELNET_LIST_SIZE;} inline uint16_t getTELNETListThreshold() const {return TELNET_LIST_THRESHOLD;} inline ur_time_t getTELNETRecordTimeout() const {return TELNET_RECORD_TIMEOUT;} - inline ur_time_t getTELNETHostDeleteTimeout() const {return TELNET_HOST_TIMEOUT;} + inline ur_time_t getTELNETHostDeleteTimeout()const {return TELNET_HOST_TIMEOUT;} inline ur_time_t getTELNETReportTimeout() const {return TELNET_REPORT_TIMEOUT;} inline ur_time_t getTELNETAttackTimeout() const {return TELNET_ATTACK_TIMEOUT;} @@ -123,6 +123,8 @@ class Config { inline uint16_t getTELNETIncMinBytes() const {return TELNET_BRUTEFORCE_INC_MIN_BYTES;} inline uint16_t getTELNETIncMaxBytes() const {return TELNET_BRUTEFORCE_INC_MAX_BYTES;} + // TODO Where is telnet outgoing + static Config& getInstance() { static Config instance; @@ -142,7 +144,7 @@ class Config { double GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; uint8_t GENERAL_IGNORE_FIRST_SEND; float GENERAL_MATCHED_FLOW_RATIO; - + std::string kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT; std::string kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT; std::string kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; @@ -166,11 +168,11 @@ class Config { uint16_t SSH_BRUTEFORCE_INC_MAX_PACKETS; uint16_t SSH_BRUTEFORCE_INC_MIN_BYTES; uint16_t SSH_BRUTEFORCE_INC_MAX_BYTES; - + uint16_t SSH_BRUTEFORCE_OUT_MIN_PACKETS; uint16_t SSH_BRUTEFORCE_OUT_MAX_PACKETS; uint16_t SSH_BRUTEFORCE_OUT_MIN_BYTES; - uint16_t SSH_BRUTEFORCE_OUT_MAX_BYTES; + uint16_t SSH_BRUTEFORCE_OUT_MAX_BYTES; //SSH keywords std::string kw_SSH_LIST_SIZE; @@ -203,7 +205,7 @@ class Config { uint16_t RDP_BRUTEFORCE_INC_MAX_PACKETS; uint16_t RDP_BRUTEFORCE_INC_MIN_BYTES; uint16_t RDP_BRUTEFORCE_INC_MAX_BYTES; - + uint16_t RDP_BRUTEFORCE_OUT_MIN_PACKETS; uint16_t RDP_BRUTEFORCE_OUT_MAX_PACKETS; uint16_t RDP_BRUTEFORCE_OUT_MIN_BYTES; diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 577e727d..f88a117c 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -106,11 +106,10 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { return SSHHost::NO_ATTACK; } - } else { - // Number of records is between bottom size and max size TODO What max size -max list size? per host or total max? + // Number of records is between bottom size and max list size per protocol auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); @@ -125,7 +124,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { return SSHHost::NO_ATTACK; } - } + } } else // isReported { @@ -138,7 +137,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); - + uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); @@ -249,9 +248,9 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { return RDPHost::NO_ATTACK; } - } + } } - else + else // isReported { // host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) @@ -262,7 +261,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); - + uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); @@ -372,9 +371,9 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { return TELNETHost::NO_ATTACK; } - } + } } - else + else // isReported { // host is attacking, wait for timeout to report again if(!canReportAgain(actualTime)) @@ -385,7 +384,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); - + uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); @@ -497,7 +496,7 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct { ip = structure->dstIp; // attacker is now destination address } - + auto it = hostMap.find(ip); RDPHost *host; diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 56668609..cec6ac67 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -92,28 +92,32 @@ class IHost { virtual bool addRecord(T record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) { if(direction == FLOW_INCOMING_DIRECTION) - recordListIncoming.addRecord(record, isReported()); + { + recordListIncoming.addRecord(record, isReported()); + } else - recordListOutgoing.addRecord(record, isReported()); + { + recordListOutgoing.addRecord(record, isReported()); + } return true; } void clearOldRecords(ur_time_t actualTime) { recordListIncoming.clearOldRecords(actualTime); recordListOutgoing.clearOldRecords(actualTime);} - - - virtual ur_time_t getHostDeleteTimeout() = 0; - + + + virtual ur_time_t getHostDeleteTimeout() = 0; + virtual bool canDeleteHost(ur_time_t actualTime) { // TODO investigate this /* ur_time_t timeOfLastIncomingRecord = recordListIncoming.getTimeOfLastRecord(); ur_time_t timeOfLastOutgoingRecord = recordListOutgoing.getTimeOfLastRecord(); - + if(timeOfLastIncomingRecord == 0 && timeOfLastOutgoingRecord == 0) //empty lists return true; - - + + ur_time_t timeOfLastRecord = timeOfLastIncomingRecord > timeOfLastOutgoingRecord ? timeOfLastIncomingRecord : timeOfLastOutgoingRecord; */ ur_time_t timer = getHostDeleteTimeout(); @@ -304,7 +308,7 @@ class RDPHostMap: public IHostMap { { IHostMap::clearMap(&hostMap); } - + inline uint16_t size() override { return hostMap.size(); @@ -329,7 +333,7 @@ class TELNETHostMap: public IHostMap { { IHostMap::clearMap(&hostMap); } - + inline uint16_t size() override { return hostMap.size(); diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 10c6df49..4304e3b2 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -92,7 +92,7 @@ bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { return false; } - + if(st.packets > Config::getInstance().getSSHOutMaxPackets() || st.packets < Config::getInstance().getSSHOutMinPackets()) { return false; @@ -128,7 +128,7 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); signatureMatched = false; - + // Win8 manual input if((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) @@ -144,10 +144,10 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return false; } signatureMatched = true; - return true; + return true; } - } - + } + // Ncrack/thc hydra to win8 unsuccessful connection if((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) @@ -193,9 +193,9 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); - + signatureMatched = false; - + // Win8 manual input if((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) @@ -213,8 +213,8 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) signatureMatched = true; return true; } - } - + } + // Ncrack/thc hydra to win8 unsuccessful connection if((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) @@ -232,12 +232,12 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) return true; } } - + if((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { return false; } - + if(st.packets > Config::getInstance().getRDPOutMaxPackets() || st.packets < Config::getInstance().getRDPOutMinPackets()) { return false; @@ -246,15 +246,15 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { return false; } - - + + if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } signatureMatched = true; - return true; + return true; } @@ -297,6 +297,7 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return true; } + bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); @@ -315,12 +316,12 @@ bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) } TSPProfile->profileWithNewData(st.packets, st.bytes); - - if(st.packets < 6) + + if(st.packets < 6) // FIXME magic constant { return false; } - + //for max range only if(TSPProfile->isProfiled()) { @@ -335,7 +336,7 @@ bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) } signatureMatched = true; - return true; + return true; } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 6ad81a08..80b231fd 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -70,13 +70,13 @@ * Interface for record */ class IRecord { - + public: IRecord () : signatureMatched(false) {} virtual ~IRecord() = default; virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl) = 0; virtual bool matchWithOutgoingSignature(void *structure, Whitelist *wl) = 0; - + inline bool isMatched() { return signatureMatched; } virtual ur_time_t getRecordTimeout() = 0; @@ -103,7 +103,7 @@ class IRecord { }; class SSHRecord : public IRecord { - + public: SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; @@ -121,9 +121,9 @@ class RDPRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; // SYN + ACK + PSH + RST const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; // SYN + ACK + PSH - const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH }; @@ -148,13 +148,13 @@ class RecordList { public: RecordList(); ~RecordList(); - + void addRecord(T record, bool isHostReported); void setNewMaxListSize(uint16_t newMaxListSize); void clearOldRecords(ur_time_t actualTime); void clearAllRecords(); ur_time_t getTimeOfLastRecord(); - + inline uint16_t getActualListSize() { return actualListSize; }; inline uint16_t getActualMatchedFlows() { return actualMatchedFlows; } inline uint32_t getMatchedFlowsSinceLastReport() { return matchedFlowsSinceLastReport; } @@ -173,13 +173,13 @@ class RecordList { std::vector getIpsOfVictims(); private: - std::list list; + std::list list; // TODO List of what uint16_t maxListSize; uint16_t actualListSize; uint16_t actualMatchedFlows; uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; - + uint32_t flowCounter; uint32_t flowMatchedCounter; @@ -217,8 +217,8 @@ RecordList::RecordList() { maxListSize = Config::getInstance().getTELNETMaxListSize(); } - else - { + else + { std::cerr << "Error record.h: Max list size for class " << typeid(T).name() << " is not defined!\n"; std::terminate(); } @@ -259,14 +259,15 @@ void RecordList::clearAllRecords() template void RecordList::addRecord(T record, bool isHostReported) -{ +{ flowCounter++; actualListSize++; if(actualListSize > maxListSize) - { + { // list is full // delete first record + if((*list.begin())->isMatched()) { actualMatchedFlows--; @@ -276,14 +277,15 @@ void RecordList::addRecord(T record, bool isHostReported) list.pop_front(); actualListSize--; + // TODO Missing if(isHostReported) { totalFlowsSinceLastReport--; } ? } - + if(record->isMatched()) { flowMatchedCounter++; actualMatchedFlows++; } - + if(isHostReported) { totalFlowsSinceLastReport++; @@ -291,8 +293,8 @@ void RecordList::addRecord(T record, bool isHostReported) if(record->isMatched()) { matchedFlowsSinceLastReport++; - - hashedDstIPSet.insert(record->dstIp); + + hashedDstIPSet.insert(record->dstIp); hashedDstTotalIPSet.insert(record->dstIp); } } diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index d93ec297..eb6f7bbf 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -109,7 +109,7 @@ class Sender host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToOutgoingRecordList()->clearTotalFlowsSinceLastReport(); - return send(host, dstPort, actualTime, incomingMatched > outgoingMatched ? incomingMatched : outgoingMatched, endOfAttack, sNote); + return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), endOfAttack, sNote); } private: diff --git a/brute_force_detector/telnet_server_profile.cpp b/brute_force_detector/telnet_server_profile.cpp index 0e464df1..c78f75d4 100644 --- a/brute_force_detector/telnet_server_profile.cpp +++ b/brute_force_detector/telnet_server_profile.cpp @@ -48,32 +48,32 @@ using namespace std; void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) { - //at least 6 packets from server to client - //1. syn+ack - //2. supported configuration - //3. username request //or only password - //4. ack username - //4/5. password request - //4/6. ack password - //5/7. information about successfull/failed login - //6/8. FIN packet - if(packets < 6) + // at least 6 packets from server to client + // 1. syn+ack + // 2. supported configuration + // 3. username request // or only password + // 4. ack username + // 4/5. password request + // 4/6. ack password + // 5/7. information about successfull/failed login + // 6/8. FIN packet + if(packets < 6) // FIXME magic constant return; - + static uint16_t profileCounter = 0; profileCounter++; - + if(listSize >= TSPArraySize) { byteList.pop_front(); packetList.pop_front(); listSize--; } - + byteList.push_back(bytes); packetList.push_back(packets); listSize++; - + if(!profiled && listSize == TSPArraySize) { countNewMaxValues(); @@ -83,38 +83,38 @@ void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) { countNewMaxValues(); profileCounter = 0; - } + } } void TelnetServerProfile::countNewMaxValues() { size_t n = packetList.size() / 2; - + vector packetVector; - vector byteVector; - + vector byteVector; + copy(packetList.begin(), packetList.end(), back_inserter(packetVector)); copy(byteList.begin(), byteList.end(), back_inserter(byteVector)); - - //median + + // median nth_element(byteVector.begin(), byteVector.begin() + n, byteVector.end()); nth_element(packetVector.begin(), packetVector.begin() + n, packetVector.end()); - + maxPackets = packetVector[n] + 5; maxBytes = byteVector[n] + 500; - - //char *c = new char[55]; - //ip_to_str(&serverIp,c); - //std::cout<<"Profilovano "<(ip, TSP)); - + return TSP; } @@ -122,7 +122,9 @@ TelnetServerProfile * TelnetServerProfileMap::findProfile(ip_addr_t & hostIp) co { auto it = TSPMap.find(hostIp); if(it == TSPMap.end()) - return nullptr; - + { + return nullptr; + } + return it->second; } From 33e9de8d960d019155002323d164abcfc8860d47 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Tue, 18 Jun 2019 13:25:10 +0200 Subject: [PATCH 20/40] Removed unnecessary variables, merged checkForTimeout functions, --- brute_force_detector/brute_force_detector.cpp | 45 ++++++------- brute_force_detector/config.cpp | 12 ++-- brute_force_detector/config.h | 2 +- brute_force_detector/host.cpp | 14 +++- brute_force_detector/host.h | 44 +++++++----- brute_force_detector/record.h | 67 +++++++++++-------- brute_force_detector/sender.h | 8 ++- 7 files changed, 111 insertions(+), 81 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index ef67cc6e..ff374595 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -111,7 +111,7 @@ trap_module_info_t *module_info = nullptr; static int stop = 0; - // TODO consider changing globals +// TODO consider changing globals TelnetServerProfileMap TELNETRecord::TSPMap; Whitelist whitelist; @@ -150,35 +150,29 @@ void signalHandler(int signal) } } -bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t actualTime) -{ - return oldTime + timer <= actualTime; -} - - void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment /* optional, implicitly set to "" (see .h) */) { - if (b && p) + double percentage = 0.0; + if (b != 0 && p != 0) { - ios::fmtflags f(cout.flags()); - cout << " (" - << std::fixed << std::setprecision(2) - << 100.0 / b * p - << "%" << comment << ")"; - cout.flags(f); - } - /* - else { - cerr << "Attempted division by zero in printFlowPercent." << endl; + percentage = 100.0 / b * p; } - // error output not necessary - */ + + ios::fmtflags f(cout.flags()); + + cout << " (" + << std::fixed << std::setprecision(2) + << percentage + << "%" << comment << ")"; + cout.flags(f); + + } int main(int argc, char **argv) { - getc(stdin); /// DEBUGGING + // getc(stdin); /// DEBUG // ***** TRAP initialization ***** int ret; INIT_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) @@ -349,7 +343,7 @@ int main(int argc, char **argv) } // Skip non TCP flows - if(ur_get(tmplt, data, F_PROTOCOL) != TCP_PROTOCOL_NUM) // TCP flows only + if(ur_get(tmplt, data, F_PROTOCOL) != TCP_PROTOCOL_NUM) { continue; } @@ -425,6 +419,7 @@ int main(int argc, char **argv) SSHHost *host = sshHostMap.findHost(&structure, direction); is_matched = host->addRecord(record, &structure, direction); + if(!is_matched) { delete record; @@ -433,7 +428,8 @@ int main(int argc, char **argv) { // check for attack auto attackState = host->checkForAttack(structure.flowLastSeen); - if(attackState != SSHHost::NO_ATTACK) + + if(attackState != SSHHost::NO_ATTACK) { if(attackState == SSHHost::NEW_ATTACK) { @@ -620,7 +616,6 @@ int main(int argc, char **argv) } } - // check for timeout if(checkForTimeout(timeOfLastReportCheck, timerForReportCheck, structure.flowLastSeen)) { timeOfLastReportCheck = structure.flowLastSeen; @@ -656,7 +651,7 @@ int main(int argc, char **argv) } } - // kontrola po odeslani + // post-send state check TRAP_DEFAULT_SEND_ERROR_HANDLING(ret, continue, break); } // ***** End of main processing loop ***** diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index cd8fe83d..c3cb4531 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -52,10 +52,10 @@ Config::Config() GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(60, 0); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(60, 0); GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10; - GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0f; + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0; GENERAL_IGNORE_FIRST_SEND = 0; - GENERAL_MATCHED_FLOW_RATIO = 0.9f; //TODO change back to 0.9f + GENERAL_MATCHED_FLOW_RATIO = 0.9; //TODO change back to 0.9 DEBUG //SSH SSH_LIST_SIZE = 1000; @@ -69,7 +69,7 @@ Config::Config() SSH_BRUTEFORCE_INC_MAX_PACKETS = 30; SSH_BRUTEFORCE_INC_MIN_BYTES = 1000; SSH_BRUTEFORCE_INC_MAX_BYTES = 5000; - + SSH_BRUTEFORCE_OUT_MIN_PACKETS = 11; SSH_BRUTEFORCE_OUT_MAX_PACKETS = 50; SSH_BRUTEFORCE_OUT_MIN_BYTES = 1000; @@ -89,7 +89,7 @@ Config::Config() RDP_BRUTEFORCE_INC_MAX_PACKETS = 100; RDP_BRUTEFORCE_INC_MIN_BYTES = 2200; RDP_BRUTEFORCE_INC_MAX_BYTES = 8001; - + //based on Flow-based detection of RDP brute-force attacks by Vykopal RDP_BRUTEFORCE_OUT_MIN_PACKETS = 30; RDP_BRUTEFORCE_OUT_MAX_PACKETS = 190; @@ -136,7 +136,7 @@ Config::Config() kw_SSH_BRUTEFORCE_INC_MAX_PACKETS = "SSH_BRUTEFORCE_INC_MAX_PACKETS"; kw_SSH_BRUTEFORCE_INC_MIN_BYTES = "SSH_BRUTEFORCE_INC_MIN_BYTES"; kw_SSH_BRUTEFORCE_INC_MAX_BYTES = "SSH_BRUTEFORCE_INC_MAX_BYTES"; - + kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS = "SSH_BRUTEFORCE_OUT_MIN_PACKETS"; kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS = "SSH_BRUTEFORCE_OUT_MAX_PACKETS"; kw_SSH_BRUTEFORCE_OUT_MIN_BYTES = "SSH_BRUTEFORCE_OUT_MIN_BYTES"; @@ -156,7 +156,7 @@ Config::Config() kw_RDP_BRUTEFORCE_INC_MAX_PACKETS = "RDP_BRUTEFORCE_INC_MAX_PACKETS"; kw_RDP_BRUTEFORCE_INC_MIN_BYTES = "RDP_BRUTEFORCE_INC_MIN_BYTES"; kw_RDP_BRUTEFORCE_INC_MAX_BYTES = "RDP_BRUTEFORCE_INC_MAX_BYTES"; - + kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS = "RDP_BRUTEFORCE_OUT_MIN_PACKETS"; kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS = "RDP_BRUTEFORCE_OUT_MAX_PACKETS"; kw_RDP_BRUTEFORCE_OUT_MIN_BYTES = "RDP_BRUTEFORCE_OUT_MIN_BYTES"; diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index 5b8a7579..4ec8b811 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -143,7 +143,7 @@ class Config { uint16_t GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; double GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; uint8_t GENERAL_IGNORE_FIRST_SEND; - float GENERAL_MATCHED_FLOW_RATIO; + double GENERAL_MATCHED_FLOW_RATIO; std::string kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT; std::string kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT; diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index f88a117c..6213c59b 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -75,7 +75,8 @@ bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) { recordListOutgoing.addRecord(record, isReported()); } - return true; + + return true; } } @@ -104,7 +105,9 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } else { - return SSHHost::NO_ATTACK; + cout << std::max(incomingMatched, outgoingMatched) << "< bottomThreshold" << "\n"; + + return SSHHost::NO_ATTACK; } } else @@ -122,8 +125,10 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } else { + cout << topMatchedRatio << "< ratio" << "\n"; return SSHHost::NO_ATTACK; - } + + } } } else // isReported @@ -149,6 +154,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + // avoids div by zero double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); @@ -478,7 +484,9 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { + std::cout << "deleting:" << size(); // DEBUG IHostMap::clearOldRecAndHost(&hostMap, actualTime); + std::cout << "," << size() << "\n"; // DEBUG } // ************************************************************/ diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index cec6ac67..b2e9d500 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -55,6 +55,8 @@ #include #include "brute_force_detector.h" + + /** * Base class for host */ @@ -74,7 +76,7 @@ class IHost { virtual ~IHost() = default; enum ATTACK_STATE { NO_ATTACK, NEW_ATTACK, ATTACK_REPORT_WAIT, ATTACK, - ATTACK_MIN_EVENTS_WAIT, END_OF_ATTACK, REPORT_END_OF_ATTACK}; + ATTACK_MIN_EVENTS_WAIT, END_OF_ATTACK, REPORT_END_OF_ATTACK }; inline ip_addr_t getHostIp() { return hostIp; } inline ur_time_t getTimeOfLastReport() { return timeOfLastReport; } @@ -102,7 +104,11 @@ class IHost { return true; } - void clearOldRecords(ur_time_t actualTime) { recordListIncoming.clearOldRecords(actualTime); recordListOutgoing.clearOldRecords(actualTime);} + void clearOldRecords(ur_time_t actualTime) + { + recordListIncoming.clearOldRecords(actualTime); + recordListOutgoing.clearOldRecords(actualTime); + } virtual ur_time_t getHostDeleteTimeout() = 0; @@ -115,10 +121,11 @@ class IHost { ur_time_t timeOfLastOutgoingRecord = recordListOutgoing.getTimeOfLastRecord(); if(timeOfLastIncomingRecord == 0 && timeOfLastOutgoingRecord == 0) //empty lists + { return true; + } - - ur_time_t timeOfLastRecord = timeOfLastIncomingRecord > timeOfLastOutgoingRecord ? timeOfLastIncomingRecord : timeOfLastOutgoingRecord; + ur_time_t timeOfLastRecord = std::max(timeOfLastIncomingRecord, timeOfLastOutgoingRecord); */ ur_time_t timer = getHostDeleteTimeout(); // return checkForTimeout(timeOfLastRecord, timer, actualTime); @@ -151,12 +158,12 @@ class IHost { bool isFlowScan(const uint32_t *packets, const uint8_t *flags) { - if((*packets == 1 && *flags == 0b00000010) // SYN - || (*packets == 2 && *flags == 0b00000010) // SYN - || (*packets == 2 && *flags == 0b00000110) // SYN + RST - || (*packets == 1 && *flags == 0b00010010) // SYN + ACK - || (*packets == 1 && *flags == 0b00010100) // RST + ACK - || (*packets == 3 && *flags == 0b00000010)) // 3 SYN packets + if( (*packets == 1 && *flags == 0b00000010) // SYN + || (*packets == 1 && *flags == 0b00010010) // SYN + ACK + || (*packets == 1 && *flags == 0b00010100) // RST + ACK + || (*packets == 2 && *flags == 0b00000010) // SYN + || (*packets == 2 && *flags == 0b00000110) // SYN + RST + || (*packets == 3 && *flags == 0b00000010)) // 3 SYN packets { scanned = true; return true; @@ -168,10 +175,6 @@ class IHost { } protected: - bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) - { - return flowTime + timer <= actualTime; - } bool scanned; @@ -243,9 +246,10 @@ class IHostMap { void clearMap(Container *c) { auto it = c->begin(); + while(it != c->end()) { - // if(it->second) + // if(it->second) // TODO is this change harmless? delete it->second; it++; @@ -253,10 +257,20 @@ class IHostMap { c->clear(); } + /** + * @brief clear old hostMap records and old hosts + * + * @tparam Container + * @param c + * @param actualTime + */ template void clearOldRecAndHost(Container *c, ur_time_t actualTime) { + typename Container::iterator it = c->begin(); + // iterating over map (or RDPHost* or TELNETHost*) + while(it != c->end()) { it->second->clearOldRecords(actualTime); diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 80b231fd..842a98a8 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -58,13 +58,14 @@ #include "whitelist.h" #include "config.h" -// class TelnetServerProfileMap; +// class TelnetServerProfileMap #include "telnet_server_profile.h" -// TODO Is this relevant? -// If we don't have a lot of memory use hash -// #define USE_HASH - +// TODO find better place to put this as a global function +inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTime) +{ + return oldTime + timer <= newTime; +} /** * Interface for record @@ -93,7 +94,7 @@ class IRecord { ur_time_t flowLastSeen; }; - // May seem unused, actually are passed to reporting functions + // May seem unused, actually are passed to reporting functions TODO why separate from MatchStructure ip_addr_t dstIp{}; ur_time_t flowLastSeen{}; @@ -165,33 +166,30 @@ class RecordList { inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } - inline uint16_t getCurrentTargets(); // TODO does this need implementation? + inline uint16_t getCurrentTargets(); // TODO never used, investigate inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } inline void initTotalTargetsSet(); + + std::vector getIpsOfVictims(); private: - std::list list; // TODO List of what + std::list list; // In derived classes implemented like list, stores flow records uint16_t maxListSize; uint16_t actualListSize; uint16_t actualMatchedFlows; uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; - uint32_t flowCounter; - uint32_t flowMatchedCounter; + // uint32_t flowCounter; // experimental + // uint32_t flowMatchedCounter; // experimental - std::set hashedDstIPSet; // TODO WHAT ARE THOSE? + std::set hashedDstIPSet; // TODO WHAT ARE THOSE? std::set hashedDstTotalIPSet; // AND WHY ARE NEITHER EVER USED ANYWHERE ELSE? char victimIP[46]{}; - - static inline bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) - { - return flowTime + timer <= actualTime; - } }; template @@ -199,8 +197,9 @@ RecordList::RecordList() { actualListSize = 0; actualMatchedFlows = 0; - flowCounter = 0; - flowMatchedCounter = 0; + + // flowCounter = 0; // experimental + // flowMatchedCounter = 0; // experimental matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; @@ -247,8 +246,8 @@ void RecordList::clearAllRecords() actualListSize = 0; actualMatchedFlows = 0; - flowCounter = 0; - flowMatchedCounter = 0; + // flowCounter = 0; // experimental + // flowMatchedCounter = 0; // experimental matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; @@ -256,11 +255,10 @@ void RecordList::clearAllRecords() clearTargetsSinceLastReport(); } - template void RecordList::addRecord(T record, bool isHostReported) { - flowCounter++; + // flowCounter++; // experimental actualListSize++; if(actualListSize > maxListSize) @@ -282,7 +280,7 @@ void RecordList::addRecord(T record, bool isHostReported) if(record->isMatched()) { - flowMatchedCounter++; + // flowMatchedCounter++; // experimental actualMatchedFlows++; } @@ -298,7 +296,7 @@ void RecordList::addRecord(T record, bool isHostReported) hashedDstTotalIPSet.insert(record->dstIp); } } - list.push_back(record); // finally push record to a list + list.push_back(record); } template @@ -314,7 +312,9 @@ void RecordList::setNewMaxListSize(uint16_t newMaxListSize) T recToDelete = list.front(); if (recToDelete->isMatched()) - actualMatchedFlows--; + { + actualMatchedFlows--; + } delete recToDelete; list.pop_front(); @@ -324,11 +324,19 @@ void RecordList::setNewMaxListSize(uint16_t newMaxListSize) maxListSize = newMaxListSize; } +/** + * @brief Delete records older than Record Timeout (30min by def) + * + * @tparam T + * @param actualTime + */ template void RecordList::clearOldRecords(ur_time_t actualTime) { if(list.empty()) - return; + { + return; + } T rec = list.front(); ur_time_t timer = rec->getRecordTimeout(); @@ -338,6 +346,7 @@ void RecordList::clearOldRecords(ur_time_t actualTime) while(it != list.end()) { ur_time_t flowTime = (*it)->flowLastSeen; + if (checkForTimeout(flowTime, timer, actualTime)) { if ((*it)->isMatched()) @@ -374,7 +383,7 @@ template uint16_t RecordList::getCurrentTargets() { std::set dstIpSet; - for(auto it : list) + for(const auto & it : list) { if(it->isMatched()) { @@ -387,7 +396,7 @@ uint16_t RecordList::getCurrentTargets() template void RecordList::initTotalTargetsSet() { - for(auto it : list) + for(const auto & it : list) { if(it->isMatched()) { @@ -402,7 +411,7 @@ std::vector RecordList::getIpsOfVictims() { std::vector tmpIpsOfVictims; - for(auto& it : list) + for(const auto& it : list) { if(it->isMatched()) { diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index eb6f7bbf..faaeb3df 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -88,9 +88,13 @@ class Sender return TRAP_E_OK; } - string sNote; + //TODO check + uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); + uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); + + string sNote; - return send(host, dstPort, actualTime, detectionThreshold, false, sNote); + return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), false, sNote); } template From 3052468670d3e2045e410c02e5944e134b5d1bfe Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Tue, 18 Jun 2019 16:07:04 +0200 Subject: [PATCH 21/40] Removed more unnecessary variables, reports don't show matched count --- brute_force_detector/config.cpp | 24 +++++----- brute_force_detector/config/config.conf | 48 ++++++++++---------- brute_force_detector/config/whitelist.wl | 3 +- brute_force_detector/host.cpp | 41 +++++++---------- brute_force_detector/host.h | 26 ++++------- brute_force_detector/record.h | 56 +----------------------- brute_force_detector/sender.h | 4 +- 7 files changed, 66 insertions(+), 136 deletions(-) diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index c3cb4531..588b82c0 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -51,18 +51,22 @@ Config::Config() //init default config variables GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(60, 0); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(60, 0); + + GENERAL_MATCHED_FLOW_RATIO = 0.9; + GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10; + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0; + GENERAL_IGNORE_FIRST_SEND = 0; - GENERAL_MATCHED_FLOW_RATIO = 0.9; //TODO change back to 0.9 DEBUG //SSH SSH_LIST_SIZE = 1000; - SSH_LIST_SIZE_BOTTOM_THRESHOLD = 50; // There are two types of thresholds, first means how many records are in list [50/1000] + SSH_LIST_SIZE_BOTTOM_THRESHOLD = 100; // There are two types of thresholds, first means how many records are in list [50/1000] // and based on this value is set up THRESHOLD which detects if host is attacker or not - SSH_LIST_THRESHOLD = 30; - SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); + SSH_LIST_THRESHOLD = 90; + SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); SSH_BRUTEFORCE_INC_MIN_PACKETS = 11; @@ -80,9 +84,9 @@ Config::Config() //RDP RDP_LIST_SIZE = 1000; - RDP_LIST_SIZE_BOTTOM_THRESHOLD = 50; - RDP_LIST_THRESHOLD = 30; - RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); + RDP_LIST_SIZE_BOTTOM_THRESHOLD = 100; + RDP_LIST_THRESHOLD = 90; + RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); RDP_BRUTEFORCE_INC_MIN_PACKETS = 20; @@ -101,9 +105,9 @@ Config::Config() //TELNET TELNET_LIST_SIZE = 1000; - TELNET_LIST_SIZE_BOTTOM_THRESHOLD = 50; - TELNET_LIST_THRESHOLD = 30; - TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); + TELNET_LIST_SIZE_BOTTOM_THRESHOLD = 100; + TELNET_LIST_THRESHOLD = 90; + TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9; diff --git a/brute_force_detector/config/config.conf b/brute_force_detector/config/config.conf index 1625ead9..bb1d1c0c 100644 --- a/brute_force_detector/config/config.conf +++ b/brute_force_detector/config/config.conf @@ -21,36 +21,36 @@ ## Percentage threshold between suspicious and benign flows to keep track host ## If below threshold and after protocol_REPORT_TIMEOUT report end of attack # GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0 -## -## Suppress reporting of first detection -## If set, attack scale will have to pass threshold +## +## Suppress reporting of first detection +## If set, attack scale will have to pass threshold ## "GENERAL_ATTACK_MIN_EVENTS_TO_REPORT". This option may decrease number of the -## false positive detections. 0/1 = false/true +## false positive detections. 0/1 = false/true # GENERAL_IGNORE_FIRST_SEND = 0 ## ## How much of the flow has to be suspicious to report an attack (sensitivity) -## In the range of (0;1]. (0 would mean everything is considered an attack) +## In the range of (0;1]. (0 would mean everything is considered an attack) # GENERAL_MATCHED_FLOW_RATIO = 0.9 ####################################### ## PROTOCOL (X) KEYWORDS INFORMATION ## ## X -> SSH/RDP/TELNET -## -## X_ATTACK_TIMEOUT - After n seconds from last report set attack by given host +## +## X_ATTACK_TIMEOUT - After n seconds from last report set attack by given host ## as finished ## X_LIST_SIZE - Set number of max records(flows) that each host can store ## X_LIST_THRESHOLD - Set threshold for number of suspicious flows ## X_REPORT_TIMEOUT - Attacker can be reported again after n seconds. -## During this entire period attack information is agregated. -## X_ATTACK_TIMEOUT > X_REPORT_TIMEOUT +## During this entire period attack information is agregated. +## X_ATTACK_TIMEOUT > X_REPORT_TIMEOUT ## -## X_RECORD_TIMEOUT - Delete record from memory after n seconds -## X_HOST_TIMEOUT - Delete host from memory after n seconds of inactivity -## Shorter timeout means smaller memory usage of these two -## aforementioned keywords. On the other hand detection of +## X_RECORD_TIMEOUT - Delete record from memory after n seconds +## X_HOST_TIMEOUT - Delete host from memory after n seconds of inactivity +## Shorter timeout means smaller memory usage of these two +## aforementioned keywords. On the other hand detection of ## slower attacks could be worse ## -## Following keywords are used for check flow records which may correspond with +## Following keywords are used for check flow records which may correspond with ## brute force attack ## DIR - Flow direction : INC (Attacker -> Victim) ## OUT (Victim -> Victim) @@ -65,10 +65,10 @@ ######### SSH ########## ######################## #SSH_ATTACK_TIMEOUT = 600 -#SSH_LIST_SIZE = 50 -#SSH_LIST_THRESHOLD = 30 +#SSH_LIST_SIZE = 100 +#SSH_LIST_THRESHOLD = 90 #SSH_RECORD_TIMEOUT = 1800 -#SSH_HOST_TIMEOUT = 4200 +#SSH_HOST_TIMEOUT = 4200 #SSH_BRUTEFORCE_INC_MIN_PACKETS = 11 #SSH_BRUTEFORCE_INC_MAX_PACKETS = 30 #SSH_BRUTEFORCE_INC_MIN_BYTES = 1000 @@ -82,10 +82,10 @@ ######### RDP ########## ######################## #RDP_ATTACK_TIMEOUT = 600 -#RDP_LIST_SIZE = 50 -#RDP_LIST_THRESHOLD = 30 +#RDP_LIST_SIZE = 100 +#RDP_LIST_THRESHOLD = 90 #RDP_RECORD_TIMEOUT = 1800 -#RDP_HOST_TIMEOUT = 4200 +#RDP_HOST_TIMEOUT = 4200 #RDP_BRUTEFORCE_INC_MIN_PACKETS = 20 #RDP_BRUTEFORCE_INC_MAX_PACKETS = 100 #RDP_BRUTEFORCE_INC_MIN_BYTES = 2200 @@ -98,14 +98,14 @@ ######################## ######## Telnet ######## ######################## -#TELNET_ATTACK_TIMEOUT = 600 -#TELNET_LIST_SIZE = 50 -#TELNET_LIST_THRESHOLD = 30 +#TELNET_LIST_SIZE = 100 +#TELNET_LIST_THRESHOLD = 90 #TELNET_RECORD_TIMEOUT = 1800 -#TELNET_HOST_TIMEOUT = 4200 +#TELNET_HOST_TIMEOUT = 4200 #TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9 #TELNET_BRUTEFORCE_INC_MAX_PACKETS = 50 #TELNET_BRUTEFORCE_INC_MIN_BYTES = 450 #TELNET_BRUTEFORCE_INC_MAX_BYTES = 3000 ## Outgoing version is not supported +#TELNET_ATTACK_TIMEOUT = 600 #TELNET_REPORT_TIMEOUT = 300 diff --git a/brute_force_detector/config/whitelist.wl b/brute_force_detector/config/whitelist.wl index b18c5099..8a9a29ac 100644 --- a/brute_force_detector/config/whitelist.wl +++ b/brute_force_detector/config/whitelist.wl @@ -13,11 +13,12 @@ # direction: # "src", "dst" or "" (no keyword = src and dst) -dst 192.30.252.128/30/22 #github +dst 192.30.252.128/30/22 #github dst 131.103.20.160/28/22 #bitbucket src 166.88.20.3/32 # valid communication to 195.113.184.18 src 195.113.44.19/32 # valid(???) communication to 88.208.125.10 & 88.208.125.11 +# TODO Delete/solve unknown addresses diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 6213c59b..aab60516 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -99,13 +99,11 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); return SSHHost::NEW_ATTACK; } else { - cout << std::max(incomingMatched, outgoingMatched) << "< bottomThreshold" << "\n"; + cout << std::max(incomingMatched, outgoingMatched) << "< bottomThreshold" << "\n"; // DEBUG return SSHHost::NO_ATTACK; } @@ -114,18 +112,18 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max list size per protocol - auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + double topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); return SSHHost::NEW_ATTACK; } else { - cout << topMatchedRatio << "< ratio" << "\n"; + // cout << incomingMatched << "/" << incomingListSize << "\n"; + // cout << outgoingMatched << "/" << outgoingListSize << "\n"; + cout << topMatchedRatio << " < ratio" << "\n"; // DEBUG return SSHHost::NO_ATTACK; } @@ -155,8 +153,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); // avoids div by zero - double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); - double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); + auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); + auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { @@ -226,9 +224,6 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return RDPHost::NEW_ATTACK; } else @@ -240,14 +235,11 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max size - auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + auto topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return RDPHost::NEW_ATTACK; } else @@ -279,8 +271,9 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); - double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); + // avoids div by zero + auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); + auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { @@ -350,9 +343,6 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return TELNETHost::NEW_ATTACK; } else @@ -364,13 +354,11 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max size - auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + auto topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); return TELNETHost::NEW_ATTACK; } else @@ -402,8 +390,9 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); - double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); + // avoids div by zero + auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); + auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index b2e9d500..c88ef176 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -75,8 +75,14 @@ class IHost { virtual ~IHost() = default; - enum ATTACK_STATE { NO_ATTACK, NEW_ATTACK, ATTACK_REPORT_WAIT, ATTACK, - ATTACK_MIN_EVENTS_WAIT, END_OF_ATTACK, REPORT_END_OF_ATTACK }; + enum ATTACK_STATE { NO_ATTACK, + NEW_ATTACK, // send report + ATTACK_REPORT_WAIT, + ATTACK, // send report + ATTACK_MIN_EVENTS_WAIT, + END_OF_ATTACK, + REPORT_END_OF_ATTACK // send report + }; inline ip_addr_t getHostIp() { return hostIp; } inline ur_time_t getTimeOfLastReport() { return timeOfLastReport; } @@ -85,8 +91,6 @@ class IHost { inline void setNotReported() { timeOfLastReport = 0; - recordListIncoming.clearTotalTargetsSinceAttack(); - recordListOutgoing.clearTotalTargetsSinceAttack(); } inline bool getHostScannedNetwork() { return scanned; } @@ -110,25 +114,11 @@ class IHost { recordListOutgoing.clearOldRecords(actualTime); } - virtual ur_time_t getHostDeleteTimeout() = 0; virtual bool canDeleteHost(ur_time_t actualTime) { - // TODO investigate this - /* - ur_time_t timeOfLastIncomingRecord = recordListIncoming.getTimeOfLastRecord(); - ur_time_t timeOfLastOutgoingRecord = recordListOutgoing.getTimeOfLastRecord(); - - if(timeOfLastIncomingRecord == 0 && timeOfLastOutgoingRecord == 0) //empty lists - { - return true; - } - - ur_time_t timeOfLastRecord = std::max(timeOfLastIncomingRecord, timeOfLastOutgoingRecord); - */ ur_time_t timer = getHostDeleteTimeout(); - // return checkForTimeout(timeOfLastRecord, timer, actualTime); return checkForTimeout(timeOfLastReceivedRecord, timer, actualTime); } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 842a98a8..36f4b8fb 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -103,6 +103,7 @@ class IRecord { bool signatureMatched; }; + class SSHRecord : public IRecord { public: @@ -114,6 +115,7 @@ class SSHRecord : public IRecord { const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH }; + class RDPRecord : public IRecord { public: @@ -163,16 +165,6 @@ class RecordList { inline void clearMatchedFlowsSinceLastReport() { matchedFlowsSinceLastReport = 0; } inline void clearTotalFlowsSinceLastReport() { totalFlowsSinceLastReport = 0; } - inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } - inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } - - inline uint16_t getCurrentTargets(); // TODO never used, investigate - - inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } - inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } - inline void initTotalTargetsSet(); - - std::vector getIpsOfVictims(); private: @@ -183,11 +175,6 @@ class RecordList { uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; - // uint32_t flowCounter; // experimental - // uint32_t flowMatchedCounter; // experimental - - std::set hashedDstIPSet; // TODO WHAT ARE THOSE? - std::set hashedDstTotalIPSet; // AND WHY ARE NEITHER EVER USED ANYWHERE ELSE? char victimIP[46]{}; }; @@ -198,9 +185,6 @@ RecordList::RecordList() actualListSize = 0; actualMatchedFlows = 0; - // flowCounter = 0; // experimental - // flowMatchedCounter = 0; // experimental - matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; @@ -246,19 +230,14 @@ void RecordList::clearAllRecords() actualListSize = 0; actualMatchedFlows = 0; - // flowCounter = 0; // experimental - // flowMatchedCounter = 0; // experimental matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; - - clearTargetsSinceLastReport(); } template void RecordList::addRecord(T record, bool isHostReported) { - // flowCounter++; // experimental actualListSize++; if(actualListSize > maxListSize) @@ -280,7 +259,6 @@ void RecordList::addRecord(T record, bool isHostReported) if(record->isMatched()) { - // flowMatchedCounter++; // experimental actualMatchedFlows++; } @@ -291,9 +269,6 @@ void RecordList::addRecord(T record, bool isHostReported) if(record->isMatched()) { matchedFlowsSinceLastReport++; - - hashedDstIPSet.insert(record->dstIp); - hashedDstTotalIPSet.insert(record->dstIp); } } list.push_back(record); @@ -379,33 +354,6 @@ ur_time_t RecordList::getTimeOfLastRecord() } } -template -uint16_t RecordList::getCurrentTargets() -{ - std::set dstIpSet; - for(const auto & it : list) - { - if(it->isMatched()) - { - dstIpSet.insert(it->dstIp); - } - } - return dstIpSet.size(); -} - -template -void RecordList::initTotalTargetsSet() -{ - for(const auto & it : list) - { - if(it->isMatched()) - { - // TODO Why is TotalIPSet filled with matched flows only? - hashedDstTotalIPSet.insert(it->dstIp); - } - } -} - template std::vector RecordList::getIpsOfVictims() { diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index faaeb3df..4ddc6f38 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -88,7 +88,7 @@ class Sender return TRAP_E_OK; } - //TODO check + //TODO test if output correct uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); @@ -105,11 +105,9 @@ class Sender string sNote; - host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToIncomingRecordList()->clearTotalFlowsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToOutgoingRecordList()->clearTotalFlowsSinceLastReport(); From 443cac055a4acfeacf5b656288c1df47ce15d49f Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Fri, 28 Jun 2019 15:15:41 +0200 Subject: [PATCH 22/40] Renamed attack states --- brute_force_detector/brute_force_detector.cpp | 12 ++++----- brute_force_detector/brute_force_detector.h | 4 +-- brute_force_detector/host.cpp | 26 +++++++++---------- brute_force_detector/host.h | 4 +-- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index ff374595..ca3bd0f9 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -431,7 +431,7 @@ int main(int argc, char **argv) if(attackState != SSHHost::NO_ATTACK) { - if(attackState == SSHHost::NEW_ATTACK) + if(attackState == SSHHost::REPORT_NEW_ATTACK) { ret = sender->firstReport(host, TCP_SSH_PORT, structure.flowLastSeen, Config::getInstance().getSSHListThreshold()); } @@ -454,7 +454,7 @@ int main(int argc, char **argv) host->clearAllRecords(); host->setNotReported(); } - else if(attackState == SSHHost::ATTACK) + else if(attackState == SSHHost::REPORT_ATTACK) { ret = sender->continuingReport(host, TCP_SSH_PORT, structure.flowLastSeen); } @@ -509,7 +509,7 @@ int main(int argc, char **argv) RDPHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != RDPHost::NO_ATTACK) { - if(attackState == RDPHost::NEW_ATTACK) + if(attackState == RDPHost::REPORT_NEW_ATTACK) { ret = sender->firstReport(host, TCP_RDP_PORT, structure.flowLastSeen, Config::getInstance().getRDPListThreshold()); } @@ -531,7 +531,7 @@ int main(int argc, char **argv) host->clearAllRecords(); host->setNotReported(); } - else if(attackState == RDPHost::ATTACK) + else if(attackState == RDPHost::REPORT_ATTACK) { ret = sender->continuingReport(host, TCP_RDP_PORT, structure.flowLastSeen); } @@ -586,7 +586,7 @@ int main(int argc, char **argv) TELNETHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != TELNETHost::NO_ATTACK) { - if(attackState == TELNETHost::NEW_ATTACK) + if(attackState == TELNETHost::REPORT_NEW_ATTACK) { ret = sender->firstReport(host, TCP_TELNET_PORT, structure.flowLastSeen, Config::getInstance().getTELNETListThreshold()); } @@ -608,7 +608,7 @@ int main(int argc, char **argv) host->clearAllRecords(); host->setNotReported(); } - else if(attackState == TELNETHost::ATTACK) + else if(attackState == TELNETHost::REPORT_ATTACK) { ret = sender->continuingReport(host, TCP_TELNET_PORT, structure.flowLastSeen); } diff --git a/brute_force_detector/brute_force_detector.h b/brute_force_detector/brute_force_detector.h index 97a4fbe3..c18af9cc 100644 --- a/brute_force_detector/brute_force_detector.h +++ b/brute_force_detector/brute_force_detector.h @@ -102,11 +102,11 @@ class logInfo { std::cout << std::endl; std::cout << " Matched Incoming Flows: " << this->matchedIncomingFlows; printFlowPercent(this->matchedFlows, this->matchedIncomingFlows, " from matched"); - printFlowPercent(this->flows, this->matchedIncomingFlows, " from all flows"); + printFlowPercent(this->flows, this->matchedIncomingFlows, " from incoming"); std::cout << std::endl; std::cout << " Matched Outgoing Flows: " << this->matchedOutgoingFlows; printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows, " from matched"); - printFlowPercent(this->flows, this->matchedOutgoingFlows, " from all flows"); + printFlowPercent(this->flows, this->matchedOutgoingFlows, " from outgoing"); std::cout << std::endl; } diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index aab60516..dbb01f28 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -99,11 +99,11 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold()) { // crossed threshold, new attack detected - return SSHHost::NEW_ATTACK; + return SSHHost::REPORT_NEW_ATTACK; } else { - cout << std::max(incomingMatched, outgoingMatched) << "< bottomThreshold" << "\n"; // DEBUG + // cout << std::max(incomingMatched, outgoingMatched) << "< bottomThreshold" << "\n"; // DEBUG return SSHHost::NO_ATTACK; } @@ -117,13 +117,13 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - return SSHHost::NEW_ATTACK; + return SSHHost::REPORT_NEW_ATTACK; } else { // cout << incomingMatched << "/" << incomingListSize << "\n"; // cout << outgoingMatched << "/" << outgoingListSize << "\n"; - cout << topMatchedRatio << " < ratio" << "\n"; // DEBUG + // cout << topMatchedRatio << " < ratio" << "\n"; // DEBUG return SSHHost::NO_ATTACK; } @@ -170,7 +170,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { - return SSHHost::ATTACK; + return SSHHost::REPORT_ATTACK; } else { @@ -224,7 +224,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold()) { // crossed threshold, new attack detected - return RDPHost::NEW_ATTACK; + return RDPHost::REPORT_NEW_ATTACK; } else { @@ -240,7 +240,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - return RDPHost::NEW_ATTACK; + return RDPHost::REPORT_NEW_ATTACK; } else { @@ -289,7 +289,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { - return RDPHost::ATTACK; + return RDPHost::REPORT_ATTACK; } else { @@ -343,7 +343,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold()) { // crossed threshold, new attack detected - return TELNETHost::NEW_ATTACK; + return TELNETHost::REPORT_NEW_ATTACK; } else { @@ -359,7 +359,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - return TELNETHost::NEW_ATTACK; + return TELNETHost::REPORT_NEW_ATTACK; } else { @@ -408,7 +408,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { - return TELNETHost::ATTACK; + return TELNETHost::REPORT_ATTACK; } else { @@ -473,9 +473,9 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { - std::cout << "deleting:" << size(); // DEBUG + // std::cout << "deleting:" << size(); // DEBUG IHostMap::clearOldRecAndHost(&hostMap, actualTime); - std::cout << "," << size() << "\n"; // DEBUG + // std::cout << "," << size() << "\n"; // DEBUG } // ************************************************************/ diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index c88ef176..349ff3b8 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -76,9 +76,9 @@ class IHost { virtual ~IHost() = default; enum ATTACK_STATE { NO_ATTACK, - NEW_ATTACK, // send report + REPORT_NEW_ATTACK, // send report ATTACK_REPORT_WAIT, - ATTACK, // send report + REPORT_ATTACK, // send report ATTACK_MIN_EVENTS_WAIT, END_OF_ATTACK, REPORT_END_OF_ATTACK // send report From 521393abe8de89529e7f6b6d840fe6fdb499fb2b Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Wed, 18 Sep 2019 17:18:31 +0200 Subject: [PATCH 23/40] Clarified portscans, minor changes --- brute_force_detector/brute_force_detector.cpp | 32 ++++++++++++------- brute_force_detector/host.cpp | 2 -- brute_force_detector/host.h | 24 +++++++------- brute_force_detector/record.h | 1 - 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index ca3bd0f9..b23d0237 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -245,7 +245,8 @@ int main(int argc, char **argv) if(!RDP && !SSH && !TELNET) { cerr << "Error: Detection mode is not set.\n"; - return 3; + FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) + return 3; } // ***** Config init ***** @@ -286,7 +287,7 @@ int main(int argc, char **argv) free(errstr); } trap_finalize(); - FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS); + FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) return 4; } @@ -323,7 +324,7 @@ int main(int argc, char **argv) // Receive data from input interface (block until data are available) const void *data; uint16_t data_size; - ret = TRAP_RECEIVE(0, data, data_size, tmplt); + ret = TRAP_RECEIVE(0, data, data_size, tmplt) TRAP_DEFAULT_RECV_ERROR_HANDLING(ret, continue, break); // Check size of received data @@ -386,6 +387,7 @@ int main(int argc, char **argv) if(SSH && (dstPort == TCP_SSH_PORT || srcPort == TCP_SSH_PORT)) { bool is_matched; + bool is_portscan; SSHRecord *record; if(direction == FLOW_INCOMING_DIRECTION) @@ -398,8 +400,9 @@ int main(int argc, char **argv) } ssh.incomingFlows++; } - else // FLOW_OUTGOING_DIRECTION + else { + // FLOW_OUTGOING_DIRECTION record = new SSHRecord(structure.srcIp, structure.flowLastSeen); is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); if(is_matched) @@ -418,9 +421,9 @@ int main(int argc, char **argv) // host is the source of current flow/connection SSHHost *host = sshHostMap.findHost(&structure, direction); - is_matched = host->addRecord(record, &structure, direction); + is_portscan = host->addRecord(record, &structure, direction); - if(!is_matched) + if(!is_matched || is_portscan) { delete record; } @@ -466,6 +469,7 @@ int main(int argc, char **argv) if(RDP && (dstPort == TCP_RDP_PORT || srcPort == TCP_RDP_PORT)) { bool is_matched; + bool is_portscan; RDPRecord *record; if(direction == FLOW_INCOMING_DIRECTION) @@ -498,8 +502,8 @@ int main(int argc, char **argv) RDPHost *host = rdpHostMap.findHost(&structure, direction); - is_matched = host->addRecord(record, &structure, direction); - if(!is_matched) + is_portscan = host->addRecord(record, &structure, direction); + if(!is_matched || is_portscan) { delete record; } @@ -543,6 +547,7 @@ int main(int argc, char **argv) if(TELNET && (dstPort == TCP_TELNET_PORT || srcPort == TCP_TELNET_PORT)) { bool is_matched; + bool is_portscan; TELNETRecord *record; if(direction == FLOW_INCOMING_DIRECTION) @@ -575,8 +580,8 @@ int main(int argc, char **argv) TELNETHost *host = telnetHostMap.findHost(&structure, direction); - is_matched = host->addRecord(record, &structure, direction); - if(!is_matched) + is_portscan = host->addRecord(record, &structure, direction); + if(!is_matched || is_portscan) { delete record; } @@ -633,6 +638,7 @@ int main(int argc, char **argv) telnetHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); } } + if(checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, structure.flowLastSeen)) { timeOfLastDeleteCheck = structure.flowLastSeen; @@ -656,11 +662,14 @@ int main(int argc, char **argv) } // ***** End of main processing loop ***** + + // TODO how to pass Host Map base class to printLogInfo if(SSH) { ssh.printLogInfo(); std::cout << " Host Map Size: " << sshHostMap.size() << std::endl; + sshHostMap.clear(); } if(RDP) @@ -676,7 +685,8 @@ int main(int argc, char **argv) telnetHostMap.clear(); } - TRAP_DEFAULT_FINALIZATION(); + + TRAP_DEFAULT_FINALIZATION(); ur_free_template(tmplt); ur_finalize(); delete sender; // free output template diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index dbb01f28..bf11fc22 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -473,9 +473,7 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { - // std::cout << "deleting:" << size(); // DEBUG IHostMap::clearOldRecAndHost(&hostMap, actualTime); - // std::cout << "," << size() << "\n"; // DEBUG } // ************************************************************/ diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 349ff3b8..eb8452a5 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -237,12 +237,12 @@ class IHostMap { { auto it = c->begin(); - while(it != c->end()) + while(it != c->end()) { - // if(it->second) // TODO is this change harmless? - delete it->second; - it++; + if(it->second) // TODO harmless to remove this? + delete it->second; + it++; } c->clear(); } @@ -286,9 +286,9 @@ class SSHHostMap : public IHostMap { ~SSHHostMap() = default; void clear() override - { - IHostMap::clearMap(&hostMap); - } + { + IHostMap::clearMap(&hostMap); + } inline uint16_t size() override { return hostMap.size(); @@ -308,10 +308,10 @@ class RDPHostMap: public IHostMap { RDPHostMap() = default; ~RDPHostMap() = default; - void clear() override - { - IHostMap::clearMap(&hostMap); - } + void clear() override + { + IHostMap::clearMap(&hostMap); + } inline uint16_t size() override { @@ -335,7 +335,7 @@ class TELNETHostMap: public IHostMap { void clear() override { - IHostMap::clearMap(&hostMap); + IHostMap::clearMap(&hostMap); } inline uint16_t size() override diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 36f4b8fb..38394f0c 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -175,7 +175,6 @@ class RecordList { uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; - char victimIP[46]{}; }; From 647d4d9cf628e5f3665cd48c9ab080c66cf7be01 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Tue, 18 Jun 2019 16:07:04 +0200 Subject: [PATCH 24/40] Reverted part of 3052468 --- brute_force_detector/config.cpp | 24 ++++---- brute_force_detector/config/config.conf | 48 ++++++++-------- brute_force_detector/config/whitelist.wl | 3 +- brute_force_detector/host.cpp | 53 +++++++++--------- brute_force_detector/host.h | 26 +++------ brute_force_detector/record.h | 71 ++++++++++++------------ brute_force_detector/sender.h | 10 ++-- 7 files changed, 117 insertions(+), 118 deletions(-) diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index c3cb4531..588b82c0 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -51,18 +51,22 @@ Config::Config() //init default config variables GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(60, 0); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(60, 0); + + GENERAL_MATCHED_FLOW_RATIO = 0.9; + GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10; + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0; + GENERAL_IGNORE_FIRST_SEND = 0; - GENERAL_MATCHED_FLOW_RATIO = 0.9; //TODO change back to 0.9 DEBUG //SSH SSH_LIST_SIZE = 1000; - SSH_LIST_SIZE_BOTTOM_THRESHOLD = 50; // There are two types of thresholds, first means how many records are in list [50/1000] + SSH_LIST_SIZE_BOTTOM_THRESHOLD = 100; // There are two types of thresholds, first means how many records are in list [50/1000] // and based on this value is set up THRESHOLD which detects if host is attacker or not - SSH_LIST_THRESHOLD = 30; - SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); + SSH_LIST_THRESHOLD = 90; + SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); SSH_BRUTEFORCE_INC_MIN_PACKETS = 11; @@ -80,9 +84,9 @@ Config::Config() //RDP RDP_LIST_SIZE = 1000; - RDP_LIST_SIZE_BOTTOM_THRESHOLD = 50; - RDP_LIST_THRESHOLD = 30; - RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); + RDP_LIST_SIZE_BOTTOM_THRESHOLD = 100; + RDP_LIST_THRESHOLD = 90; + RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); RDP_BRUTEFORCE_INC_MIN_PACKETS = 20; @@ -101,9 +105,9 @@ Config::Config() //TELNET TELNET_LIST_SIZE = 1000; - TELNET_LIST_SIZE_BOTTOM_THRESHOLD = 50; - TELNET_LIST_THRESHOLD = 30; - TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); + TELNET_LIST_SIZE_BOTTOM_THRESHOLD = 100; + TELNET_LIST_THRESHOLD = 90; + TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9; diff --git a/brute_force_detector/config/config.conf b/brute_force_detector/config/config.conf index 1625ead9..bb1d1c0c 100644 --- a/brute_force_detector/config/config.conf +++ b/brute_force_detector/config/config.conf @@ -21,36 +21,36 @@ ## Percentage threshold between suspicious and benign flows to keep track host ## If below threshold and after protocol_REPORT_TIMEOUT report end of attack # GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0 -## -## Suppress reporting of first detection -## If set, attack scale will have to pass threshold +## +## Suppress reporting of first detection +## If set, attack scale will have to pass threshold ## "GENERAL_ATTACK_MIN_EVENTS_TO_REPORT". This option may decrease number of the -## false positive detections. 0/1 = false/true +## false positive detections. 0/1 = false/true # GENERAL_IGNORE_FIRST_SEND = 0 ## ## How much of the flow has to be suspicious to report an attack (sensitivity) -## In the range of (0;1]. (0 would mean everything is considered an attack) +## In the range of (0;1]. (0 would mean everything is considered an attack) # GENERAL_MATCHED_FLOW_RATIO = 0.9 ####################################### ## PROTOCOL (X) KEYWORDS INFORMATION ## ## X -> SSH/RDP/TELNET -## -## X_ATTACK_TIMEOUT - After n seconds from last report set attack by given host +## +## X_ATTACK_TIMEOUT - After n seconds from last report set attack by given host ## as finished ## X_LIST_SIZE - Set number of max records(flows) that each host can store ## X_LIST_THRESHOLD - Set threshold for number of suspicious flows ## X_REPORT_TIMEOUT - Attacker can be reported again after n seconds. -## During this entire period attack information is agregated. -## X_ATTACK_TIMEOUT > X_REPORT_TIMEOUT +## During this entire period attack information is agregated. +## X_ATTACK_TIMEOUT > X_REPORT_TIMEOUT ## -## X_RECORD_TIMEOUT - Delete record from memory after n seconds -## X_HOST_TIMEOUT - Delete host from memory after n seconds of inactivity -## Shorter timeout means smaller memory usage of these two -## aforementioned keywords. On the other hand detection of +## X_RECORD_TIMEOUT - Delete record from memory after n seconds +## X_HOST_TIMEOUT - Delete host from memory after n seconds of inactivity +## Shorter timeout means smaller memory usage of these two +## aforementioned keywords. On the other hand detection of ## slower attacks could be worse ## -## Following keywords are used for check flow records which may correspond with +## Following keywords are used for check flow records which may correspond with ## brute force attack ## DIR - Flow direction : INC (Attacker -> Victim) ## OUT (Victim -> Victim) @@ -65,10 +65,10 @@ ######### SSH ########## ######################## #SSH_ATTACK_TIMEOUT = 600 -#SSH_LIST_SIZE = 50 -#SSH_LIST_THRESHOLD = 30 +#SSH_LIST_SIZE = 100 +#SSH_LIST_THRESHOLD = 90 #SSH_RECORD_TIMEOUT = 1800 -#SSH_HOST_TIMEOUT = 4200 +#SSH_HOST_TIMEOUT = 4200 #SSH_BRUTEFORCE_INC_MIN_PACKETS = 11 #SSH_BRUTEFORCE_INC_MAX_PACKETS = 30 #SSH_BRUTEFORCE_INC_MIN_BYTES = 1000 @@ -82,10 +82,10 @@ ######### RDP ########## ######################## #RDP_ATTACK_TIMEOUT = 600 -#RDP_LIST_SIZE = 50 -#RDP_LIST_THRESHOLD = 30 +#RDP_LIST_SIZE = 100 +#RDP_LIST_THRESHOLD = 90 #RDP_RECORD_TIMEOUT = 1800 -#RDP_HOST_TIMEOUT = 4200 +#RDP_HOST_TIMEOUT = 4200 #RDP_BRUTEFORCE_INC_MIN_PACKETS = 20 #RDP_BRUTEFORCE_INC_MAX_PACKETS = 100 #RDP_BRUTEFORCE_INC_MIN_BYTES = 2200 @@ -98,14 +98,14 @@ ######################## ######## Telnet ######## ######################## -#TELNET_ATTACK_TIMEOUT = 600 -#TELNET_LIST_SIZE = 50 -#TELNET_LIST_THRESHOLD = 30 +#TELNET_LIST_SIZE = 100 +#TELNET_LIST_THRESHOLD = 90 #TELNET_RECORD_TIMEOUT = 1800 -#TELNET_HOST_TIMEOUT = 4200 +#TELNET_HOST_TIMEOUT = 4200 #TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9 #TELNET_BRUTEFORCE_INC_MAX_PACKETS = 50 #TELNET_BRUTEFORCE_INC_MIN_BYTES = 450 #TELNET_BRUTEFORCE_INC_MAX_BYTES = 3000 ## Outgoing version is not supported +#TELNET_ATTACK_TIMEOUT = 600 #TELNET_REPORT_TIMEOUT = 300 diff --git a/brute_force_detector/config/whitelist.wl b/brute_force_detector/config/whitelist.wl index b18c5099..8a9a29ac 100644 --- a/brute_force_detector/config/whitelist.wl +++ b/brute_force_detector/config/whitelist.wl @@ -13,11 +13,12 @@ # direction: # "src", "dst" or "" (no keyword = src and dst) -dst 192.30.252.128/30/22 #github +dst 192.30.252.128/30/22 #github dst 131.103.20.160/28/22 #bitbucket src 166.88.20.3/32 # valid communication to 195.113.184.18 src 195.113.44.19/32 # valid(???) communication to 88.208.125.10 & 88.208.125.11 +# TODO Delete/solve unknown addresses diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 6213c59b..ecce8bd6 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -99,13 +99,13 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); return SSHHost::NEW_ATTACK; } else { - cout << std::max(incomingMatched, outgoingMatched) << "< bottomThreshold" << "\n"; + cout << std::max(incomingMatched, outgoingMatched) << "< bottomThreshold" << "\n"; // DEBUG return SSHHost::NO_ATTACK; } @@ -114,18 +114,20 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max list size per protocol - auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + double topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); return SSHHost::NEW_ATTACK; } else { - cout << topMatchedRatio << "< ratio" << "\n"; + // cout << incomingMatched << "/" << incomingListSize << "\n"; + // cout << outgoingMatched << "/" << outgoingListSize << "\n"; + cout << topMatchedRatio << " < ratio" << "\n"; // DEBUG return SSHHost::NO_ATTACK; } @@ -155,8 +157,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); // avoids div by zero - double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); - double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); + auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); + auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { @@ -226,9 +228,8 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); return RDPHost::NEW_ATTACK; } else @@ -240,14 +241,13 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max size - auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + auto topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); return RDPHost::NEW_ATTACK; } else @@ -279,8 +279,9 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); - double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); + // avoids div by zero + auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); + auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { @@ -350,9 +351,8 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); return TELNETHost::NEW_ATTACK; } else @@ -364,13 +364,13 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { // Number of records is between bottom size and max size - auto topMatchedRatio = std::max(incomingMatched/incomingListSize, outgoingMatched/outgoingListSize); + auto topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) { // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); return TELNETHost::NEW_ATTACK; } else @@ -402,8 +402,9 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : incomingMatchedNew / incomingTotalNew); - double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : outgoingMatchedNew / outgoingTotalNew); + // avoids div by zero + auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); + auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index b2e9d500..7bf49fae 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -75,8 +75,14 @@ class IHost { virtual ~IHost() = default; - enum ATTACK_STATE { NO_ATTACK, NEW_ATTACK, ATTACK_REPORT_WAIT, ATTACK, - ATTACK_MIN_EVENTS_WAIT, END_OF_ATTACK, REPORT_END_OF_ATTACK }; + enum ATTACK_STATE { NO_ATTACK, + NEW_ATTACK, // send report + ATTACK_REPORT_WAIT, + ATTACK, // send report + ATTACK_MIN_EVENTS_WAIT, + END_OF_ATTACK, + REPORT_END_OF_ATTACK // send report + }; inline ip_addr_t getHostIp() { return hostIp; } inline ur_time_t getTimeOfLastReport() { return timeOfLastReport; } @@ -84,9 +90,9 @@ class IHost { inline void setReportTime(ur_time_t actualTime) { timeOfLastReport = actualTime; } inline void setNotReported() { - timeOfLastReport = 0; recordListIncoming.clearTotalTargetsSinceAttack(); recordListOutgoing.clearTotalTargetsSinceAttack(); + timeOfLastReport = 0; } inline bool getHostScannedNetwork() { return scanned; } @@ -110,25 +116,11 @@ class IHost { recordListOutgoing.clearOldRecords(actualTime); } - virtual ur_time_t getHostDeleteTimeout() = 0; virtual bool canDeleteHost(ur_time_t actualTime) { - // TODO investigate this - /* - ur_time_t timeOfLastIncomingRecord = recordListIncoming.getTimeOfLastRecord(); - ur_time_t timeOfLastOutgoingRecord = recordListOutgoing.getTimeOfLastRecord(); - - if(timeOfLastIncomingRecord == 0 && timeOfLastOutgoingRecord == 0) //empty lists - { - return true; - } - - ur_time_t timeOfLastRecord = std::max(timeOfLastIncomingRecord, timeOfLastOutgoingRecord); - */ ur_time_t timer = getHostDeleteTimeout(); - // return checkForTimeout(timeOfLastRecord, timer, actualTime); return checkForTimeout(timeOfLastReceivedRecord, timer, actualTime); } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 842a98a8..4d41221f 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -103,6 +103,7 @@ class IRecord { bool signatureMatched; }; + class SSHRecord : public IRecord { public: @@ -114,6 +115,7 @@ class SSHRecord : public IRecord { const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH }; + class RDPRecord : public IRecord { public: @@ -163,15 +165,14 @@ class RecordList { inline void clearMatchedFlowsSinceLastReport() { matchedFlowsSinceLastReport = 0; } inline void clearTotalFlowsSinceLastReport() { totalFlowsSinceLastReport = 0; } - inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } - inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } - - inline uint16_t getCurrentTargets(); // TODO never used, investigate + inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } + inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } - inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } - inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } - inline void initTotalTargetsSet(); + inline uint16_t getCurrentTargets(); // TODO never used, investigate + inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } + inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } + inline void initTotalTargetsSet(); std::vector getIpsOfVictims(); @@ -183,11 +184,11 @@ class RecordList { uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; - // uint32_t flowCounter; // experimental - // uint32_t flowMatchedCounter; // experimental + uint32_t flowCounter; + uint32_t flowMatchedCounter; - std::set hashedDstIPSet; // TODO WHAT ARE THOSE? - std::set hashedDstTotalIPSet; // AND WHY ARE NEITHER EVER USED ANYWHERE ELSE? + std::set hashedDstIPSet; // TODO WHAT ARE THOSE? + std::set hashedDstTotalIPSet; // AND WHY ARE NEITHER EVER USED ANYWHERE ELSE? char victimIP[46]{}; }; @@ -198,8 +199,8 @@ RecordList::RecordList() actualListSize = 0; actualMatchedFlows = 0; - // flowCounter = 0; // experimental - // flowMatchedCounter = 0; // experimental + flowCounter = 0; + flowMatchedCounter = 0; matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; @@ -246,20 +247,19 @@ void RecordList::clearAllRecords() actualListSize = 0; actualMatchedFlows = 0; - // flowCounter = 0; // experimental - // flowMatchedCounter = 0; // experimental + + flowCounter = 0; + flowMatchedCounter = 0; matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; - - clearTargetsSinceLastReport(); } template void RecordList::addRecord(T record, bool isHostReported) { - // flowCounter++; // experimental actualListSize++; + flowCounter++; if(actualListSize > maxListSize) { @@ -280,8 +280,8 @@ void RecordList::addRecord(T record, bool isHostReported) if(record->isMatched()) { - // flowMatchedCounter++; // experimental actualMatchedFlows++; + flowMatchedCounter++; } if(isHostReported) @@ -292,8 +292,8 @@ void RecordList::addRecord(T record, bool isHostReported) { matchedFlowsSinceLastReport++; - hashedDstIPSet.insert(record->dstIp); - hashedDstTotalIPSet.insert(record->dstIp); + hashedDstIPSet.insert(record->dstIp); + hashedDstTotalIPSet.insert(record->dstIp); } } list.push_back(record); @@ -382,30 +382,31 @@ ur_time_t RecordList::getTimeOfLastRecord() template uint16_t RecordList::getCurrentTargets() { - std::set dstIpSet; - for(const auto & it : list) - { + std::set dstIpSet; + for(const auto & it : list) + { if(it->isMatched()) - { - dstIpSet.insert(it->dstIp); - } - } - return dstIpSet.size(); + { + dstIpSet.insert(it->dstIp); + } + } + return dstIpSet.size(); } template void RecordList::initTotalTargetsSet() { - for(const auto & it : list) - { + for(const auto & it : list) + { if(it->isMatched()) - { + { // TODO Why is TotalIPSet filled with matched flows only? - hashedDstTotalIPSet.insert(it->dstIp); - } - } + hashedDstTotalIPSet.insert(it->dstIp); + } + } } + template std::vector RecordList::getIpsOfVictims() { diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index faaeb3df..66522eb9 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -88,7 +88,7 @@ class Sender return TRAP_E_OK; } - //TODO check + //TODO test if output correct uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); @@ -105,12 +105,12 @@ class Sender string sNote; - host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); - host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToIncomingRecordList()->clearTotalFlowsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToOutgoingRecordList()->clearTotalFlowsSinceLastReport(); return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), endOfAttack, sNote); From be3d553c6b54057b4c37fbdb7faab41fd3401d0a Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Fri, 28 Jun 2019 15:15:41 +0200 Subject: [PATCH 25/40] Renamed attack states --- brute_force_detector/brute_force_detector.cpp | 12 ++++++------ brute_force_detector/brute_force_detector.h | 4 ++-- brute_force_detector/host.h | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index ff374595..ca3bd0f9 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -431,7 +431,7 @@ int main(int argc, char **argv) if(attackState != SSHHost::NO_ATTACK) { - if(attackState == SSHHost::NEW_ATTACK) + if(attackState == SSHHost::REPORT_NEW_ATTACK) { ret = sender->firstReport(host, TCP_SSH_PORT, structure.flowLastSeen, Config::getInstance().getSSHListThreshold()); } @@ -454,7 +454,7 @@ int main(int argc, char **argv) host->clearAllRecords(); host->setNotReported(); } - else if(attackState == SSHHost::ATTACK) + else if(attackState == SSHHost::REPORT_ATTACK) { ret = sender->continuingReport(host, TCP_SSH_PORT, structure.flowLastSeen); } @@ -509,7 +509,7 @@ int main(int argc, char **argv) RDPHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != RDPHost::NO_ATTACK) { - if(attackState == RDPHost::NEW_ATTACK) + if(attackState == RDPHost::REPORT_NEW_ATTACK) { ret = sender->firstReport(host, TCP_RDP_PORT, structure.flowLastSeen, Config::getInstance().getRDPListThreshold()); } @@ -531,7 +531,7 @@ int main(int argc, char **argv) host->clearAllRecords(); host->setNotReported(); } - else if(attackState == RDPHost::ATTACK) + else if(attackState == RDPHost::REPORT_ATTACK) { ret = sender->continuingReport(host, TCP_RDP_PORT, structure.flowLastSeen); } @@ -586,7 +586,7 @@ int main(int argc, char **argv) TELNETHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); if(attackState != TELNETHost::NO_ATTACK) { - if(attackState == TELNETHost::NEW_ATTACK) + if(attackState == TELNETHost::REPORT_NEW_ATTACK) { ret = sender->firstReport(host, TCP_TELNET_PORT, structure.flowLastSeen, Config::getInstance().getTELNETListThreshold()); } @@ -608,7 +608,7 @@ int main(int argc, char **argv) host->clearAllRecords(); host->setNotReported(); } - else if(attackState == TELNETHost::ATTACK) + else if(attackState == TELNETHost::REPORT_ATTACK) { ret = sender->continuingReport(host, TCP_TELNET_PORT, structure.flowLastSeen); } diff --git a/brute_force_detector/brute_force_detector.h b/brute_force_detector/brute_force_detector.h index 97a4fbe3..c18af9cc 100644 --- a/brute_force_detector/brute_force_detector.h +++ b/brute_force_detector/brute_force_detector.h @@ -102,11 +102,11 @@ class logInfo { std::cout << std::endl; std::cout << " Matched Incoming Flows: " << this->matchedIncomingFlows; printFlowPercent(this->matchedFlows, this->matchedIncomingFlows, " from matched"); - printFlowPercent(this->flows, this->matchedIncomingFlows, " from all flows"); + printFlowPercent(this->flows, this->matchedIncomingFlows, " from incoming"); std::cout << std::endl; std::cout << " Matched Outgoing Flows: " << this->matchedOutgoingFlows; printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows, " from matched"); - printFlowPercent(this->flows, this->matchedOutgoingFlows, " from all flows"); + printFlowPercent(this->flows, this->matchedOutgoingFlows, " from outgoing"); std::cout << std::endl; } diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 7bf49fae..2cac2548 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -76,9 +76,9 @@ class IHost { virtual ~IHost() = default; enum ATTACK_STATE { NO_ATTACK, - NEW_ATTACK, // send report + REPORT_NEW_ATTACK, // send report ATTACK_REPORT_WAIT, - ATTACK, // send report + REPORT_ATTACK, // send report ATTACK_MIN_EVENTS_WAIT, END_OF_ATTACK, REPORT_END_OF_ATTACK // send report From 9c363c3c76ec79a310fd3e10835c94cb6473f571 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Wed, 18 Sep 2019 17:18:31 +0200 Subject: [PATCH 26/40] Clarified portscans, minor changes --- brute_force_detector/brute_force_detector.cpp | 32 ++++++++++++------- brute_force_detector/host.h | 24 +++++++------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index ca3bd0f9..b23d0237 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -245,7 +245,8 @@ int main(int argc, char **argv) if(!RDP && !SSH && !TELNET) { cerr << "Error: Detection mode is not set.\n"; - return 3; + FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) + return 3; } // ***** Config init ***** @@ -286,7 +287,7 @@ int main(int argc, char **argv) free(errstr); } trap_finalize(); - FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS); + FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) return 4; } @@ -323,7 +324,7 @@ int main(int argc, char **argv) // Receive data from input interface (block until data are available) const void *data; uint16_t data_size; - ret = TRAP_RECEIVE(0, data, data_size, tmplt); + ret = TRAP_RECEIVE(0, data, data_size, tmplt) TRAP_DEFAULT_RECV_ERROR_HANDLING(ret, continue, break); // Check size of received data @@ -386,6 +387,7 @@ int main(int argc, char **argv) if(SSH && (dstPort == TCP_SSH_PORT || srcPort == TCP_SSH_PORT)) { bool is_matched; + bool is_portscan; SSHRecord *record; if(direction == FLOW_INCOMING_DIRECTION) @@ -398,8 +400,9 @@ int main(int argc, char **argv) } ssh.incomingFlows++; } - else // FLOW_OUTGOING_DIRECTION + else { + // FLOW_OUTGOING_DIRECTION record = new SSHRecord(structure.srcIp, structure.flowLastSeen); is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); if(is_matched) @@ -418,9 +421,9 @@ int main(int argc, char **argv) // host is the source of current flow/connection SSHHost *host = sshHostMap.findHost(&structure, direction); - is_matched = host->addRecord(record, &structure, direction); + is_portscan = host->addRecord(record, &structure, direction); - if(!is_matched) + if(!is_matched || is_portscan) { delete record; } @@ -466,6 +469,7 @@ int main(int argc, char **argv) if(RDP && (dstPort == TCP_RDP_PORT || srcPort == TCP_RDP_PORT)) { bool is_matched; + bool is_portscan; RDPRecord *record; if(direction == FLOW_INCOMING_DIRECTION) @@ -498,8 +502,8 @@ int main(int argc, char **argv) RDPHost *host = rdpHostMap.findHost(&structure, direction); - is_matched = host->addRecord(record, &structure, direction); - if(!is_matched) + is_portscan = host->addRecord(record, &structure, direction); + if(!is_matched || is_portscan) { delete record; } @@ -543,6 +547,7 @@ int main(int argc, char **argv) if(TELNET && (dstPort == TCP_TELNET_PORT || srcPort == TCP_TELNET_PORT)) { bool is_matched; + bool is_portscan; TELNETRecord *record; if(direction == FLOW_INCOMING_DIRECTION) @@ -575,8 +580,8 @@ int main(int argc, char **argv) TELNETHost *host = telnetHostMap.findHost(&structure, direction); - is_matched = host->addRecord(record, &structure, direction); - if(!is_matched) + is_portscan = host->addRecord(record, &structure, direction); + if(!is_matched || is_portscan) { delete record; } @@ -633,6 +638,7 @@ int main(int argc, char **argv) telnetHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); } } + if(checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, structure.flowLastSeen)) { timeOfLastDeleteCheck = structure.flowLastSeen; @@ -656,11 +662,14 @@ int main(int argc, char **argv) } // ***** End of main processing loop ***** + + // TODO how to pass Host Map base class to printLogInfo if(SSH) { ssh.printLogInfo(); std::cout << " Host Map Size: " << sshHostMap.size() << std::endl; + sshHostMap.clear(); } if(RDP) @@ -676,7 +685,8 @@ int main(int argc, char **argv) telnetHostMap.clear(); } - TRAP_DEFAULT_FINALIZATION(); + + TRAP_DEFAULT_FINALIZATION(); ur_free_template(tmplt); ur_finalize(); delete sender; // free output template diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 2cac2548..d7aa0285 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -239,12 +239,12 @@ class IHostMap { { auto it = c->begin(); - while(it != c->end()) + while(it != c->end()) { - // if(it->second) // TODO is this change harmless? - delete it->second; - it++; + if(it->second) // TODO harmless to remove this? + delete it->second; + it++; } c->clear(); } @@ -288,9 +288,9 @@ class SSHHostMap : public IHostMap { ~SSHHostMap() = default; void clear() override - { - IHostMap::clearMap(&hostMap); - } + { + IHostMap::clearMap(&hostMap); + } inline uint16_t size() override { return hostMap.size(); @@ -310,10 +310,10 @@ class RDPHostMap: public IHostMap { RDPHostMap() = default; ~RDPHostMap() = default; - void clear() override - { - IHostMap::clearMap(&hostMap); - } + void clear() override + { + IHostMap::clearMap(&hostMap); + } inline uint16_t size() override { @@ -337,7 +337,7 @@ class TELNETHostMap: public IHostMap { void clear() override { - IHostMap::clearMap(&hostMap); + IHostMap::clearMap(&hostMap); } inline uint16_t size() override From cfaf279df97ffb07df0e28c5f229abbdee044be1 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 19 Sep 2019 10:28:07 +0200 Subject: [PATCH 27/40] Reverted deleting of some variables --- brute_force_detector/sender.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index 66522eb9..1208a175 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -88,7 +88,7 @@ class Sender return TRAP_E_OK; } - //TODO test if output correct + // TODO test if output correct uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); From c42c0233bfe778fab24cc67858b93ecf0b186904 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 19 Sep 2019 10:41:21 +0200 Subject: [PATCH 28/40] Revert "Reverted deleting of some variables" This reverts commit 2fc9ccea --- brute_force_detector/record.h | 21 +++++++++++---------- brute_force_detector/sender.h | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 4d41221f..45632c7e 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -187,8 +187,9 @@ class RecordList { uint32_t flowCounter; uint32_t flowMatchedCounter; - std::set hashedDstIPSet; // TODO WHAT ARE THOSE? - std::set hashedDstTotalIPSet; // AND WHY ARE NEITHER EVER USED ANYWHERE ELSE? + // These keep track of all IPs, even after the host becomes inactive, for output log + std::set hashedDstIPSet; + std::set hashedDstTotalIPSet; char victimIP[46]{}; }; @@ -199,12 +200,12 @@ RecordList::RecordList() actualListSize = 0; actualMatchedFlows = 0; - flowCounter = 0; - flowMatchedCounter = 0; - matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; + flowCounter = 0; + flowMatchedCounter = 0; + if(typeid(T) == typeid(SSHRecord*)) { maxListSize = Config::getInstance().getSSHMaxListSize(); @@ -251,7 +252,7 @@ void RecordList::clearAllRecords() flowCounter = 0; flowMatchedCounter = 0; - matchedFlowsSinceLastReport = 0; + matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; } @@ -259,9 +260,9 @@ template void RecordList::addRecord(T record, bool isHostReported) { actualListSize++; - flowCounter++; + flowCounter++; - if(actualListSize > maxListSize) + if(actualListSize > maxListSize) { // list is full // delete first record @@ -281,8 +282,8 @@ void RecordList::addRecord(T record, bool isHostReported) if(record->isMatched()) { actualMatchedFlows++; - flowMatchedCounter++; - } + flowMatchedCounter++; + } if(isHostReported) { diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index 1208a175..66522eb9 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -88,7 +88,7 @@ class Sender return TRAP_E_OK; } - // TODO test if output correct + //TODO test if output correct uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); From 39d0ff4f44504026618b214ccf449b4d5c343bc1 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 19 Sep 2019 12:34:56 +0200 Subject: [PATCH 29/40] fixed attack names after rebasing --- brute_force_detector/host.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index ecce8bd6..d7e6e590 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -101,7 +101,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); - return SSHHost::NEW_ATTACK; + return SSHHost::REPORT_NEW_ATTACK; } else { @@ -121,7 +121,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); - return SSHHost::NEW_ATTACK; + return SSHHost::REPORT_NEW_ATTACK; } else { @@ -174,7 +174,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { - return SSHHost::ATTACK; + return SSHHost::REPORT_ATTACK; } else { @@ -230,7 +230,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); - return RDPHost::NEW_ATTACK; + return RDPHost::REPORT_NEW_ATTACK; } else { @@ -248,7 +248,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); - return RDPHost::NEW_ATTACK; + return RDPHost::REPORT_NEW_ATTACK; } else { @@ -297,7 +297,7 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { - return RDPHost::ATTACK; + return RDPHost::REPORT_ATTACK; } else { @@ -353,7 +353,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); - return TELNETHost::NEW_ATTACK; + return TELNETHost::REPORT_NEW_ATTACK; } else { @@ -371,7 +371,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); - return TELNETHost::NEW_ATTACK; + return TELNETHost::REPORT_NEW_ATTACK; } else { @@ -420,7 +420,7 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { - return TELNETHost::ATTACK; + return TELNETHost::REPORT_ATTACK; } else { @@ -485,9 +485,9 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { - std::cout << "deleting:" << size(); // DEBUG + std::cerr << "deleting:" << hostMap.size(); // DEBUG IHostMap::clearOldRecAndHost(&hostMap, actualTime); - std::cout << "," << size() << "\n"; // DEBUG + std::cerr << "," << size() << "\n"; // DEBUG } // ************************************************************/ From afd1d5386d5a1bc3b6e0ddbedb27616806a903ed Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 19 Sep 2019 13:22:31 +0200 Subject: [PATCH 30/40] reverted evaluation of portscan-matched --- brute_force_detector/brute_force_detector.cpp | 13 ++++++------- brute_force_detector/host.cpp | 9 --------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index b23d0237..bca87b6c 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -172,7 +172,6 @@ void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment /* opti int main(int argc, char **argv) { - // getc(stdin); /// DEBUG // ***** TRAP initialization ***** int ret; INIT_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) @@ -421,9 +420,9 @@ int main(int argc, char **argv) // host is the source of current flow/connection SSHHost *host = sshHostMap.findHost(&structure, direction); - is_portscan = host->addRecord(record, &structure, direction); + is_portscan = !host->addRecord(record, &structure, direction); - if(!is_matched || is_portscan) + if(is_portscan) { delete record; } @@ -502,8 +501,8 @@ int main(int argc, char **argv) RDPHost *host = rdpHostMap.findHost(&structure, direction); - is_portscan = host->addRecord(record, &structure, direction); - if(!is_matched || is_portscan) + is_portscan = !host->addRecord(record, &structure, direction); + if(is_portscan) { delete record; } @@ -580,8 +579,8 @@ int main(int argc, char **argv) TELNETHost *host = telnetHostMap.findHost(&structure, direction); - is_portscan = host->addRecord(record, &structure, direction); - if(!is_matched || is_portscan) + is_portscan = !host->addRecord(record, &structure, direction); + if(is_portscan) { delete record; } diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index d7e6e590..c252df0b 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -92,7 +92,6 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - // Number of records in list is lower than BottomSize (50 by default) if (std::max(incomingListSize, outgoingListSize) <= Config::getInstance().getSSHListBottomSize()) { @@ -105,8 +104,6 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } else { - cout << std::max(incomingMatched, outgoingMatched) << "< bottomThreshold" << "\n"; // DEBUG - return SSHHost::NO_ATTACK; } } @@ -125,11 +122,7 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) } else { - // cout << incomingMatched << "/" << incomingListSize << "\n"; - // cout << outgoingMatched << "/" << outgoingListSize << "\n"; - cout << topMatchedRatio << " < ratio" << "\n"; // DEBUG return SSHHost::NO_ATTACK; - } } } @@ -485,9 +478,7 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { - std::cerr << "deleting:" << hostMap.size(); // DEBUG IHostMap::clearOldRecAndHost(&hostMap, actualTime); - std::cerr << "," << size() << "\n"; // DEBUG } // ************************************************************/ From f36326fe184e93c509d31d9223406da68b42e48f Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 19 Sep 2019 14:04:11 +0200 Subject: [PATCH 31/40] Minor changes --- brute_force_detector/README.md | 12 +--- brute_force_detector/brute_force_detector.cpp | 2 - brute_force_detector/config/whitelist.wl | 4 +- brute_force_detector/record.h | 4 +- brute_force_detector/whitelist.cpp | 70 +++++++++---------- 5 files changed, 42 insertions(+), 50 deletions(-) diff --git a/brute_force_detector/README.md b/brute_force_detector/README.md index 9716fb4f..367654b3 100644 --- a/brute_force_detector/README.md +++ b/brute_force_detector/README.md @@ -1,4 +1,4 @@ - Bruteforce detector module +Bruteforce detector module ========================== @@ -46,14 +46,8 @@ Unirec template for output interface is `DETECTION_TIME,WARDEN_TYPE,SRC_IP,PROTO * `PROTOCOL` : TCP protocol number * `DST_PORT` : Port of the attacked service * `EVENT_SCALE` : Scale of the detected event -* `NOTE` : This field contains (comma is used as separator): - - 1. Total number of targets since start of the attack from both -directions separated by a dash - 2. Flag if the scan is performed - 3. Number of suspicious flows from both directions and since -last report separated by a dash - +* `NOTE` : This field contains (comma is used as separator): + "I: (list of incoming attacker IPs), O: (list of outgoing attacked IPs)" How to use ---------- diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index bca87b6c..44d5a39a 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -668,7 +668,6 @@ int main(int argc, char **argv) { ssh.printLogInfo(); std::cout << " Host Map Size: " << sshHostMap.size() << std::endl; - sshHostMap.clear(); } if(RDP) @@ -684,7 +683,6 @@ int main(int argc, char **argv) telnetHostMap.clear(); } - TRAP_DEFAULT_FINALIZATION(); ur_free_template(tmplt); ur_finalize(); diff --git a/brute_force_detector/config/whitelist.wl b/brute_force_detector/config/whitelist.wl index 8a9a29ac..69941148 100644 --- a/brute_force_detector/config/whitelist.wl +++ b/brute_force_detector/config/whitelist.wl @@ -16,8 +16,8 @@ dst 192.30.252.128/30/22 #github dst 131.103.20.160/28/22 #bitbucket -src 166.88.20.3/32 # valid communication to 195.113.184.18 -src 195.113.44.19/32 # valid(???) communication to 88.208.125.10 & 88.208.125.11 +src 166.88.20.3/32 # EGIHosting (USA) ?, valid communication to 195.113.184.18, +src 195.113.44.19/32 # Charles University, valid(???) communication to 88.208.125.10 & 88.208.125.11, # TODO Delete/solve unknown addresses diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 45632c7e..e922431b 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -94,7 +94,7 @@ class IRecord { ur_time_t flowLastSeen; }; - // May seem unused, actually are passed to reporting functions TODO why separate from MatchStructure + // May seem unused, actually are passed to reporting functions ip_addr_t dstIp{}; ur_time_t flowLastSeen{}; @@ -124,7 +124,7 @@ class RDPRecord : public IRecord { bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } - const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; // SYN + ACK + PSH + RST const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; // SYN + ACK + PSH }; diff --git a/brute_force_detector/whitelist.cpp b/brute_force_detector/whitelist.cpp index abb28098..f797b4b4 100644 --- a/brute_force_detector/whitelist.cpp +++ b/brute_force_detector/whitelist.cpp @@ -160,10 +160,10 @@ bool Whitelist::isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, ui { locked = true; bool found = false; - + if (ip_is4(srcIp)) { - //ipv4 - //check src addr first + // ipv4 + // check src addr first found = trieSearch(ipv4Src, (uint8_t*) srcIp + 8, 4, srcPort); if (found) { locked = false; @@ -175,15 +175,15 @@ bool Whitelist::isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, ui locked = false; return true; } - } else { //ipv6 - //check src addr first + } else { // ipv6 + // check src addr first found = trieSearch(ipv6Src, (uint8_t*) srcIp, 6, srcPort); if (found) { locked = false; return true; } - //check dst addr + // check dst addr found = trieSearch(ipv6Dst, (uint8_t*) dstIp, 6, dstPort); if (found) { locked = false; @@ -202,9 +202,9 @@ bool Whitelist::trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t for (int i = 0; i < iRange; i++) { for (int u = 7; u >= 0; u--) { - //change last known node + // change last known node if (currentNode->set) { - //vsechny porty + // vsechny porty if (currentNode->allPorts) { return true; } @@ -215,10 +215,10 @@ bool Whitelist::trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t } } - //search right + // search right if (((ip[i] >> u) & 1) > 0) { currentNode = currentNode->right; - } else { //search left + } else { // search left currentNode = currentNode->left; } @@ -283,15 +283,15 @@ void WhitelistParser::parse(ifstream *ifs, bool verboseMode) if (line[0] == WHITELIST_PARSER_COMMENT_DELIM) { // skip comment line continue; - } + } - //substring before comment delim if exists + // substring before comment delim if exists size_t pos = line.find_first_of(WHITELIST_PARSER_COMMENT_DELIM); if (pos != string::npos) { line = line.substr(0, pos); } - //now check for src or dst direction + // now check for src or dst direction if (line.size() < 4) { if(verbose) { cout << "Invalid line: " << line << endl; @@ -312,13 +312,13 @@ void WhitelistParser::parse(ifstream *ifs, bool verboseMode) direction = WHITELIST_PARSER_IP_DIRECTION_ALL; } - //now ip check parse + // now ip check parse pos = line.find_first_of(WHITELIST_PARSER_PREFIX_DELIM); if (pos != string::npos) { string ipstring = line.substr(0, pos); ip_addr_t ip; if (ip_from_str(ipstring.c_str(), &ip)) { - //ip ok, now parse prefix and ports + // ip ok, now parse prefix and ports string prefixAndPorts = line.substr(pos + 1); if (!prefixAndPorts.empty()) { if (verbose) { @@ -330,7 +330,7 @@ void WhitelistParser::parse(ifstream *ifs, bool verboseMode) if (pos != string::npos) { string prefixStr = prefixAndPorts.substr(0, pos); int prefix = atoi(prefixStr.c_str()); - //get ports now + // get ports now ports = prefixAndPorts.substr(pos + 1); if (ports.empty()) { if (verbose) { @@ -340,10 +340,10 @@ void WhitelistParser::parse(ifstream *ifs, bool verboseMode) if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { if (verbose) { cout << "Invalid line: " << line << endl; - } + } } } - } else { //??? mtva vezev? + } else { // ??? mtva vezev? int prefix = atoi(prefixAndPorts.c_str()); if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { if (verbose) { @@ -354,7 +354,7 @@ void WhitelistParser::parse(ifstream *ifs, bool verboseMode) } else if (verbose) { cout << "Invalid line: " << line << endl; } - } else if (verbose) { //invalid ip + } else if (verbose) { // invalid ip cout << "Invalid line: " << line << endl; } } else if (verbose) { @@ -387,16 +387,16 @@ void WhitelistParser::prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, u addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Dst, ports); } else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Src, ports); - } else { //direction == WHITELIST_PARSER_IP_DIRECTION_DST + } else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Dst, ports); } - } else { //ipv6 + } else { // ipv6 if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Src, ports); addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Dst, ports); } else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Src, ports); - } else { //direction == WHITELIST_PARSER_IP_DIRECTION_DST + } else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Dst, ports); } } @@ -417,7 +417,7 @@ void WhitelistParser::addPorts(IPTrie *currentNode, string ports) ports = ports.substr(pos + 1); pos = portString.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); - if (pos != string::npos) { //range + if (pos != string::npos) { // range string firstStringPort = portString.substr(0, pos); string secondStringPort = portString.substr(pos + 1); if (secondStringPort.empty()) { @@ -436,7 +436,7 @@ void WhitelistParser::addPorts(IPTrie *currentNode, string ports) if (verbose) { cout << "Adding port range " << portString << endl; } - } else { //single port + } else { // single port uint16_t port = atoi(portString.c_str()); whitelistedPorts->addSinglePort(port); if(verbose) { @@ -447,7 +447,7 @@ void WhitelistParser::addPorts(IPTrie *currentNode, string ports) addPorts(currentNode, ports); } else { pos = ports.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); - if (pos != string::npos) { //range + if (pos != string::npos) { // range string firstStringPort = ports.substr(0, pos); string secondStringPort = ports.substr(pos + 1); if (secondStringPort.empty()) { @@ -467,7 +467,7 @@ void WhitelistParser::addPorts(IPTrie *currentNode, string ports) if (verbose) { cout << "Adding port range " << ports << endl; } - } else { //single port + } else { // single port uint16_t port = atoi(ports.c_str()); whitelistedPorts->addSinglePort(port); if (verbose) { @@ -481,22 +481,22 @@ void WhitelistParser::addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie { IPTrie *currentNode = trie; for (int i = 0; i < prefix; i++) { - //bitset go right + // bitset go right if (((ip[i / 8] >> (7 - i % 8)) & 1) > 0) { if (currentNode->right == NULL) { currentNode->right = new IPTrie(); } - //next + // next currentNode = currentNode->right; - } else { //go left + } else { // go left if (currentNode->left == NULL) { currentNode->left = new IPTrie(); } - //next + // next currentNode = currentNode->left; } - if ((i + 1) == prefix) { //last pos + if ((i + 1) == prefix) { // last pos if(currentNode->whitelistedPorts == NULL) { currentNode->whitelistedPorts = new WhitelistedPorts; } @@ -504,14 +504,14 @@ void WhitelistParser::addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie if (ports.empty()) { currentNode->allPorts = true; } else { - addPorts(currentNode, ports); + addPorts(currentNode, ports); } - + currentNode->set = true; rulesCounter++; } } - //prefix 0 + // prefix 0 if (prefix == 0) { if (currentNode->whitelistedPorts == NULL) { currentNode->whitelistedPorts = new WhitelistedPorts; @@ -520,7 +520,7 @@ void WhitelistParser::addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie if (ports.empty()) { currentNode->allPorts = true; } else { - addPorts(currentNode, ports); + addPorts(currentNode, ports); } currentNode->set = true; From 63e9108693daea9ccb1f9fe35fb3a65c84210db7 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 19 Sep 2019 16:37:30 +0200 Subject: [PATCH 32/40] Fixed some config var names --- brute_force_detector/config/config.conf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/brute_force_detector/config/config.conf b/brute_force_detector/config/config.conf index bb1d1c0c..6aa50f44 100644 --- a/brute_force_detector/config/config.conf +++ b/brute_force_detector/config/config.conf @@ -67,6 +67,7 @@ #SSH_ATTACK_TIMEOUT = 600 #SSH_LIST_SIZE = 100 #SSH_LIST_THRESHOLD = 90 +#SSH_LIST_SIZE_BOTTOM_THRESHOLD = 100 #SSH_RECORD_TIMEOUT = 1800 #SSH_HOST_TIMEOUT = 4200 #SSH_BRUTEFORCE_INC_MIN_PACKETS = 11 @@ -82,8 +83,9 @@ ######### RDP ########## ######################## #RDP_ATTACK_TIMEOUT = 600 -#RDP_LIST_SIZE = 100 +#RDP_LIST_SIZE = 500 #RDP_LIST_THRESHOLD = 90 +#RDP_LIST_SIZE_BOTTOM_THRESHOLD = 100 #RDP_RECORD_TIMEOUT = 1800 #RDP_HOST_TIMEOUT = 4200 #RDP_BRUTEFORCE_INC_MIN_PACKETS = 20 @@ -100,6 +102,7 @@ ######################## #TELNET_LIST_SIZE = 100 #TELNET_LIST_THRESHOLD = 90 +#TELNET_LIST_SIZE_BOTTOM_THRESHOLD = 100 #TELNET_RECORD_TIMEOUT = 1800 #TELNET_HOST_TIMEOUT = 4200 #TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9 From 8fe3b5e2c92bea9a87f21dbd9f8bac8a01b62ecf Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Fri, 20 Sep 2019 13:53:18 +0200 Subject: [PATCH 33/40] Simplified attack evaluation, % of matched flows separate for each proto --- brute_force_detector/brute_force_detector.cpp | 646 ++++++++---------- brute_force_detector/config.cpp | 304 ++++----- brute_force_detector/config.h | 29 +- brute_force_detector/config/config.conf | 21 +- brute_force_detector/config/whitelist.wl | 4 +- brute_force_detector/host.cpp | 622 +++++++---------- brute_force_detector/host.h | 6 +- 7 files changed, 671 insertions(+), 961 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 44d5a39a..bde29eed 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -69,6 +69,7 @@ #include #include #include + #ifdef __cplusplus extern "C" { #endif @@ -80,17 +81,27 @@ extern "C" { using namespace std; UR_FIELDS( - // BASIC_FLOW - ipaddr SRC_IP, // Source address of a flow - ipaddr DST_IP, // Destination address of a flow - uint16 SRC_PORT, // Source transport-layer port - uint16 DST_PORT, // Destination transport-layer port - uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) - uint32 PACKETS, // Number of packets in a flow or in an interval - uint64 BYTES, // Number of bytes in a flow or in an interval - time TIME_FIRST, // Timestamp of the first packet of a flow - time TIME_LAST, // Timestamp of the last packet of a flow - uint8 TCP_FLAGS, // TCP flags of a flow (logical OR over TCP flags field of all packets) +// BASIC_FLOW + ipaddr + SRC_IP, // Source address of a flow + ipaddr + DST_IP, // Destination address of a flow + uint16 + SRC_PORT, // Source transport-layer port + uint16 + DST_PORT, // Destination transport-layer port + uint8 + PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint32 + PACKETS, // Number of packets in a flow or in an interval + uint64 + BYTES, // Number of bytes in a flow or in an interval + time + TIME_FIRST, // Timestamp of the first packet of a flow + time + TIME_LAST, // Timestamp of the last packet of a flow + uint8 + TCP_FLAGS, // TCP flags of a flow (logical OR over TCP flags field of all packets) ) /* ************************************************************************* */ @@ -99,7 +110,7 @@ trap_module_info_t *module_info = nullptr; #define MODULE_BASIC_INFO(BASIC) \ - BASIC("brute_force_detector","A module used for detecting brute force dictionary attacks on SSH, RDP and Telnet protocols. For detection is used window with N last flows and if threshold of a suspicious flows (packet and byte range is checked) is reached, alarm is triggered.",1,1) + BASIC("brute_force_detector","A module used for detecting brute force dictionary attacks on SSH, RDP and Telnet protocols. A window of N last flows is used and if threshold of matched flows (packet and byte range is checked) is reached, alarm is triggered.",1,1) #define MODULE_PARAMS(PARAM) \ PARAM('S', "SSH", "Set detection mode to SSH.", no_argument, "none") \ @@ -115,63 +126,47 @@ static int stop = 0; TelnetServerProfileMap TELNETRecord::TSPMap; Whitelist whitelist; -void signalHandler(int signal) -{ - if(signal == SIGTERM || signal == SIGINT) - { +void signalHandler(int signal) { + if (signal == SIGTERM || signal == SIGINT) { stop = 1; trap_terminate(); - } - else if(signal == SIGUSR1) - { + } else if (signal == SIGUSR1) { Config::getInstance().reloadConfig(); - } - else if(signal == SIGUSR2) - { - if(!whitelist.isLockedForConfigurationReload()) - { - whitelist.reloadWhitelist(); - } - else - { - alarm(1); // cannot reload now.. wait - } - } - else if(signal == SIGALRM) - { - if(!whitelist.isLockedForConfigurationReload()) - { - whitelist.reloadWhitelist(); - } - else - { - alarm(1); // wait another second - } + } else if (signal == SIGUSR2) { + if (!whitelist.isLockedForConfigurationReload()) { + whitelist.reloadWhitelist(); + } else { + alarm(1); // cannot reload now.. wait + } + } else if (signal == SIGALRM) { + if (!whitelist.isLockedForConfigurationReload()) { + whitelist.reloadWhitelist(); + } else { + alarm(1); // wait another second + } } } -void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment /* optional, implicitly set to "" (see .h) */) -{ - double percentage = 0.0; - if (b != 0 && p != 0) - { - percentage = 100.0 / b * p; - } +void +printFlowPercent(uint64_t b, uint64_t p, const std::string &comment /* optional, implicitly set to "" (see .h) */) { + double percentage = 0.0; + if (b != 0 && p != 0) { + percentage = 100.0 / b * p; + } - ios::fmtflags f(cout.flags()); + ios::fmtflags f(cout.flags()); - cout << " (" - << std::fixed << std::setprecision(2) - << percentage - << "%" << comment << ")"; - cout.flags(f); + cout << " (" + << std::fixed << std::setprecision(2) + << percentage + << "%" << comment << ")"; + cout.flags(f); } -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { // ***** TRAP initialization ***** int ret; INIT_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) @@ -200,7 +195,7 @@ int main(int argc, char **argv) sigaction (SIGALRM, &sigAction, nullptr); #else signal(SIGTERM, signalHandler); - signal(SIGINT, signalHandler); + signal(SIGINT, signalHandler); signal(SIGUSR1, signalHandler); signal(SIGUSR2, signalHandler); signal(SIGALRM, signalHandler); @@ -212,60 +207,53 @@ int main(int argc, char **argv) char *whitelistFilePath = nullptr; bool whitelistParserVerbose = false; bool RDP = false, SSH = false, TELNET = false; - while((opt = TRAP_GETOPT(argc, argv, module_getopt_string, long_options)) != -1) - { - switch (opt) - { - case 'c': // config - configFilePath = optarg; - break; - case 'w': - whitelistFilePath = optarg; - break; - case 'W': - whitelistParserVerbose = true; - break; - case 'R': - RDP = true; - break; - case 'S': - SSH = true; - break; - case 'T': - TELNET = true; - break; - default: - cerr << "Error: Invalid arguments.\n"; - FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) - return 3; + while ((opt = TRAP_GETOPT(argc, argv, module_getopt_string, long_options)) != -1) { + switch (opt) { + case 'c': // config + configFilePath = optarg; + break; + case 'w': + whitelistFilePath = optarg; + break; + case 'W': + whitelistParserVerbose = true; + break; + case 'R': + RDP = true; + break; + case 'S': + SSH = true; + break; + case 'T': + TELNET = true; + break; + default: + cerr << "Error: Invalid arguments.\n"; + FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) + return 3; } } - if(!RDP && !SSH && !TELNET) - { + if (!RDP && !SSH && !TELNET) { cerr << "Error: Detection mode is not set.\n"; - FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) - return 3; + FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) + return 3; } // ***** Config init ***** - if(configFilePath != nullptr) - { + if (configFilePath != nullptr) { bool state = Config::getInstance().initFromFile(configFilePath); - if(!state) - { + if (!state) { cerr << "Error: Cannot open configuration file \"" << configFilePath << "\".\n"; FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) return 5; } } - // ***** Whitelist init ***** - if(whitelistFilePath != nullptr) - { + // ***** Whitelist init ***** + if (whitelistFilePath != nullptr) { bool state = whitelist.init(whitelistFilePath, whitelistParserVerbose); - if (!state) - { + if (!state) { cerr << "Error: Cannot open whitelist file.\n"; FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) return 5; @@ -277,25 +265,22 @@ int main(int argc, char **argv) char *errstr = nullptr; ur_template_t *tmplt = ur_create_input_template(0, unirecSpecifier.c_str(), &errstr); - if (tmplt == nullptr) - { - cerr << "Error: Invalid UniRec specifier." << endl; - if(errstr != nullptr) - { - fprintf(stderr, "%s\n", errstr); - free(errstr); - } - trap_finalize(); - FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) - return 4; + if (tmplt == nullptr) { + cerr << "Error: Invalid UniRec specifier." << endl; + if (errstr != nullptr) { + fprintf(stderr, "%s\n", errstr); + free(errstr); + } + trap_finalize(); + FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) + return 4; } // ***** Init UniRec template for sender ***** bool senderState; auto sender = new Sender(&senderState); - if(!senderState) - { + if (!senderState) { cerr << "Error: Invalid output UniRec specifier. Check sender.cpp file.\n"; delete sender; ur_free_template(tmplt); @@ -305,21 +290,20 @@ int main(int argc, char **argv) } // ***** Main processing loop ***** - SSHHostMap sshHostMap; - RDPHostMap rdpHostMap; + SSHHostMap sshHostMap; + RDPHostMap rdpHostMap; TELNETHostMap telnetHostMap; logInfo ssh("SSH"); - logInfo rdp("RDP"); - logInfo telnet("TELNET"); + logInfo rdp("RDP"); + logInfo telnet("TELNET"); ur_time_t timeOfLastReportCheck = 0; ur_time_t timeOfLastDeleteCheck = 0; ur_time_t timerForReportCheck = Config::getInstance().getGlobalTimerForReportCheck(); ur_time_t timerForDeleteCheck = Config::getInstance().getGlobalTimerForDeleteCheck(); - while(!stop) - { + while (!stop) { // Receive data from input interface (block until data are available) const void *data; uint16_t data_size; @@ -327,14 +311,10 @@ int main(int argc, char **argv) TRAP_DEFAULT_RECV_ERROR_HANDLING(ret, continue, break); // Check size of received data - if(data_size < ur_rec_fixlen_size(tmplt)) - { - if(data_size <= 1) - { + if (data_size < ur_rec_fixlen_size(tmplt)) { + if (data_size <= 1) { break; // End of data (used for testing purposes) - } - else - { + } else { cerr << "Error: data with wrong size received (expected size: >= " << ur_rec_fixlen_size(tmplt) << ", received size: " << data_size << ")\n"; @@ -343,347 +323,277 @@ int main(int argc, char **argv) } // Skip non TCP flows - if(ur_get(tmplt, data, F_PROTOCOL) != TCP_PROTOCOL_NUM) - { - continue; - } + if (ur_get(tmplt, data, F_PROTOCOL) != TCP_PROTOCOL_NUM) { + continue; + } uint16_t dstPort = ur_get(tmplt, data, F_DST_PORT); uint16_t srcPort = ur_get(tmplt, data, F_SRC_PORT); - if(dstPort != TCP_SSH_PORT && dstPort != TCP_TELNET_PORT && dstPort != TCP_RDP_PORT - && srcPort != TCP_SSH_PORT && srcPort != TCP_TELNET_PORT && srcPort != TCP_RDP_PORT) - { - continue; - } - - uint8_t direction; - if(dstPort == TCP_SSH_PORT || dstPort == TCP_TELNET_PORT || dstPort == TCP_RDP_PORT) - { - direction = FLOW_INCOMING_DIRECTION; - } - else - { - direction = FLOW_OUTGOING_DIRECTION; - } - - // Process rest of new data - IRecord::MatchStructure structure { // TODO proper name - .flags = ur_get(tmplt, data, F_TCP_FLAGS), - .packets = ur_get(tmplt, data, F_PACKETS), - .bytes = ur_get(tmplt, data, F_BYTES), - .srcIp = ur_get(tmplt, data, F_SRC_IP), - .dstIp = ur_get(tmplt, data, F_DST_IP), - .srcPort = srcPort, - .dstPort = dstPort, - .flowFirstSeen = ur_get(tmplt, data, F_TIME_FIRST), - .flowLastSeen = ur_get(tmplt, data, F_TIME_LAST), - }; + if (dstPort != TCP_SSH_PORT && dstPort != TCP_TELNET_PORT && dstPort != TCP_RDP_PORT + && srcPort != TCP_SSH_PORT && srcPort != TCP_TELNET_PORT && srcPort != TCP_RDP_PORT) { + continue; + } + + uint8_t direction; + if (dstPort == TCP_SSH_PORT || dstPort == TCP_TELNET_PORT || dstPort == TCP_RDP_PORT) { + direction = FLOW_INCOMING_DIRECTION; + } else { + direction = FLOW_OUTGOING_DIRECTION; + } + + // Process rest of new data + IRecord::MatchStructure flow{ + .flags = ur_get(tmplt, data, F_TCP_FLAGS), + .packets = ur_get(tmplt, data, F_PACKETS), + .bytes = ur_get(tmplt, data, F_BYTES), + .srcIp = ur_get(tmplt, data, F_SRC_IP), + .dstIp = ur_get(tmplt, data, F_DST_IP), + .srcPort = srcPort, + .dstPort = dstPort, + .flowFirstSeen = ur_get(tmplt, data, F_TIME_FIRST), + .flowLastSeen = ur_get(tmplt, data, F_TIME_LAST), + }; ret = 0; // *** SSH *** - if(SSH && (dstPort == TCP_SSH_PORT || srcPort == TCP_SSH_PORT)) - { + if (SSH && (dstPort == TCP_SSH_PORT || srcPort == TCP_SSH_PORT)) { bool is_matched; bool is_portscan; SSHRecord *record; - if(direction == FLOW_INCOMING_DIRECTION) - { - record = new SSHRecord(structure.dstIp, structure.flowLastSeen); - is_matched = record->matchWithIncomingSignature(&structure, &whitelist); - if(is_matched) - { - ssh.matchedIncomingFlows++; - } + if (direction == FLOW_INCOMING_DIRECTION) { + record = new SSHRecord(flow.dstIp, flow.flowLastSeen); + is_matched = record->matchWithIncomingSignature(&flow, &whitelist); + if (is_matched) { + ssh.matchedIncomingFlows++; + } ssh.incomingFlows++; - } - else - { - // FLOW_OUTGOING_DIRECTION - record = new SSHRecord(structure.srcIp, structure.flowLastSeen); - is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); - if(is_matched) - { - ssh.matchedOutgoingFlows++; - } + } else { + // FLOW_OUTGOING_DIRECTION + record = new SSHRecord(flow.srcIp, flow.flowLastSeen); + is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); + if (is_matched) { + ssh.matchedOutgoingFlows++; + } ssh.outgoingFlows++; } - if(is_matched) - { - ssh.matchedFlows++; - } + if (is_matched) { + ssh.matchedFlows++; + } ssh.flows++; // host is the source of current flow/connection - SSHHost *host = sshHostMap.findHost(&structure, direction); - - is_portscan = !host->addRecord(record, &structure, direction); - - if(is_portscan) - { - delete record; - } - else - { - // check for attack - auto attackState = host->checkForAttack(structure.flowLastSeen); - - if(attackState != SSHHost::NO_ATTACK) - { - if(attackState == SSHHost::REPORT_NEW_ATTACK) - { - ret = sender->firstReport(host, TCP_SSH_PORT, structure.flowLastSeen, Config::getInstance().getSSHListThreshold()); - } - else if(attackState == SSHHost::ATTACK_REPORT_WAIT || attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) - { + SSHHost *host = sshHostMap.findHost(&flow, direction); + + is_portscan = !host->addRecord(record, &flow, direction); + + if (is_portscan) { + delete record; + } else { + // check for attack + auto attackState = host->checkForAttack(flow.flowLastSeen); + + if (attackState != SSHHost::NO_ATTACK) { + if (attackState == SSHHost::REPORT_NEW_ATTACK) { + ret = sender->firstReport(host, TCP_SSH_PORT, flow.flowLastSeen, + Config::getInstance().getSSHListThreshold()); + } else if (attackState == SSHHost::ATTACK_REPORT_WAIT || + attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } - else if(attackState == SSHHost::END_OF_ATTACK) - { + } else if (attackState == SSHHost::END_OF_ATTACK) { // clear list host->clearAllRecords(); host->setNotReported(); - } - else if(attackState == SSHHost::REPORT_END_OF_ATTACK) - { + } else if (attackState == SSHHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_SSH_PORT, structure.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_SSH_PORT, flow.flowLastSeen, true); host->clearAllRecords(); host->setNotReported(); - } - else if(attackState == SSHHost::REPORT_ATTACK) - { - ret = sender->continuingReport(host, TCP_SSH_PORT, structure.flowLastSeen); + } else if (attackState == SSHHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_SSH_PORT, flow.flowLastSeen); } } } } // *** RDP *** - if(RDP && (dstPort == TCP_RDP_PORT || srcPort == TCP_RDP_PORT)) - { + if (RDP && (dstPort == TCP_RDP_PORT || srcPort == TCP_RDP_PORT)) { bool is_matched; bool is_portscan; RDPRecord *record; - if(direction == FLOW_INCOMING_DIRECTION) - { - record = new RDPRecord(structure.dstIp, structure.flowLastSeen); - is_matched = record->matchWithIncomingSignature(&structure, &whitelist); - if(is_matched) - { - rdp.matchedIncomingFlows++; - } + if (direction == FLOW_INCOMING_DIRECTION) { + record = new RDPRecord(flow.dstIp, flow.flowLastSeen); + is_matched = record->matchWithIncomingSignature(&flow, &whitelist); + if (is_matched) { + rdp.matchedIncomingFlows++; + } rdp.incomingFlows++; - } - else - { - // FLOW_OUTGOING_DIRECTION - record = new RDPRecord(structure.srcIp, structure.flowLastSeen); - is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); - if(is_matched) - { - rdp.matchedOutgoingFlows++; - } + } else { + // FLOW_OUTGOING_DIRECTION + record = new RDPRecord(flow.srcIp, flow.flowLastSeen); + is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); + if (is_matched) { + rdp.matchedOutgoingFlows++; + } rdp.outgoingFlows++; } - if(is_matched) - { - rdp.matchedFlows++; - } + if (is_matched) { + rdp.matchedFlows++; + } rdp.flows++; - RDPHost *host = rdpHostMap.findHost(&structure, direction); - - is_portscan = !host->addRecord(record, &structure, direction); - if(is_portscan) - { - delete record; - } - else - { - // check for attack - RDPHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); - if(attackState != RDPHost::NO_ATTACK) - { - if(attackState == RDPHost::REPORT_NEW_ATTACK) - { - ret = sender->firstReport(host, TCP_RDP_PORT, structure.flowLastSeen, Config::getInstance().getRDPListThreshold()); - } - else if(attackState == RDPHost::ATTACK_REPORT_WAIT || attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) - { + RDPHost *host = rdpHostMap.findHost(&flow, direction); + + is_portscan = !host->addRecord(record, &flow, direction); + if (is_portscan) { + delete record; + } else { + // check for attack + RDPHost::ATTACK_STATE attackState = host->checkForAttack(flow.flowLastSeen); + if (attackState != RDPHost::NO_ATTACK) { + if (attackState == RDPHost::REPORT_NEW_ATTACK) { + ret = sender->firstReport(host, TCP_RDP_PORT, flow.flowLastSeen, + Config::getInstance().getRDPListThreshold()); + } else if (attackState == RDPHost::ATTACK_REPORT_WAIT || + attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } - else if(attackState == RDPHost::END_OF_ATTACK) - { + } else if (attackState == RDPHost::END_OF_ATTACK) { host->clearAllRecords(); host->setNotReported(); - } - else if(attackState == RDPHost::REPORT_END_OF_ATTACK) - { + } else if (attackState == RDPHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_RDP_PORT, structure.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_RDP_PORT, flow.flowLastSeen, true); host->clearAllRecords(); host->setNotReported(); - } - else if(attackState == RDPHost::REPORT_ATTACK) - { - ret = sender->continuingReport(host, TCP_RDP_PORT, structure.flowLastSeen); + } else if (attackState == RDPHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_RDP_PORT, flow.flowLastSeen); } } } } // *** TELNET *** - if(TELNET && (dstPort == TCP_TELNET_PORT || srcPort == TCP_TELNET_PORT)) - { + if (TELNET && (dstPort == TCP_TELNET_PORT || srcPort == TCP_TELNET_PORT)) { bool is_matched; bool is_portscan; TELNETRecord *record; - if(direction == FLOW_INCOMING_DIRECTION) - { - record = new TELNETRecord(structure.dstIp, structure.flowLastSeen); - is_matched = record->matchWithIncomingSignature(&structure, &whitelist); - if(is_matched) - { - telnet.matchedIncomingFlows++; - } + if (direction == FLOW_INCOMING_DIRECTION) { + record = new TELNETRecord(flow.dstIp, flow.flowLastSeen); + is_matched = record->matchWithIncomingSignature(&flow, &whitelist); + if (is_matched) { + telnet.matchedIncomingFlows++; + } telnet.incomingFlows++; - } - else - { - // FLOW_OUTGOING_DIRECTION - record = new TELNETRecord(structure.srcIp, structure.flowLastSeen); - is_matched = record->matchWithOutgoingSignature(&structure, &whitelist); - if(is_matched) - { - telnet.matchedOutgoingFlows++; - } + } else { + // FLOW_OUTGOING_DIRECTION + record = new TELNETRecord(flow.srcIp, flow.flowLastSeen); + is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); + if (is_matched) { + telnet.matchedOutgoingFlows++; + } telnet.outgoingFlows++; } - if(is_matched) - { - telnet.matchedFlows++; - } + if (is_matched) { + telnet.matchedFlows++; + } telnet.flows++; - TELNETHost *host = telnetHostMap.findHost(&structure, direction); - - is_portscan = !host->addRecord(record, &structure, direction); - if(is_portscan) - { - delete record; - } - else - { - // check for attack - TELNETHost::ATTACK_STATE attackState = host->checkForAttack(structure.flowLastSeen); - if(attackState != TELNETHost::NO_ATTACK) - { - if(attackState == TELNETHost::REPORT_NEW_ATTACK) - { - ret = sender->firstReport(host, TCP_TELNET_PORT, structure.flowLastSeen, Config::getInstance().getTELNETListThreshold()); - } - else if(attackState == TELNETHost::ATTACK_REPORT_WAIT || attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) - { + TELNETHost *host = telnetHostMap.findHost(&flow, direction); + + is_portscan = !host->addRecord(record, &flow, direction); + if (is_portscan) { + delete record; + } else { + // check for attack + TELNETHost::ATTACK_STATE attackState = host->checkForAttack(flow.flowLastSeen); + if (attackState != TELNETHost::NO_ATTACK) { + if (attackState == TELNETHost::REPORT_NEW_ATTACK) { + ret = sender->firstReport(host, TCP_TELNET_PORT, flow.flowLastSeen, + Config::getInstance().getTELNETListThreshold()); + } else if (attackState == TELNETHost::ATTACK_REPORT_WAIT || + attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } - else if(attackState == TELNETHost::END_OF_ATTACK) - { + } else if (attackState == TELNETHost::END_OF_ATTACK) { host->clearAllRecords(); host->setNotReported(); - } - else if(attackState == TELNETHost::REPORT_END_OF_ATTACK) - { + } else if (attackState == TELNETHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_TELNET_PORT, structure.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.flowLastSeen, true); host->clearAllRecords(); host->setNotReported(); - } - else if(attackState == TELNETHost::REPORT_ATTACK) - { - ret = sender->continuingReport(host, TCP_TELNET_PORT, structure.flowLastSeen); + } else if (attackState == TELNETHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.flowLastSeen); } } } } - if(checkForTimeout(timeOfLastReportCheck, timerForReportCheck, structure.flowLastSeen)) - { - timeOfLastReportCheck = structure.flowLastSeen; - - if(SSH) - { - sshHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); - } - if(RDP) - { - rdpHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); - } - if(TELNET) - { - telnetHostMap.checkForAttackTimeout(structure.flowLastSeen, sender); - } + if (checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flow.flowLastSeen)) { + timeOfLastReportCheck = flow.flowLastSeen; + + if (SSH) { + sshHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + } + if (RDP) { + rdpHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + } + if (TELNET) { + telnetHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + } } - if(checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, structure.flowLastSeen)) - { - timeOfLastDeleteCheck = structure.flowLastSeen; - - if(SSH) - { - sshHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); - } - if(RDP) - { - rdpHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); - } - if(TELNET) - { - telnetHostMap.deleteOldRecordAndHosts(structure.flowLastSeen); - } + if (checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, flow.flowLastSeen)) { + timeOfLastDeleteCheck = flow.flowLastSeen; + + if (SSH) { + sshHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + } + if (RDP) { + rdpHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + } + if (TELNET) { + telnetHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + } } - // post-send state check - TRAP_DEFAULT_SEND_ERROR_HANDLING(ret, continue, break); + // post-send state check + TRAP_DEFAULT_SEND_ERROR_HANDLING(ret, continue, break); } // ***** End of main processing loop ***** // TODO how to pass Host Map base class to printLogInfo - if(SSH) - { - ssh.printLogInfo(); - std::cout << " Host Map Size: " << sshHostMap.size() << std::endl; - sshHostMap.clear(); + if (SSH) { + ssh.printLogInfo(); + std::cout << " Host Map Size: " << sshHostMap.size() << std::endl; + sshHostMap.clear(); } - if(RDP) - { - rdp.printLogInfo(); - std::cout << " Host Map Size: " << rdpHostMap.size() << std::endl; - rdpHostMap.clear(); + if (RDP) { + rdp.printLogInfo(); + std::cout << " Host Map Size: " << rdpHostMap.size() << std::endl; + rdpHostMap.clear(); } - if(TELNET) - { - telnet.printLogInfo(); - std::cout << " Host Map Size: " << telnetHostMap.size() << std::endl; - telnetHostMap.clear(); + if (TELNET) { + telnet.printLogInfo(); + std::cout << " Host Map Size: " << telnetHostMap.size() << std::endl; + telnetHostMap.clear(); } - TRAP_DEFAULT_FINALIZATION(); + TRAP_DEFAULT_FINALIZATION(); ur_free_template(tmplt); ur_finalize(); delete sender; // free output template diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index 588b82c0..65769491 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -46,28 +46,22 @@ using namespace std; -Config::Config() -{ +Config::Config() { //init default config variables GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(60, 0); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(60, 0); - GENERAL_MATCHED_FLOW_RATIO = 0.9; - GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10; - GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0; - GENERAL_IGNORE_FIRST_SEND = 0; - //SSH SSH_LIST_SIZE = 1000; - SSH_LIST_SIZE_BOTTOM_THRESHOLD = 100; // There are two types of thresholds, first means how many records are in list [50/1000] - // and based on this value is set up THRESHOLD which detects if host is attacker or not SSH_LIST_THRESHOLD = 90; + SSH_MATCHED_FLOW_RATIO = 0.9; + SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); - SSH_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); + SSH_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); SSH_BRUTEFORCE_INC_MIN_PACKETS = 11; SSH_BRUTEFORCE_INC_MAX_PACKETS = 30; @@ -84,10 +78,11 @@ Config::Config() //RDP RDP_LIST_SIZE = 1000; - RDP_LIST_SIZE_BOTTOM_THRESHOLD = 100; RDP_LIST_THRESHOLD = 90; + RDP_MATCHED_FLOW_RATIO = 0.9; + RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); - RDP_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); + RDP_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); RDP_BRUTEFORCE_INC_MIN_PACKETS = 20; RDP_BRUTEFORCE_INC_MAX_PACKETS = 100; @@ -105,10 +100,11 @@ Config::Config() //TELNET TELNET_LIST_SIZE = 1000; - TELNET_LIST_SIZE_BOTTOM_THRESHOLD = 100; TELNET_LIST_THRESHOLD = 90; + TELNET_MATCHED_FLOW_RATIO = 0.9; + TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); - TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); + TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9; TELNET_BRUTEFORCE_INC_MAX_PACKETS = 50; @@ -118,118 +114,109 @@ Config::Config() TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(300, 0); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(600, 0); - //init keywords + //init keywords kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT = "GENERAL_CHECK_FOR_REPORT_TIMEOUT"; kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT = "GENERAL_CHECK_FOR_DELETE_TIMEOUT"; kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = "GENERAL_ATTACK_MIN_EVENTS_TO_REPORT"; kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = "GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST"; kw_GENERAL_IGNORE_FIRST_SEND = "GENERAL_IGNORE_FIRST_SEND"; - kw_GENERAL_MATCHED_FLOW_RATIO = "GENERAL_MATCHED_FLOW_RATIO"; + kw_GENERAL_MATCHED_FLOW_RATIO = "GENERAL_MATCHED_FLOW_RATIO"; //SSH - kw_SSH_LIST_SIZE = "SSH_LIST_SIZE"; + kw_SSH_LIST_SIZE = "SSH_LIST_SIZE"; kw_SSH_LIST_THRESHOLD = "SSH_LIST_THRESHOLD"; - kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD = "SSH_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD = "SSH_LIST_SIZE_BOTTOM_THRESHOLD"; kw_SSH_RECORD_TIMEOUT = "SSH_RECORD_TIMEOUT"; - kw_SSH_HOST_TIMEOUT = "SSH_HOST_TIMEOUT"; + kw_SSH_HOST_TIMEOUT = "SSH_HOST_TIMEOUT"; kw_SSH_REPORT_TIMEOUT = "SSH_REPORT_TIMEOUT"; kw_SSH_ATTACK_TIMEOUT = "SSH_ATTACK_TIMEOUT"; kw_SSH_BRUTEFORCE_INC_MIN_PACKETS = "SSH_BRUTEFORCE_INC_MIN_PACKETS"; kw_SSH_BRUTEFORCE_INC_MAX_PACKETS = "SSH_BRUTEFORCE_INC_MAX_PACKETS"; - kw_SSH_BRUTEFORCE_INC_MIN_BYTES = "SSH_BRUTEFORCE_INC_MIN_BYTES"; - kw_SSH_BRUTEFORCE_INC_MAX_BYTES = "SSH_BRUTEFORCE_INC_MAX_BYTES"; + kw_SSH_BRUTEFORCE_INC_MIN_BYTES = "SSH_BRUTEFORCE_INC_MIN_BYTES"; + kw_SSH_BRUTEFORCE_INC_MAX_BYTES = "SSH_BRUTEFORCE_INC_MAX_BYTES"; kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS = "SSH_BRUTEFORCE_OUT_MIN_PACKETS"; kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS = "SSH_BRUTEFORCE_OUT_MAX_PACKETS"; - kw_SSH_BRUTEFORCE_OUT_MIN_BYTES = "SSH_BRUTEFORCE_OUT_MIN_BYTES"; - kw_SSH_BRUTEFORCE_OUT_MAX_BYTES = "SSH_BRUTEFORCE_OUT_MAX_BYTES"; + kw_SSH_BRUTEFORCE_OUT_MIN_BYTES = "SSH_BRUTEFORCE_OUT_MIN_BYTES"; + kw_SSH_BRUTEFORCE_OUT_MAX_BYTES = "SSH_BRUTEFORCE_OUT_MAX_BYTES"; //RDP - kw_RDP_LIST_SIZE = "RDP_LIST_SIZE"; + kw_RDP_LIST_SIZE = "RDP_LIST_SIZE"; kw_RDP_LIST_THRESHOLD = "RDP_LIST_THRESHOLD"; - kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD = "RDP_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD = "RDP_LIST_SIZE_BOTTOM_THRESHOLD"; - kw_RDP_RECORD_TIMEOUT = "RDP_RECORD_TIMEOUT"; - kw_RDP_HOST_TIMEOUT = "RDP_HOST_TIMEOUT"; + kw_RDP_RECORD_TIMEOUT = "RDP_RECORD_TIMEOUT"; + kw_RDP_HOST_TIMEOUT = "RDP_HOST_TIMEOUT"; kw_RDP_REPORT_TIMEOUT = "RDP_REPORT_TIMEOUT"; kw_RDP_ATTACK_TIMEOUT = "RDP_ATTACK_TIMEOUT"; kw_RDP_BRUTEFORCE_INC_MIN_PACKETS = "RDP_BRUTEFORCE_INC_MIN_PACKETS"; kw_RDP_BRUTEFORCE_INC_MAX_PACKETS = "RDP_BRUTEFORCE_INC_MAX_PACKETS"; - kw_RDP_BRUTEFORCE_INC_MIN_BYTES = "RDP_BRUTEFORCE_INC_MIN_BYTES"; - kw_RDP_BRUTEFORCE_INC_MAX_BYTES = "RDP_BRUTEFORCE_INC_MAX_BYTES"; + kw_RDP_BRUTEFORCE_INC_MIN_BYTES = "RDP_BRUTEFORCE_INC_MIN_BYTES"; + kw_RDP_BRUTEFORCE_INC_MAX_BYTES = "RDP_BRUTEFORCE_INC_MAX_BYTES"; kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS = "RDP_BRUTEFORCE_OUT_MIN_PACKETS"; kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS = "RDP_BRUTEFORCE_OUT_MAX_PACKETS"; - kw_RDP_BRUTEFORCE_OUT_MIN_BYTES = "RDP_BRUTEFORCE_OUT_MIN_BYTES"; - kw_RDP_BRUTEFORCE_OUT_MAX_BYTES = "RDP_BRUTEFORCE_OUT_MAX_BYTES"; + kw_RDP_BRUTEFORCE_OUT_MIN_BYTES = "RDP_BRUTEFORCE_OUT_MIN_BYTES"; + kw_RDP_BRUTEFORCE_OUT_MAX_BYTES = "RDP_BRUTEFORCE_OUT_MAX_BYTES"; //TELNET - kw_TELNET_LIST_SIZE = "TELNET_LIST_SIZE"; + kw_TELNET_LIST_SIZE = "TELNET_LIST_SIZE"; kw_TELNET_LIST_THRESHOLD = "TELNET_LIST_THRESHOLD"; - kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD = "TELNET_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD = "TELNET_LIST_SIZE_BOTTOM_THRESHOLD"; - kw_TELNET_RECORD_TIMEOUT = "TELNET_RECORD_TIMEOUT"; - kw_TELNET_HOST_TIMEOUT = "TELNET_HOST_TIMEOUT"; + kw_TELNET_RECORD_TIMEOUT = "TELNET_RECORD_TIMEOUT"; + kw_TELNET_HOST_TIMEOUT = "TELNET_HOST_TIMEOUT"; kw_TELNET_REPORT_TIMEOUT = "TELNET_REPORT_TIMEOUT"; kw_TELNET_ATTACK_TIMEOUT = "TELNET_ATTACK_TIMEOUT"; kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS = "TELNET_BRUTEFORCE_INC_MIN_PACKETS"; kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS = "TELNET_BRUTEFORCE_INC_MAX_PACKETS"; - kw_TELNET_BRUTEFORCE_INC_MIN_BYTES = "TELNET_BRUTEFORCE_INC_MIN_BYTES"; - kw_TELNET_BRUTEFORCE_INC_MAX_BYTES = "TELNET_BRUTEFORCE_INC_MAX_BYTES"; + kw_TELNET_BRUTEFORCE_INC_MIN_BYTES = "TELNET_BRUTEFORCE_INC_MIN_BYTES"; + kw_TELNET_BRUTEFORCE_INC_MAX_BYTES = "TELNET_BRUTEFORCE_INC_MAX_BYTES"; } -void Config::reloadConfig() -{ - if(!configPath.empty()) - { - if(!initFromFile(configPath)) - { +void Config::reloadConfig() { + if (!configPath.empty()) { + if (!initFromFile(configPath)) { cerr << "Error Config: Configuration reload failed!\n"; } - else - { + else { cout << "Config: Configuration reloaded successfully.\n"; } } - else - { + else { cerr << "Error Config: Configuration path is not set!\n"; } } -bool Config::initFromFile(const string& path) -{ +bool Config::initFromFile(const string &path) { configPath = path; ifstream configFile; configFile.open(path.c_str()); - if(!configFile.is_open()) + if (!configFile.is_open()) { return false; + } //Parse file string line; string keyword, value; - while(configFile.good()) - { + while (configFile.good()) { getline(configFile, line); - if(line.empty()) - { - continue; //skip empty line - } + if (line.empty()) { + continue; //skip empty line + } - if(line[0] == '#') - { - continue; //skip comment line - } + if (line[0] == '#') { + continue; //skip comment line + } size_t pos = line.find('='); // = delimiter - if(pos == std::string::npos) - { + if (pos == std::string::npos) { cerr << "Error Config: Invalid line \"" << line << "\"" << endl; cerr.flush(); continue; //skip invalid line @@ -242,229 +229,178 @@ bool Config::initFromFile(const string& path) keyword.erase(remove_if(keyword.begin(), keyword.end(), ::isspace), keyword.end()); value.erase(remove_if(value.begin(), value.end(), ::isspace), value.end()); - // ********************* - // ****** GENERAL ****** - // ********************* - if(keyword == kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) - { + // ********************* + // ****** GENERAL ****** + // ********************* + if (keyword == kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) - { + else if (keyword == kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) - { + else if (keyword == kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) { GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = std::stoul(value, nullptr); } - else if(keyword == kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) - { + else if (keyword == kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) { GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = std::stod(value, nullptr); } - else if(keyword == kw_GENERAL_IGNORE_FIRST_SEND) - { + else if (keyword == kw_GENERAL_IGNORE_FIRST_SEND) { GENERAL_IGNORE_FIRST_SEND = std::stoul(value, nullptr); } - else if(keyword == kw_GENERAL_MATCHED_FLOW_RATIO) - { - GENERAL_MATCHED_FLOW_RATIO = std::stod(value, nullptr); - } - // ********************* - // ******* SSH ********* - // ********************* - else if(keyword == kw_SSH_LIST_SIZE) - { + // ********************* + // ******* SSH ********* + // ********************* + else if (keyword == kw_SSH_LIST_SIZE) { SSH_LIST_SIZE = std::stoul(value, nullptr); } - else if(keyword == kw_SSH_LIST_THRESHOLD) - { + else if (keyword == kw_SSH_LIST_THRESHOLD) { SSH_LIST_THRESHOLD = std::stoul(value, nullptr); } - else if(keyword == kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD) - { - SSH_LIST_SIZE_BOTTOM_THRESHOLD = std::stoul(value, nullptr); + else if (keyword == kw_SSH_MATCHED_FLOW_RATIO) { + SSH_MATCHED_FLOW_RATIO = std::stod(value, nullptr); } - else if(keyword == kw_SSH_ATTACK_TIMEOUT) - { + else if (keyword == kw_SSH_ATTACK_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_SSH_RECORD_TIMEOUT) - { + else if (keyword == kw_SSH_RECORD_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_SSH_HOST_TIMEOUT) - { + else if (keyword == kw_SSH_HOST_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_SSH_REPORT_TIMEOUT) - { + else if (keyword == kw_SSH_REPORT_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); SSH_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) - else if(keyword == kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) - { + // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) + else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) { SSH_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) - { + else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) { SSH_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_SSH_BRUTEFORCE_INC_MIN_BYTES) - { + else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_BYTES) { SSH_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); } - else if(keyword == kw_SSH_BRUTEFORCE_INC_MAX_BYTES) - { + else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_BYTES) { SSH_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); } - // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) - else if(keyword == kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) - { + // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) + else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) { SSH_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) - { + else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) { SSH_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) - { + else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) { SSH_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, nullptr); } - else if(keyword == kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) - { + else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) { SSH_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, nullptr); } - // ********************* - // ******* RDP ********* - // ********************* - else if(keyword == kw_RDP_LIST_SIZE) - { + // ********************* + // ******* RDP ********* + // ********************* + else if (keyword == kw_RDP_LIST_SIZE) { RDP_LIST_SIZE = std::stoul(value, nullptr); } - else if(keyword == kw_RDP_LIST_THRESHOLD) - { + else if (keyword == kw_RDP_LIST_THRESHOLD) { RDP_LIST_THRESHOLD = std::stoul(value, nullptr); } - else if(keyword == kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD) - { - RDP_LIST_SIZE_BOTTOM_THRESHOLD = std::stoul(value, nullptr); - } - else if(keyword == kw_RDP_ATTACK_TIMEOUT) - { + else if (keyword == kw_RDP_MATCHED_FLOW_RATIO) { + RDP_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + } + else if (keyword == kw_RDP_ATTACK_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_RDP_RECORD_TIMEOUT) - { + else if (keyword == kw_RDP_RECORD_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_RDP_HOST_TIMEOUT) - { + else if (keyword == kw_RDP_HOST_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_RDP_REPORT_TIMEOUT) - { + else if (keyword == kw_RDP_REPORT_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); RDP_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) - else if(keyword == kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) - { + // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) + else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) { RDP_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) - { + else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) { RDP_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_RDP_BRUTEFORCE_INC_MIN_BYTES) - { + else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_BYTES) { RDP_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); } - else if(keyword == kw_RDP_BRUTEFORCE_INC_MAX_BYTES) - { + else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_BYTES) { RDP_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); } - // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) - else if(keyword == kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) - { + // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) + else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) { RDP_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) - { + else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) { RDP_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) - { + else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) { RDP_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, nullptr); } - else if(keyword == kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) - { + else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) { RDP_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, nullptr); } - // ********************* - // ****** TELNET ******* - // ********************* - else if(keyword == kw_TELNET_LIST_SIZE) - { + // ********************* + // ****** TELNET ******* + // ********************* + else if (keyword == kw_TELNET_LIST_SIZE) { TELNET_LIST_SIZE = std::stoul(value, nullptr); } - else if(keyword == kw_TELNET_LIST_THRESHOLD) - { + else if (keyword == kw_TELNET_LIST_THRESHOLD) { TELNET_LIST_THRESHOLD = std::stoul(value, nullptr); } - else if(keyword == kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD) - { - TELNET_LIST_SIZE_BOTTOM_THRESHOLD = std::stoul(value, nullptr); - } - else if(keyword == kw_TELNET_ATTACK_TIMEOUT) - { + else if (keyword == kw_TELNET_MATCHED_FLOW_RATIO) { + TELNET_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + } + else if (keyword == kw_TELNET_ATTACK_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_TELNET_RECORD_TIMEOUT) - { + else if (keyword == kw_TELNET_RECORD_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_TELNET_HOST_TIMEOUT) - { + else if (keyword == kw_TELNET_HOST_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_TELNET_REPORT_TIMEOUT) - { + else if (keyword == kw_TELNET_REPORT_TIMEOUT) { uint32_t sec = std::stoul(value, nullptr); TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword == kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) - { + else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) { TELNET_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) - { + else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) { TELNET_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); } - else if(keyword == kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) - { + else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) { TELNET_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); } - else if(keyword == kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) - { + else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) { TELNET_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); } - // ********************* - // ******* UNKNOWN ***** - // ********************* - else - { + // ********************* + // ******* UNKNOWN ***** + // ********************* + else { cerr << "Error Config: Unknown keyword " << keyword << endl; cerr.flush(); } diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index 4ec8b811..7a76ee8b 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -62,15 +62,13 @@ class Config { inline ur_time_t getGlobalTimerForDeleteCheck() const {return GENERAL_CHECK_FOR_DELETE_TIMEOUT;} inline ur_time_t getGlobalAttackMinEvToReport() const {return GENERAL_ATTACK_MIN_EVENTS_TO_REPORT;} inline double getGlobalAttackMinRatioToKeepTrackingHost() const {return GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST;} - inline int getGlobalIgnoreFirstSend() const {return GENERAL_IGNORE_FIRST_SEND;} - inline double getGlobalMatchedFlowRatio() const {return GENERAL_MATCHED_FLOW_RATIO;} //SSH inline uint16_t getSSHMaxListSize() const {return SSH_LIST_SIZE;} - inline uint16_t getSSHListBottomSize() const {return SSH_LIST_SIZE_BOTTOM_THRESHOLD;} - inline uint16_t getSSHListThreshold() const {return SSH_LIST_THRESHOLD;} + inline double getSSHMatchedFlowRatio() const {return SSH_MATCHED_FLOW_RATIO;} + inline ur_time_t getSSHRecordTimeout() const {return SSH_RECORD_TIMEOUT;} inline ur_time_t getSSHHostDeleteTimeout() const {return SSH_HOST_TIMEOUT;} inline ur_time_t getSSHReportTimeout() const {return SSH_REPORT_TIMEOUT;} @@ -89,9 +87,10 @@ class Config { inline uint16_t getSSHOutMaxBytes() const {return SSH_BRUTEFORCE_OUT_MAX_BYTES;} //RDP - inline uint16_t getRDPListBottomSize() const {return RDP_LIST_SIZE_BOTTOM_THRESHOLD;} inline uint16_t getRDPMaxListSize() const {return RDP_LIST_SIZE;} inline uint16_t getRDPListThreshold() const {return RDP_LIST_THRESHOLD;} + inline double getRDPMatchedFlowRatio() const {return RDP_MATCHED_FLOW_RATIO;} + inline ur_time_t getRDPRecordTimeout() const {return RDP_RECORD_TIMEOUT;} inline ur_time_t getRDPHostDeleteTimeout() const {return RDP_HOST_TIMEOUT;} inline ur_time_t getRDPReportTimeout() const {return RDP_REPORT_TIMEOUT;} @@ -110,9 +109,10 @@ class Config { inline uint32_t getRDPOutMaxBytes() const {return RDP_BRUTEFORCE_OUT_MAX_BYTES;} //TELNET - inline uint16_t getTELNETListBottomSize() const {return TELNET_LIST_SIZE_BOTTOM_THRESHOLD;} inline uint16_t getTELNETMaxListSize() const {return TELNET_LIST_SIZE;} inline uint16_t getTELNETListThreshold() const {return TELNET_LIST_THRESHOLD;} + inline double getTELNETMatchedFlowRatio() const {return TELNET_MATCHED_FLOW_RATIO;} + inline ur_time_t getTELNETRecordTimeout() const {return TELNET_RECORD_TIMEOUT;} inline ur_time_t getTELNETHostDeleteTimeout()const {return TELNET_HOST_TIMEOUT;} inline ur_time_t getTELNETReportTimeout() const {return TELNET_REPORT_TIMEOUT;} @@ -143,7 +143,7 @@ class Config { uint16_t GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; double GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; uint8_t GENERAL_IGNORE_FIRST_SEND; - double GENERAL_MATCHED_FLOW_RATIO; + // double GENERAL_MATCHED_FLOW_RATIO; std::string kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT; std::string kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT; @@ -158,8 +158,10 @@ class Config { uint16_t SSH_LIST_SIZE; uint16_t SSH_LIST_THRESHOLD; uint16_t SSH_LIST_SIZE_BOTTOM_THRESHOLD; + double SSH_MATCHED_FLOW_RATIO; - ur_time_t SSH_RECORD_TIMEOUT; + + ur_time_t SSH_RECORD_TIMEOUT; ur_time_t SSH_HOST_TIMEOUT; ur_time_t SSH_REPORT_TIMEOUT; ur_time_t SSH_ATTACK_TIMEOUT; @@ -178,6 +180,7 @@ class Config { std::string kw_SSH_LIST_SIZE; std::string kw_SSH_LIST_THRESHOLD; std::string kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD; + std::string kw_SSH_MATCHED_FLOW_RATIO; std::string kw_SSH_RECORD_TIMEOUT; std::string kw_SSH_HOST_TIMEOUT; std::string kw_SSH_BRUTEFORCE_INC_MIN_PACKETS; @@ -196,7 +199,9 @@ class Config { uint16_t RDP_LIST_SIZE; uint16_t RDP_LIST_SIZE_BOTTOM_THRESHOLD; uint16_t RDP_LIST_THRESHOLD; - ur_time_t RDP_RECORD_TIMEOUT; + double RDP_MATCHED_FLOW_RATIO; + + ur_time_t RDP_RECORD_TIMEOUT; ur_time_t RDP_HOST_TIMEOUT; ur_time_t RDP_REPORT_TIMEOUT; ur_time_t RDP_ATTACK_TIMEOUT; @@ -215,6 +220,7 @@ class Config { std::string kw_RDP_LIST_SIZE; std::string kw_RDP_LIST_THRESHOLD; std::string kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD; + std::string kw_RDP_MATCHED_FLOW_RATIO; std::string kw_RDP_RECORD_TIMEOUT; std::string kw_RDP_HOST_TIMEOUT; std::string kw_RDP_BRUTEFORCE_INC_MIN_PACKETS; @@ -231,8 +237,10 @@ class Config { //TELNET uint16_t TELNET_LIST_SIZE; - uint16_t TELNET_LIST_SIZE_BOTTOM_THRESHOLD; uint16_t TELNET_LIST_THRESHOLD; + uint16_t TELNET_LIST_SIZE_BOTTOM_THRESHOLD; + double TELNET_MATCHED_FLOW_RATIO; + ur_time_t TELNET_RECORD_TIMEOUT; ur_time_t TELNET_HOST_TIMEOUT; ur_time_t TELNET_REPORT_TIMEOUT; @@ -247,6 +255,7 @@ class Config { std::string kw_TELNET_LIST_SIZE; std::string kw_TELNET_LIST_THRESHOLD; std::string kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD; + std::string kw_TELNET_MATCHED_FLOW_RATIO; std::string kw_TELNET_RECORD_TIMEOUT; std::string kw_TELNET_HOST_TIMEOUT; diff --git a/brute_force_detector/config/config.conf b/brute_force_detector/config/config.conf index 6aa50f44..f26e45e3 100644 --- a/brute_force_detector/config/config.conf +++ b/brute_force_detector/config/config.conf @@ -14,11 +14,11 @@ ## Every n seconds check all Hosts/Records for host/record timeout # GENERAL_CHECK_FOR_DELETE_TIMEOUT = 60 ## -## Minimum number of suspicious flows to report (continuous detection [not first detection]) +## Minimum number of matched flows to report (continuous detection [not first detection]) ## Lower value can report more slow attacks # GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10 ## -## Percentage threshold between suspicious and benign flows to keep track host +## Percentage threshold of matched/total flows to keep track host ## If below threshold and after protocol_REPORT_TIMEOUT report end of attack # GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0 ## @@ -27,15 +27,16 @@ ## "GENERAL_ATTACK_MIN_EVENTS_TO_REPORT". This option may decrease number of the ## false positive detections. 0/1 = false/true # GENERAL_IGNORE_FIRST_SEND = 0 -## -## How much of the flow has to be suspicious to report an attack (sensitivity) -## In the range of (0;1]. (0 would mean everything is considered an attack) -# GENERAL_MATCHED_FLOW_RATIO = 0.9 ####################################### ## PROTOCOL (X) KEYWORDS INFORMATION ## ## X -> SSH/RDP/TELNET ## +## +## X_MATCHED_FLOW_RATIO = 0.9 +## How much of the flow has to be matched(suspicious) to report an attack (sensitivity) +## In the range of (0;1]. (0 would mean everything is considered an attack) +## ## X_ATTACK_TIMEOUT - After n seconds from last report set attack by given host ## as finished ## X_LIST_SIZE - Set number of max records(flows) that each host can store @@ -67,7 +68,7 @@ #SSH_ATTACK_TIMEOUT = 600 #SSH_LIST_SIZE = 100 #SSH_LIST_THRESHOLD = 90 -#SSH_LIST_SIZE_BOTTOM_THRESHOLD = 100 +#SSH_MATCHED_FLOW_RATIO = 0.9 #SSH_RECORD_TIMEOUT = 1800 #SSH_HOST_TIMEOUT = 4200 #SSH_BRUTEFORCE_INC_MIN_PACKETS = 11 @@ -85,7 +86,7 @@ #RDP_ATTACK_TIMEOUT = 600 #RDP_LIST_SIZE = 500 #RDP_LIST_THRESHOLD = 90 -#RDP_LIST_SIZE_BOTTOM_THRESHOLD = 100 +#RDP_MATCHED_FLOW_RATIO = 0.9 #RDP_RECORD_TIMEOUT = 1800 #RDP_HOST_TIMEOUT = 4200 #RDP_BRUTEFORCE_INC_MIN_PACKETS = 20 @@ -102,13 +103,13 @@ ######################## #TELNET_LIST_SIZE = 100 #TELNET_LIST_THRESHOLD = 90 -#TELNET_LIST_SIZE_BOTTOM_THRESHOLD = 100 +#TELNET_MATCHED_FLOW_RATIO = 0.9 #TELNET_RECORD_TIMEOUT = 1800 #TELNET_HOST_TIMEOUT = 4200 #TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9 #TELNET_BRUTEFORCE_INC_MAX_PACKETS = 50 #TELNET_BRUTEFORCE_INC_MIN_BYTES = 450 #TELNET_BRUTEFORCE_INC_MAX_BYTES = 3000 -## Outgoing version is not supported +## Outgoing direction is not supported #TELNET_ATTACK_TIMEOUT = 600 #TELNET_REPORT_TIMEOUT = 300 diff --git a/brute_force_detector/config/whitelist.wl b/brute_force_detector/config/whitelist.wl index 69941148..cb1626eb 100644 --- a/brute_force_detector/config/whitelist.wl +++ b/brute_force_detector/config/whitelist.wl @@ -17,8 +17,8 @@ dst 192.30.252.128/30/22 #github dst 131.103.20.160/28/22 #bitbucket src 166.88.20.3/32 # EGIHosting (USA) ?, valid communication to 195.113.184.18, -src 195.113.44.19/32 # Charles University, valid(???) communication to 88.208.125.10 & 88.208.125.11, -# TODO Delete/solve unknown addresses +src 195.113.44.19/32 # Charles University (CZ), valid(???) communication to 88.208.125.10 & 88.208.125.11, + diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index c252df0b..1657317e 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -47,132 +47,95 @@ // ************************************************************/ // ************************* SSH HOST *************************/ // ************************************************************/ -bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*) (structure); - - // ignore port-scans - if(isFlowScan(&st.packets, &st.flags)) - { - return false; - } - else if(st.packets == 1 && st.flags == 0b00010000) // skip ack only packet - { - return false; - } - else if(st.packets == 4 && st.flags == 0b00000010) // 4 packet SYN request - { - return false; - } - else +bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); + + // ignore port-scans + if (isFlowScan(&st.packets, &st.flags)) { + return false; + } else if (st.packets == 1 && st.flags == 0b00010000) // skip ack only packet { + return false; + } else if (st.packets == 4 && st.flags == 0b00000010) // 4 packet SYN request + { + return false; + } else { timeOfLastReceivedRecord = st.flowLastSeen; - if(direction == FLOW_INCOMING_DIRECTION) - { - recordListIncoming.addRecord(record, isReported()); - } - else - { - recordListOutgoing.addRecord(record, isReported()); - } - - return true; + if (direction == FLOW_INCOMING_DIRECTION) { + recordListIncoming.addRecord(record, isReported()); + } else { + recordListOutgoing.addRecord(record, isReported()); + } + + return true; } } -SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) -{ +SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); - if(!isReported()) - { - // no attack yet + if (!isReported()) { + // no attack yet uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - // Number of records in list is lower than BottomSize (50 by default) - if (std::max(incomingListSize, outgoingListSize) <= Config::getInstance().getSSHListBottomSize()) - { - if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold()) - { - // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return SSHHost::REPORT_NEW_ATTACK; - } - else - { - return SSHHost::NO_ATTACK; - } - } - else - { - // Number of records is between bottom size and max list size per protocol - - double topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); - - if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) - { - // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return SSHHost::REPORT_NEW_ATTACK; - } - else - { - return SSHHost::NO_ATTACK; - } + double incomingMatchedRatio = (incomingListSize == 0 ? 0 : (double) incomingMatched / incomingListSize); + double outgoingMatchedRatio = (outgoingListSize == 0 ? 0 : (double) outgoingMatched / outgoingListSize); + + double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); + + // is flow count over a minimum threshold and is a big enough part of it matched? + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold() && + (topMatchedRatio >= Config::getInstance().getSSHMatchedFlowRatio())) { + // crossed threshold, new attack detected + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); + return SSHHost::REPORT_NEW_ATTACK; + } else { + return SSHHost::NO_ATTACK; } - } - else // isReported + } else // isReported { - // host is attacking, wait for timeout to report again - if(!canReportAgain(actualTime)) - { - return SSHHost::ATTACK_REPORT_WAIT; - } - else - { + // host is attacking, wait for timeout to report again + if (!canReportAgain(actualTime)) { + return SSHHost::ATTACK_REPORT_WAIT; + } else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); - uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); - - uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); - - if(incomingMatched == 0 && incomingMatchedNew == 0 && - outgoingMatched == 0 && outgoingMatchedNew == 0) - { - return SSHHost::END_OF_ATTACK; - } - - auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - - // avoids div by zero - auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); - auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); - - if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) - { - if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) - { - return SSHHost::REPORT_END_OF_ATTACK; - } - else - { - return SSHHost::END_OF_ATTACK; - } + uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); + + uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); + uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); + + if (incomingMatched == 0 && incomingMatchedNew == 0 && + outgoingMatched == 0 && outgoingMatchedNew == 0) { + return SSHHost::END_OF_ATTACK; + } + + double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + + // avoids div by zero + double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double) incomingMatchedNew / + incomingTotalNew); + double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double) outgoingMatchedNew / + outgoingTotalNew); + + if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return SSHHost::REPORT_END_OF_ATTACK; + } else { + return SSHHost::END_OF_ATTACK; + } } - if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) - { - return SSHHost::REPORT_ATTACK; - } - else - { - return SSHHost::ATTACK_MIN_EVENTS_WAIT; - } + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return SSHHost::REPORT_ATTACK; + } else { + return SSHHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -180,122 +143,87 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) // ************************************************************/ // ************************* RDP HOST *************************/ // ************************************************************/ -bool RDPHost::addRecord(RDPRecord *record, void *structure, uint8_t direction) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*) (structure); +bool RDPHost::addRecord(RDPRecord *record, void *structure, uint8_t direction) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); // ignore port-scans - if(isFlowScan(&st.packets, &st.flags)) - { - return false; - } - else - { + if (isFlowScan(&st.packets, &st.flags)) { + return false; + } else { timeOfLastReceivedRecord = st.flowLastSeen; - if(direction == FLOW_INCOMING_DIRECTION) - { - recordListIncoming.addRecord(record, isReported()); - } - else - { - recordListOutgoing.addRecord(record, isReported()); - } + if (direction == FLOW_INCOMING_DIRECTION) { + recordListIncoming.addRecord(record, isReported()); + } else { + recordListOutgoing.addRecord(record, isReported()); + } return true; } } -RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) -{ +RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); - if(!isReported()) - { - // no attack yet + if (!isReported()) { + // no attack yet uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - if (std::max(incomingListSize, outgoingListSize) <= Config::getInstance().getRDPListBottomSize()) - { + double incomingMatchedRatio = (incomingListSize == 0 ? 0 : (double) incomingMatched / incomingListSize); + double outgoingMatchedRatio = (outgoingListSize == 0 ? 0 : (double) outgoingMatched / outgoingListSize); + double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); - if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold()) - { - // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return RDPHost::REPORT_NEW_ATTACK; - } - else - { - return RDPHost::NO_ATTACK; - } - } - else - { - // Number of records is between bottom size and max size - - auto topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); - - if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) - { - // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return RDPHost::REPORT_NEW_ATTACK; - } - else - { - return RDPHost::NO_ATTACK; - } + // is flow count over a minimum threshold and is a big enough part of it matched? + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold() && + (topMatchedRatio >= Config::getInstance().getRDPMatchedFlowRatio())) { + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); + + return RDPHost::REPORT_NEW_ATTACK; + } else { + return RDPHost::NO_ATTACK; } - } - else // isReported + + } else // isReported { - // host is attacking, wait for timeout to report again - if(!canReportAgain(actualTime)) - { - return RDPHost::ATTACK_REPORT_WAIT; - } - else - { + // host is attacking, wait for timeout to report again + if (!canReportAgain(actualTime)) { + return RDPHost::ATTACK_REPORT_WAIT; + } else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); - uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); + uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); + uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); - if(incomingMatched == 0 && incomingMatchedNew == 0 && - outgoingMatched == 0 && outgoingMatchedNew == 0) - { - return RDPHost::END_OF_ATTACK; - } + if (incomingMatched == 0 && incomingMatchedNew == 0 && + outgoingMatched == 0 && outgoingMatchedNew == 0) { + return RDPHost::END_OF_ATTACK; + } - auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); // avoids div by zero - auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); - auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); - - if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) - { - if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) - { - return RDPHost::REPORT_END_OF_ATTACK; - } - else - { - return RDPHost::END_OF_ATTACK; - } + double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double) incomingMatchedNew / + incomingTotalNew); + double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double) outgoingMatchedNew / + outgoingTotalNew); + + if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return RDPHost::REPORT_END_OF_ATTACK; + } else { + return RDPHost::END_OF_ATTACK; + } } - if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) - { - return RDPHost::REPORT_ATTACK; - } - else - { - return RDPHost::ATTACK_MIN_EVENTS_WAIT; - } + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return RDPHost::REPORT_ATTACK; + } else { + return RDPHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -303,122 +231,84 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) // ************************************************************/ // ************************ TELNET HOST ***********************/ // ************************************************************/ -bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direction) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*) (structure); - - // ignore port-scans - if(isFlowScan(&st.packets, &st.flags)) - { - return false; - } - else - { +bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direction) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); + + // ignore port-scans + if (isFlowScan(&st.packets, &st.flags)) { + return false; + } else { timeOfLastReceivedRecord = st.flowLastSeen; - if(direction == FLOW_INCOMING_DIRECTION) - { - recordListIncoming.addRecord(record, isReported()); - } - else - { - recordListOutgoing.addRecord(record, isReported()); - } + if (direction == FLOW_INCOMING_DIRECTION) { + recordListIncoming.addRecord(record, isReported()); + } else { + recordListOutgoing.addRecord(record, isReported()); + } return true; } } -TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) -{ +TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); - if(!isReported()) - { - // no attack yet + if (!isReported()) { uint16_t incomingListSize = recordListIncoming.getActualListSize(); uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); - if (std::max(incomingListSize, outgoingListSize) <= Config::getInstance().getTELNETListBottomSize()) - { + double incomingMatchedRatio = (incomingListSize == 0 ? 0 : (double) incomingMatched / incomingListSize); + double outgoingMatchedRatio = (outgoingListSize == 0 ? 0 : (double) outgoingMatched / outgoingListSize); + double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); - if(std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold()) - { - // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return TELNETHost::REPORT_NEW_ATTACK; - } - else - { - return TELNETHost::NO_ATTACK; - } - } - else - { - // Number of records is between bottom size and max size - - auto topMatchedRatio = std::max((double)incomingMatched/incomingListSize, (double)outgoingMatched/outgoingListSize); - - if(topMatchedRatio >= Config::getInstance().getGlobalMatchedFlowRatio()) - { - // crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return TELNETHost::REPORT_NEW_ATTACK; - } - else - { - return TELNETHost::NO_ATTACK; - } + // is flow count over a minimum threshold and is a big enough part of it matched? + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold() && + (topMatchedRatio >= Config::getInstance().getTELNETMatchedFlowRatio())) { + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); + + return TELNETHost::REPORT_NEW_ATTACK; + } else { + return TELNETHost::NO_ATTACK; } - } - else // isReported + } else // isReported { - // host is attacking, wait for timeout to report again - if(!canReportAgain(actualTime)) - { - return TELNETHost::ATTACK_REPORT_WAIT; - } - else - { + // host is attacking, wait for timeout to report again + if (!canReportAgain(actualTime)) { + return TELNETHost::ATTACK_REPORT_WAIT; + } else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); - uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); + uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); uint32_t outgoingMatchedNew = recordListOutgoing.getMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); - - if(incomingMatched == 0 && incomingMatchedNew == 0 && - outgoingMatched == 0 && outgoingMatchedNew == 0) - { - return TELNETHost::END_OF_ATTACK; - } - - auto keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - - // avoids div by zero - auto incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double)incomingMatchedNew / incomingTotalNew); - auto outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double)outgoingMatchedNew / outgoingTotalNew); - - if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) - { - if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) - { - return TELNETHost::REPORT_END_OF_ATTACK; - } - else - { - return TELNETHost::END_OF_ATTACK; - } + uint32_t outgoingTotalNew = recordListOutgoing.getTotalFlowsSinceLastReport(); + + if (incomingMatched == 0 && incomingMatchedNew == 0 && + outgoingMatched == 0 && outgoingMatchedNew == 0) { + return TELNETHost::END_OF_ATTACK; + } + + double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); + + double incomingMatchedNewRatio = (incomingTotalNew == 0 ? 0 : (double) incomingMatchedNew / + incomingTotalNew); + double outgoingMatchedNewRatio = (outgoingTotalNew == 0 ? 0 : (double) outgoingMatchedNew / + outgoingTotalNew); + + if (std::max(incomingMatchedNewRatio, outgoingMatchedNewRatio) < keepTrackingHostRatio) { + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return TELNETHost::REPORT_END_OF_ATTACK; + } else { + return TELNETHost::END_OF_ATTACK; + } } - if(std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) - { - return TELNETHost::REPORT_ATTACK; - } - else - { - return TELNETHost::ATTACK_MIN_EVENTS_WAIT; - } + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return TELNETHost::REPORT_ATTACK; + } else { + return TELNETHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -427,47 +317,36 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) // *********************** SSH HOST MAP ***********************/ // ************************************************************/ -SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) -{ +SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) { ip_addr_t ip; - if(direction == FLOW_INCOMING_DIRECTION) - { - ip = structure->srcIp; - } - else - { - ip = structure->dstIp; - } + if (direction == FLOW_INCOMING_DIRECTION) { + ip = structure->srcIp; + } else { + ip = structure->dstIp; + } auto it = hostMap.find(ip); SSHHost *host; - if(it == hostMap.end()) - { - // not found, create new host + if (it == hostMap.end()) { + // not found, create new host host = new SSHHost(ip, structure->flowFirstSeen); - hostMap.insert(std::pair(ip, host)); + hostMap.insert(std::pair(ip, host)); + } else { + host = it->second; } - else - { - host = it->second; - } return host; } -void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) -{ - for (const auto & it : hostMap) - { +void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { + for (const auto &it : hostMap) { SSHHost *host = it.second; - if(host->isReported() && host->checkForAttackTimeout(actualTime)) - { + if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); - if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) - { + if (numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_SSH_PORT, actualTime, true); } host->setNotReported(); @@ -476,56 +355,44 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) } } -void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) -{ - IHostMap::clearOldRecAndHost(&hostMap, actualTime); +void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { + IHostMap::clearOldRecAndHost(&hostMap, actualTime); } // ************************************************************/ // *********************** RDP HOST MAP ***********************/ // ************************************************************/ -RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) -{ +RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) { ip_addr_t ip; - if(direction == FLOW_INCOMING_DIRECTION) - { - ip = structure->srcIp; - } - else - { - ip = structure->dstIp; // attacker is now destination address - } + if (direction == FLOW_INCOMING_DIRECTION) { + ip = structure->srcIp; + } else { + ip = structure->dstIp; // attacker is now destination address + } auto it = hostMap.find(ip); RDPHost *host; - if (it == hostMap.end()) - { - // not found, create new host + if (it == hostMap.end()) { + // not found, create new host host = new RDPHost(ip, structure->flowFirstSeen); - hostMap.insert(std::pair(ip, host)); + hostMap.insert(std::pair(ip, host)); + } else { + host = it->second; } - else - { - host = it->second; - } return host; } -void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) -{ - for(const auto & it : hostMap) - { +void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { + for (const auto &it : hostMap) { RDPHost *host = it.second; - if(host->isReported() && host->checkForAttackTimeout(actualTime)) - { + if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); - if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) - { + if (numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_RDP_PORT, actualTime, true); } host->setNotReported(); @@ -534,56 +401,44 @@ void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) } } -void RDPHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) -{ - IHostMap::clearOldRecAndHost(&hostMap, actualTime); +void RDPHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { + IHostMap::clearOldRecAndHost(&hostMap, actualTime); } // ************************************************************/ // ********************** TELNET HOST MAP *********************/ // ************************************************************/ -TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) -{ +TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) { ip_addr_t ip; - if(direction == FLOW_INCOMING_DIRECTION) - { - ip = structure->srcIp; - } - else - { - ip = structure->dstIp; // attacker is now destination address - } + if (direction == FLOW_INCOMING_DIRECTION) { + ip = structure->srcIp; + } else { + ip = structure->dstIp; // attacker is now destination address + } auto it = hostMap.find(ip); TELNETHost *host; - if(it == hostMap.end()) - { - // not found, create new host + if (it == hostMap.end()) { + // not found, create new host host = new TELNETHost(ip, structure->flowFirstSeen); - hostMap.insert(std::pair(ip, host)); + hostMap.insert(std::pair(ip, host)); + } else { + host = it->second; } - else - { - host = it->second; - } return host; } -void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) -{ - for(const auto & it : hostMap) - { +void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { + for (const auto &it : hostMap) { TELNETHost *host = it.second; - if(host->isReported() && host->checkForAttackTimeout(actualTime)) - { + if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); - if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) - { + if (numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) { sender->continuingReport(host, TCP_TELNET_PORT, actualTime, true); } @@ -593,7 +448,6 @@ void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) } } -void TELNETHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) -{ - IHostMap::clearOldRecAndHost(&hostMap, actualTime); +void TELNETHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { + IHostMap::clearOldRecAndHost(&hostMap, actualTime); } diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index d7aa0285..743e1ec6 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -184,7 +184,7 @@ class SSHHost : public IHost { public: SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} - bool addRecord(SSHRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; + bool addRecord(SSHRecord *record, void *structure, uint8_t direction) override; ATTACK_STATE checkForAttack(ur_time_t actualTime) override; ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getSSHReportTimeout(); } @@ -197,7 +197,7 @@ class RDPHost : public IHost { public: RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} - bool addRecord(RDPRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; + bool addRecord(RDPRecord *record, void *structure, uint8_t direction) override; ATTACK_STATE checkForAttack(ur_time_t actualTime) override; ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getRDPReportTimeout(); } @@ -209,7 +209,7 @@ class TELNETHost : public IHost { public: TELNETHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} - bool addRecord(TELNETRecord *record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) override; + bool addRecord(TELNETRecord *record, void *structure, uint8_t direction) override; ATTACK_STATE checkForAttack(ur_time_t actualTime) override; ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getTELNETReportTimeout(); } From 0e281e0b2eebbea5b7b77032aba628f529c4772e Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Fri, 20 Sep 2019 16:07:11 +0200 Subject: [PATCH 34/40] Reformatting, var names changes, fixes to default config --- brute_force_detector/brute_force_detector.cpp | 176 ++-- brute_force_detector/brute_force_detector.h | 102 +-- brute_force_detector/config.cpp | 135 ++- brute_force_detector/config.h | 248 +++--- brute_force_detector/config/config.conf | 30 +- brute_force_detector/config/whitelist.wl | 2 +- brute_force_detector/host.cpp | 125 +-- brute_force_detector/host.h | 236 +++--- brute_force_detector/record.cpp | 243 +++--- brute_force_detector/record.h | 280 +++--- brute_force_detector/sender.cpp | 38 +- brute_force_detector/sender.h | 57 +- .../telnet_server_profile.cpp | 47 +- brute_force_detector/telnet_server_profile.h | 39 +- brute_force_detector/whitelist.cpp | 797 +++++++++--------- brute_force_detector/whitelist.h | 305 +++---- brute_force_detector/whitelist_unit_test.cpp | 309 ++++--- 17 files changed, 1648 insertions(+), 1521 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index bde29eed..525c1c5b 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -106,7 +106,7 @@ UR_FIELDS( /* ************************************************************************* */ // Struct with information about module -trap_module_info_t *module_info = nullptr; +trap_module_info_t *module_info = NULL; #define MODULE_BASIC_INFO(BASIC) \ @@ -130,18 +130,23 @@ void signalHandler(int signal) { if (signal == SIGTERM || signal == SIGINT) { stop = 1; trap_terminate(); - } else if (signal == SIGUSR1) { + } + else if (signal == SIGUSR1) { Config::getInstance().reloadConfig(); - } else if (signal == SIGUSR2) { + } + else if (signal == SIGUSR2) { if (!whitelist.isLockedForConfigurationReload()) { whitelist.reloadWhitelist(); - } else { + } + else { alarm(1); // cannot reload now.. wait } - } else if (signal == SIGALRM) { + } + else if (signal == SIGALRM) { if (!whitelist.isLockedForConfigurationReload()) { whitelist.reloadWhitelist(); - } else { + } + else { alarm(1); // wait another second } } @@ -167,6 +172,7 @@ printFlowPercent(uint64_t b, uint64_t p, const std::string &comment /* optional, int main(int argc, char **argv) { + getc(stdin); // ***** TRAP initialization ***** int ret; INIT_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) @@ -188,11 +194,11 @@ int main(int argc, char **argv) { sigaddset(&sigAction.sa_mask, SIGALRM); // register signal handler - sigaction (SIGTERM, &sigAction, nullptr); - sigaction (SIGINT , &sigAction, nullptr); - sigaction (SIGUSR1, &sigAction, nullptr); - sigaction (SIGUSR2, &sigAction, nullptr); - sigaction (SIGALRM, &sigAction, nullptr); + sigaction (SIGTERM, &sigAction, NULL); + sigaction (SIGINT , &sigAction, NULL); + sigaction (SIGUSR1, &sigAction, NULL); + sigaction (SIGUSR2, &sigAction, NULL); + sigaction (SIGALRM, &sigAction, NULL); #else signal(SIGTERM, signalHandler); signal(SIGINT, signalHandler); @@ -203,8 +209,8 @@ int main(int argc, char **argv) { // ***** Parsing non TRAP arguments ***** signed char opt; - char *configFilePath = nullptr; - char *whitelistFilePath = nullptr; + char *configFilePath = NULL; + char *whitelistFilePath = NULL; bool whitelistParserVerbose = false; bool RDP = false, SSH = false, TELNET = false; while ((opt = TRAP_GETOPT(argc, argv, module_getopt_string, long_options)) != -1) { @@ -241,7 +247,7 @@ int main(int argc, char **argv) { } // ***** Config init ***** - if (configFilePath != nullptr) { + if (configFilePath != NULL) { bool state = Config::getInstance().initFromFile(configFilePath); if (!state) { cerr << "Error: Cannot open configuration file \"" << configFilePath << "\".\n"; @@ -251,7 +257,7 @@ int main(int argc, char **argv) { } // ***** Whitelist init ***** - if (whitelistFilePath != nullptr) { + if (whitelistFilePath != NULL) { bool state = whitelist.init(whitelistFilePath, whitelistParserVerbose); if (!state) { cerr << "Error: Cannot open whitelist file.\n"; @@ -263,11 +269,11 @@ int main(int argc, char **argv) { // ***** Create UniRec template for input ***** std::string unirecSpecifier = "SRC_IP,DST_IP,SRC_PORT,DST_PORT,PROTOCOL,PACKETS,BYTES,TIME_FIRST,TIME_LAST,TCP_FLAGS"; - char *errstr = nullptr; + char *errstr = NULL; ur_template_t *tmplt = ur_create_input_template(0, unirecSpecifier.c_str(), &errstr); - if (tmplt == nullptr) { + if (tmplt == NULL) { cerr << "Error: Invalid UniRec specifier." << endl; - if (errstr != nullptr) { + if (errstr != NULL) { fprintf(stderr, "%s\n", errstr); free(errstr); } @@ -279,7 +285,7 @@ int main(int argc, char **argv) { // ***** Init UniRec template for sender ***** bool senderState; - auto sender = new Sender(&senderState); + Sender *sender = new Sender(&senderState); if (!senderState) { cerr << "Error: Invalid output UniRec specifier. Check sender.cpp file.\n"; delete sender; @@ -314,7 +320,8 @@ int main(int argc, char **argv) { if (data_size < ur_rec_fixlen_size(tmplt)) { if (data_size <= 1) { break; // End of data (used for testing purposes) - } else { + } + else { cerr << "Error: data with wrong size received (expected size: >= " << ur_rec_fixlen_size(tmplt) << ", received size: " << data_size << ")\n"; @@ -338,7 +345,8 @@ int main(int argc, char **argv) { uint8_t direction; if (dstPort == TCP_SSH_PORT || dstPort == TCP_TELNET_PORT || dstPort == TCP_RDP_PORT) { direction = FLOW_INCOMING_DIRECTION; - } else { + } + else { direction = FLOW_OUTGOING_DIRECTION; } @@ -351,8 +359,8 @@ int main(int argc, char **argv) { .dstIp = ur_get(tmplt, data, F_DST_IP), .srcPort = srcPort, .dstPort = dstPort, - .flowFirstSeen = ur_get(tmplt, data, F_TIME_FIRST), - .flowLastSeen = ur_get(tmplt, data, F_TIME_LAST), + .firstSeen = ur_get(tmplt, data, F_TIME_FIRST), + .lastSeen = ur_get(tmplt, data, F_TIME_LAST), }; ret = 0; @@ -364,15 +372,16 @@ int main(int argc, char **argv) { SSHRecord *record; if (direction == FLOW_INCOMING_DIRECTION) { - record = new SSHRecord(flow.dstIp, flow.flowLastSeen); + record = new SSHRecord(flow.dstIp, flow.lastSeen); is_matched = record->matchWithIncomingSignature(&flow, &whitelist); if (is_matched) { ssh.matchedIncomingFlows++; } ssh.incomingFlows++; - } else { + } + else { // FLOW_OUTGOING_DIRECTION - record = new SSHRecord(flow.srcIp, flow.flowLastSeen); + record = new SSHRecord(flow.srcIp, flow.lastSeen); is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); if (is_matched) { ssh.matchedOutgoingFlows++; @@ -392,30 +401,35 @@ int main(int argc, char **argv) { if (is_portscan) { delete record; - } else { + } + else { // check for attack - auto attackState = host->checkForAttack(flow.flowLastSeen); + SSHHost::ATTACK_STATE attackState = host->checkForAttack(flow.lastSeen); if (attackState != SSHHost::NO_ATTACK) { if (attackState == SSHHost::REPORT_NEW_ATTACK) { - ret = sender->firstReport(host, TCP_SSH_PORT, flow.flowLastSeen, - Config::getInstance().getSSHListThreshold()); - } else if (attackState == SSHHost::ATTACK_REPORT_WAIT || - attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) { + ret = sender->firstReport(host, TCP_SSH_PORT, flow.lastSeen, + Config::getInstance().getSSHFlowThreshold()); + } + else if (attackState == SSHHost::ATTACK_REPORT_WAIT || + attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } else if (attackState == SSHHost::END_OF_ATTACK) { + } + else if (attackState == SSHHost::END_OF_ATTACK) { // clear list host->clearAllRecords(); host->setNotReported(); - } else if (attackState == SSHHost::REPORT_END_OF_ATTACK) { + } + else if (attackState == SSHHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_SSH_PORT, flow.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_SSH_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); - } else if (attackState == SSHHost::REPORT_ATTACK) { - ret = sender->continuingReport(host, TCP_SSH_PORT, flow.flowLastSeen); + } + else if (attackState == SSHHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_SSH_PORT, flow.lastSeen); } } } @@ -428,15 +442,16 @@ int main(int argc, char **argv) { RDPRecord *record; if (direction == FLOW_INCOMING_DIRECTION) { - record = new RDPRecord(flow.dstIp, flow.flowLastSeen); + record = new RDPRecord(flow.dstIp, flow.lastSeen); is_matched = record->matchWithIncomingSignature(&flow, &whitelist); if (is_matched) { rdp.matchedIncomingFlows++; } rdp.incomingFlows++; - } else { + } + else { // FLOW_OUTGOING_DIRECTION - record = new RDPRecord(flow.srcIp, flow.flowLastSeen); + record = new RDPRecord(flow.srcIp, flow.lastSeen); is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); if (is_matched) { rdp.matchedOutgoingFlows++; @@ -454,28 +469,33 @@ int main(int argc, char **argv) { is_portscan = !host->addRecord(record, &flow, direction); if (is_portscan) { delete record; - } else { + } + else { // check for attack - RDPHost::ATTACK_STATE attackState = host->checkForAttack(flow.flowLastSeen); + RDPHost::ATTACK_STATE attackState = host->checkForAttack(flow.lastSeen); if (attackState != RDPHost::NO_ATTACK) { if (attackState == RDPHost::REPORT_NEW_ATTACK) { - ret = sender->firstReport(host, TCP_RDP_PORT, flow.flowLastSeen, - Config::getInstance().getRDPListThreshold()); - } else if (attackState == RDPHost::ATTACK_REPORT_WAIT || - attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) { + ret = sender->firstReport(host, TCP_RDP_PORT, flow.lastSeen, + Config::getInstance().getRDPFlowThreshold()); + } + else if (attackState == RDPHost::ATTACK_REPORT_WAIT || + attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } else if (attackState == RDPHost::END_OF_ATTACK) { + } + else if (attackState == RDPHost::END_OF_ATTACK) { host->clearAllRecords(); host->setNotReported(); - } else if (attackState == RDPHost::REPORT_END_OF_ATTACK) { + } + else if (attackState == RDPHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_RDP_PORT, flow.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_RDP_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); - } else if (attackState == RDPHost::REPORT_ATTACK) { - ret = sender->continuingReport(host, TCP_RDP_PORT, flow.flowLastSeen); + } + else if (attackState == RDPHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_RDP_PORT, flow.lastSeen); } } } @@ -488,15 +508,16 @@ int main(int argc, char **argv) { TELNETRecord *record; if (direction == FLOW_INCOMING_DIRECTION) { - record = new TELNETRecord(flow.dstIp, flow.flowLastSeen); + record = new TELNETRecord(flow.dstIp, flow.lastSeen); is_matched = record->matchWithIncomingSignature(&flow, &whitelist); if (is_matched) { telnet.matchedIncomingFlows++; } telnet.incomingFlows++; - } else { + } + else { // FLOW_OUTGOING_DIRECTION - record = new TELNETRecord(flow.srcIp, flow.flowLastSeen); + record = new TELNETRecord(flow.srcIp, flow.lastSeen); is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); if (is_matched) { telnet.matchedOutgoingFlows++; @@ -514,58 +535,63 @@ int main(int argc, char **argv) { is_portscan = !host->addRecord(record, &flow, direction); if (is_portscan) { delete record; - } else { + } + else { // check for attack - TELNETHost::ATTACK_STATE attackState = host->checkForAttack(flow.flowLastSeen); + TELNETHost::ATTACK_STATE attackState = host->checkForAttack(flow.lastSeen); if (attackState != TELNETHost::NO_ATTACK) { if (attackState == TELNETHost::REPORT_NEW_ATTACK) { - ret = sender->firstReport(host, TCP_TELNET_PORT, flow.flowLastSeen, - Config::getInstance().getTELNETListThreshold()); - } else if (attackState == TELNETHost::ATTACK_REPORT_WAIT || - attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) { + ret = sender->firstReport(host, TCP_TELNET_PORT, flow.lastSeen, + Config::getInstance().getTELNETFlowThreshold()); + } + else if (attackState == TELNETHost::ATTACK_REPORT_WAIT || + attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } else if (attackState == TELNETHost::END_OF_ATTACK) { + } + else if (attackState == TELNETHost::END_OF_ATTACK) { host->clearAllRecords(); host->setNotReported(); - } else if (attackState == TELNETHost::REPORT_END_OF_ATTACK) { + } + else if (attackState == TELNETHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); - } else if (attackState == TELNETHost::REPORT_ATTACK) { - ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.flowLastSeen); + } + else if (attackState == TELNETHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.lastSeen); } } } } - if (checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flow.flowLastSeen)) { - timeOfLastReportCheck = flow.flowLastSeen; + if (checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flow.lastSeen)) { + timeOfLastReportCheck = flow.lastSeen; if (SSH) { - sshHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + sshHostMap.checkForAttackTimeout(flow.lastSeen, sender); } if (RDP) { - rdpHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + rdpHostMap.checkForAttackTimeout(flow.lastSeen, sender); } if (TELNET) { - telnetHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + telnetHostMap.checkForAttackTimeout(flow.lastSeen, sender); } } - if (checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, flow.flowLastSeen)) { - timeOfLastDeleteCheck = flow.flowLastSeen; + if (checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, flow.lastSeen)) { + timeOfLastDeleteCheck = flow.lastSeen; if (SSH) { - sshHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + sshHostMap.deleteOldRecordAndHosts(flow.lastSeen); } if (RDP) { - rdpHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + rdpHostMap.deleteOldRecordAndHosts(flow.lastSeen); } if (TELNET) { - telnetHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + telnetHostMap.deleteOldRecordAndHosts(flow.lastSeen); } } diff --git a/brute_force_detector/brute_force_detector.h b/brute_force_detector/brute_force_detector.h index c18af9cc..4165b9c9 100644 --- a/brute_force_detector/brute_force_detector.h +++ b/brute_force_detector/brute_force_detector.h @@ -49,74 +49,76 @@ #include #include //ip_addr_t -const static uint8_t TCP_PROTOCOL_NUM = 6; -const static uint16_t TCP_SSH_PORT = 22; -const static uint16_t TCP_TELNET_PORT = 23; -const static uint16_t TCP_RDP_PORT = 3389; +const static uint8_t TCP_PROTOCOL_NUM = 6; +const static uint16_t TCP_SSH_PORT = 22; +const static uint16_t TCP_TELNET_PORT = 23; +const static uint16_t TCP_RDP_PORT = 3389; const static uint8_t FLOW_INCOMING_DIRECTION = 1; const static uint8_t FLOW_OUTGOING_DIRECTION = 2; -void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment = ""); +static const uint16_t TELNET_OUTGOING_MIN_PACKETS = 6; + + +void printFlowPercent(uint64_t b, uint64_t p, const std::string &comment = ""); //ip address comparison for std::map and std::set struct cmpByIpAddr { - bool operator ()(const ip_addr_t& a, const ip_addr_t& b) const { - return (memcmp((char*)&a, (char*)&b, sizeof(ip_addr_t)) < 0); + bool operator()(const ip_addr_t &a, const ip_addr_t &b) const { + return (memcmp((char *) &a, (char *) &b, sizeof(ip_addr_t)) < 0); } }; struct thousandsSeparator : std::numpunct { - // use dot as separator - char do_thousands_sep() const override { return '.'; } + // use dot as separator + char do_thousands_sep() const override { return '.'; } - // digits are grouped by 3 digits each - std::string do_grouping() const override { return "\3"; } + // digits are grouped by 3 digits each + std::string do_grouping() const override { return "\3"; } }; class logInfo { public: - explicit logInfo(std::string _protocolName) : protocolName(std::move(_protocolName)), - flows(0), - incomingFlows(0), - outgoingFlows(0), - matchedFlows(0), - matchedIncomingFlows(0), - matchedOutgoingFlows(0) - {}; - - void printLogInfo(){ - std::cout << this->protocolName << std::endl; - std::cout.imbue(std::locale(std::locale(), new thousandsSeparator)); // TODO move elsewhere - std::cout << " Total Flows: " << this->flows << std::endl; - std::cout << " Incoming Flows: " << this->incomingFlows; - printFlowPercent(this->flows, this->incomingFlows); - std::cout << std::endl; - std::cout << " Outgoing Flows: " << this->outgoingFlows; - printFlowPercent(this->flows, this->outgoingFlows); - std::cout << std::endl; - std::cout << " Matched Flows: " << this->matchedFlows; - printFlowPercent(this->flows, this->matchedFlows); - std::cout << std::endl; - std::cout << " Matched Incoming Flows: " << this->matchedIncomingFlows; - printFlowPercent(this->matchedFlows, this->matchedIncomingFlows, " from matched"); - printFlowPercent(this->flows, this->matchedIncomingFlows, " from incoming"); - std::cout << std::endl; - std::cout << " Matched Outgoing Flows: " << this->matchedOutgoingFlows; - printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows, " from matched"); - printFlowPercent(this->flows, this->matchedOutgoingFlows, " from outgoing"); - std::cout << std::endl; - } - - std::string protocolName; - uint64_t flows; - uint64_t incomingFlows; - uint64_t outgoingFlows; - uint64_t matchedFlows ; - uint64_t matchedIncomingFlows; - uint64_t matchedOutgoingFlows; + explicit logInfo(std::string _protocolName) : protocolName(std::move(_protocolName)), + flows(0), + incomingFlows(0), + outgoingFlows(0), + matchedFlows(0), + matchedIncomingFlows(0), + matchedOutgoingFlows(0) {}; + + void printLogInfo() { + std::cout << this->protocolName << std::endl; + std::cout.imbue(std::locale(std::locale(), new thousandsSeparator)); + std::cout << " Total Flows: " << this->flows << std::endl; + std::cout << " Incoming Flows: " << this->incomingFlows; + printFlowPercent(this->flows, this->incomingFlows); + std::cout << std::endl; + std::cout << " Outgoing Flows: " << this->outgoingFlows; + printFlowPercent(this->flows, this->outgoingFlows); + std::cout << std::endl; + std::cout << " Matched Flows: " << this->matchedFlows; + printFlowPercent(this->flows, this->matchedFlows); + std::cout << std::endl; + std::cout << " Matched Incoming Flows: " << this->matchedIncomingFlows; + printFlowPercent(this->matchedFlows, this->matchedIncomingFlows, " from matched"); + printFlowPercent(this->flows, this->matchedIncomingFlows, " from incoming"); + std::cout << std::endl; + std::cout << " Matched Outgoing Flows: " << this->matchedOutgoingFlows; + printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows, " from matched"); + printFlowPercent(this->flows, this->matchedOutgoingFlows, " from outgoing"); + std::cout << std::endl; + } + + std::string protocolName; + uint64_t flows; + uint64_t incomingFlows; + uint64_t outgoingFlows; + uint64_t matchedFlows; + uint64_t matchedIncomingFlows; + uint64_t matchedOutgoingFlows; }; #endif diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index 65769491..eb1ffa0f 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -56,8 +56,8 @@ Config::Config() { GENERAL_IGNORE_FIRST_SEND = 0; //SSH - SSH_LIST_SIZE = 1000; - SSH_LIST_THRESHOLD = 90; + SSH_MAX_RECORDS = 500; + SSH_FLOW_THRESHOLD = 90; SSH_MATCHED_FLOW_RATIO = 0.9; SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); @@ -77,8 +77,8 @@ Config::Config() { SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(600, 0); //RDP - RDP_LIST_SIZE = 1000; - RDP_LIST_THRESHOLD = 90; + RDP_MAX_RECORDS = 500; + RDP_FLOW_THRESHOLD = 90; RDP_MATCHED_FLOW_RATIO = 0.9; RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); @@ -99,8 +99,8 @@ Config::Config() { RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(600, 0); //TELNET - TELNET_LIST_SIZE = 1000; - TELNET_LIST_THRESHOLD = 90; + TELNET_MAX_RECORDS = 500; + TELNET_FLOW_THRESHOLD = 90; TELNET_MATCHED_FLOW_RATIO = 0.9; TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); @@ -120,12 +120,11 @@ Config::Config() { kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = "GENERAL_ATTACK_MIN_EVENTS_TO_REPORT"; kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = "GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST"; kw_GENERAL_IGNORE_FIRST_SEND = "GENERAL_IGNORE_FIRST_SEND"; - kw_GENERAL_MATCHED_FLOW_RATIO = "GENERAL_MATCHED_FLOW_RATIO"; //SSH - kw_SSH_LIST_SIZE = "SSH_LIST_SIZE"; - kw_SSH_LIST_THRESHOLD = "SSH_LIST_THRESHOLD"; - kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD = "SSH_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_SSH_MAX_RECORDS = "SSH_MAX_RECORDS"; + kw_SSH_FLOW_THRESHOLD = "SSH_FLOW_THRESHOLD"; + kw_SSH_MATCHED_FLOW_RATIO = "SSH_MATCHED_FLOW_RATIO"; kw_SSH_RECORD_TIMEOUT = "SSH_RECORD_TIMEOUT"; kw_SSH_HOST_TIMEOUT = "SSH_HOST_TIMEOUT"; @@ -143,9 +142,9 @@ Config::Config() { kw_SSH_BRUTEFORCE_OUT_MAX_BYTES = "SSH_BRUTEFORCE_OUT_MAX_BYTES"; //RDP - kw_RDP_LIST_SIZE = "RDP_LIST_SIZE"; - kw_RDP_LIST_THRESHOLD = "RDP_LIST_THRESHOLD"; - kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD = "RDP_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_RDP_MAX_RECORDS = "RDP_MAX_RECORDS"; + kw_RDP_FLOW_THRESHOLD = "RDP_FLOW_THRESHOLD"; + kw_RDP_MATCHED_FLOW_RATIO = "RDP_MATCHED_FLOW_RATIO"; kw_RDP_RECORD_TIMEOUT = "RDP_RECORD_TIMEOUT"; kw_RDP_HOST_TIMEOUT = "RDP_HOST_TIMEOUT"; @@ -163,9 +162,9 @@ Config::Config() { kw_RDP_BRUTEFORCE_OUT_MAX_BYTES = "RDP_BRUTEFORCE_OUT_MAX_BYTES"; //TELNET - kw_TELNET_LIST_SIZE = "TELNET_LIST_SIZE"; - kw_TELNET_LIST_THRESHOLD = "TELNET_LIST_THRESHOLD"; - kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD = "TELNET_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_TELNET_MAX_RECORDS = "TELNET_MAX_RECORDS"; + kw_TELNET_FLOW_THRESHOLD = "TELNET_FLOW_THRESHOLD"; + kw_TELNET_MATCHED_FLOW_RATIO = "TELNET_MATCHED_FLOW_RATIO"; kw_TELNET_RECORD_TIMEOUT = "TELNET_RECORD_TIMEOUT"; kw_TELNET_HOST_TIMEOUT = "TELNET_HOST_TIMEOUT"; @@ -233,169 +232,169 @@ bool Config::initFromFile(const string &path) { // ****** GENERAL ****** // ********************* if (keyword == kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) { - GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = std::stoul(value, nullptr); + GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = std::stoul(value, NULL); } else if (keyword == kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) { - GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = std::stod(value, nullptr); + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = std::stod(value, NULL); } else if (keyword == kw_GENERAL_IGNORE_FIRST_SEND) { - GENERAL_IGNORE_FIRST_SEND = std::stoul(value, nullptr); + GENERAL_IGNORE_FIRST_SEND = std::stoul(value, NULL); } // ********************* // ******* SSH ********* // ********************* - else if (keyword == kw_SSH_LIST_SIZE) { - SSH_LIST_SIZE = std::stoul(value, nullptr); + else if (keyword == kw_SSH_MAX_RECORDS) { + SSH_MAX_RECORDS = std::stoul(value, NULL); } - else if (keyword == kw_SSH_LIST_THRESHOLD) { - SSH_LIST_THRESHOLD = std::stoul(value, nullptr); + else if (keyword == kw_SSH_FLOW_THRESHOLD) { + SSH_FLOW_THRESHOLD = std::stoul(value, NULL); } else if (keyword == kw_SSH_MATCHED_FLOW_RATIO) { - SSH_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + SSH_MATCHED_FLOW_RATIO = std::stod(value, NULL); } else if (keyword == kw_SSH_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); SSH_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) { - SSH_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); + SSH_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) { - SSH_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); + SSH_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_BYTES) { - SSH_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); + SSH_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_BYTES) { - SSH_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); + SSH_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); } // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) { - SSH_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, nullptr); + SSH_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) { - SSH_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, nullptr); + SSH_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) { - SSH_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, nullptr); + SSH_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) { - SSH_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, nullptr); + SSH_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, NULL); } // ********************* // ******* RDP ********* // ********************* - else if (keyword == kw_RDP_LIST_SIZE) { - RDP_LIST_SIZE = std::stoul(value, nullptr); + else if (keyword == kw_RDP_MAX_RECORDS) { + RDP_MAX_RECORDS = std::stoul(value, NULL); } - else if (keyword == kw_RDP_LIST_THRESHOLD) { - RDP_LIST_THRESHOLD = std::stoul(value, nullptr); + else if (keyword == kw_RDP_FLOW_THRESHOLD) { + RDP_FLOW_THRESHOLD = std::stoul(value, NULL); } else if (keyword == kw_RDP_MATCHED_FLOW_RATIO) { - RDP_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + RDP_MATCHED_FLOW_RATIO = std::stod(value, NULL); } else if (keyword == kw_RDP_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); RDP_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) { - RDP_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); + RDP_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) { - RDP_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); + RDP_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_BYTES) { - RDP_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); + RDP_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_BYTES) { - RDP_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); + RDP_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); } // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) { - RDP_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, nullptr); + RDP_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) { - RDP_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, nullptr); + RDP_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) { - RDP_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, nullptr); + RDP_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) { - RDP_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, nullptr); + RDP_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, NULL); } // ********************* // ****** TELNET ******* // ********************* - else if (keyword == kw_TELNET_LIST_SIZE) { - TELNET_LIST_SIZE = std::stoul(value, nullptr); + else if (keyword == kw_TELNET_MAX_RECORDS) { + TELNET_MAX_RECORDS = std::stoul(value, NULL); } - else if (keyword == kw_TELNET_LIST_THRESHOLD) { - TELNET_LIST_THRESHOLD = std::stoul(value, nullptr); + else if (keyword == kw_TELNET_FLOW_THRESHOLD) { + TELNET_FLOW_THRESHOLD = std::stoul(value, NULL); } else if (keyword == kw_TELNET_MATCHED_FLOW_RATIO) { - TELNET_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + TELNET_MATCHED_FLOW_RATIO = std::stod(value, NULL); } else if (keyword == kw_TELNET_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) { - TELNET_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); + TELNET_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) { - TELNET_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); + TELNET_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) { - TELNET_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); + TELNET_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) { - TELNET_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); + TELNET_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); } // ********************* // ******* UNKNOWN ***** diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index 7a76ee8b..d3d47ff8 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -56,77 +56,109 @@ class Config { public: - bool initFromFile(const std::string& path); + bool initFromFile(const std::string &path); - inline ur_time_t getGlobalTimerForReportCheck() const {return GENERAL_CHECK_FOR_REPORT_TIMEOUT;} - inline ur_time_t getGlobalTimerForDeleteCheck() const {return GENERAL_CHECK_FOR_DELETE_TIMEOUT;} - inline ur_time_t getGlobalAttackMinEvToReport() const {return GENERAL_ATTACK_MIN_EVENTS_TO_REPORT;} - inline double getGlobalAttackMinRatioToKeepTrackingHost() const {return GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST;} - inline int getGlobalIgnoreFirstSend() const {return GENERAL_IGNORE_FIRST_SEND;} + inline ur_time_t getGlobalTimerForReportCheck() const { return GENERAL_CHECK_FOR_REPORT_TIMEOUT; } - //SSH - inline uint16_t getSSHMaxListSize() const {return SSH_LIST_SIZE;} - inline uint16_t getSSHListThreshold() const {return SSH_LIST_THRESHOLD;} - inline double getSSHMatchedFlowRatio() const {return SSH_MATCHED_FLOW_RATIO;} + inline ur_time_t getGlobalTimerForDeleteCheck() const { return GENERAL_CHECK_FOR_DELETE_TIMEOUT; } - inline ur_time_t getSSHRecordTimeout() const {return SSH_RECORD_TIMEOUT;} - inline ur_time_t getSSHHostDeleteTimeout() const {return SSH_HOST_TIMEOUT;} - inline ur_time_t getSSHReportTimeout() const {return SSH_REPORT_TIMEOUT;} - inline ur_time_t getSSHAttackTimeout() const {return SSH_ATTACK_TIMEOUT;} + inline ur_time_t getGlobalAttackMinEvToReport() const { return GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; } + + inline double + getGlobalAttackMinRatioToKeepTrackingHost() const { return GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; } + + inline int getGlobalIgnoreFirstSend() const { return GENERAL_IGNORE_FIRST_SEND; } + + //SSH + inline uint16_t getSSHMaxRecords() const { return SSH_MAX_RECORDS; } + + inline uint16_t getSSHFlowThreshold() const { return SSH_FLOW_THRESHOLD; } + + inline double getSSHMatchedFlowRatio() const { return SSH_MATCHED_FLOW_RATIO; } + + inline ur_time_t getSSHRecordTimeout() const { return SSH_RECORD_TIMEOUT; } + + inline ur_time_t getSSHHostDeleteTimeout() const { return SSH_HOST_TIMEOUT; } + + inline ur_time_t getSSHReportTimeout() const { return SSH_REPORT_TIMEOUT; } + + inline ur_time_t getSSHAttackTimeout() const { return SSH_ATTACK_TIMEOUT; } // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) - inline uint16_t getSSHIncMinPackets() const {return SSH_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getSSHIncMaxPackets() const {return SSH_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getSSHIncMinBytes() const {return SSH_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getSSHIncMaxBytes() const {return SSH_BRUTEFORCE_INC_MAX_BYTES;} + inline uint16_t getSSHIncMinPackets() const { return SSH_BRUTEFORCE_INC_MIN_PACKETS; } + + inline uint16_t getSSHIncMaxPackets() const { return SSH_BRUTEFORCE_INC_MAX_PACKETS; } + + inline uint16_t getSSHIncMinBytes() const { return SSH_BRUTEFORCE_INC_MIN_BYTES; } + + inline uint16_t getSSHIncMaxBytes() const { return SSH_BRUTEFORCE_INC_MAX_BYTES; } // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) - inline uint16_t getSSHOutMinPackets() const {return SSH_BRUTEFORCE_OUT_MIN_PACKETS;} - inline uint16_t getSSHOutMaxPackets() const {return SSH_BRUTEFORCE_OUT_MAX_PACKETS;} - inline uint16_t getSSHOutMinBytes() const {return SSH_BRUTEFORCE_OUT_MIN_BYTES;} - inline uint16_t getSSHOutMaxBytes() const {return SSH_BRUTEFORCE_OUT_MAX_BYTES;} + inline uint16_t getSSHOutMinPackets() const { return SSH_BRUTEFORCE_OUT_MIN_PACKETS; } + + inline uint16_t getSSHOutMaxPackets() const { return SSH_BRUTEFORCE_OUT_MAX_PACKETS; } + + inline uint16_t getSSHOutMinBytes() const { return SSH_BRUTEFORCE_OUT_MIN_BYTES; } + + inline uint16_t getSSHOutMaxBytes() const { return SSH_BRUTEFORCE_OUT_MAX_BYTES; } + + //RDP + inline uint16_t getRDPMaxRecords() const { return RDP_MAX_RECORDS; } + + inline uint16_t getRDPFlowThreshold() const { return RDP_FLOW_THRESHOLD; } + + inline double getRDPMatchedFlowRatio() const { return RDP_MATCHED_FLOW_RATIO; } + + inline ur_time_t getRDPRecordTimeout() const { return RDP_RECORD_TIMEOUT; } + + inline ur_time_t getRDPHostDeleteTimeout() const { return RDP_HOST_TIMEOUT; } - //RDP - inline uint16_t getRDPMaxListSize() const {return RDP_LIST_SIZE;} - inline uint16_t getRDPListThreshold() const {return RDP_LIST_THRESHOLD;} - inline double getRDPMatchedFlowRatio() const {return RDP_MATCHED_FLOW_RATIO;} + inline ur_time_t getRDPReportTimeout() const { return RDP_REPORT_TIMEOUT; } - inline ur_time_t getRDPRecordTimeout() const {return RDP_RECORD_TIMEOUT;} - inline ur_time_t getRDPHostDeleteTimeout() const {return RDP_HOST_TIMEOUT;} - inline ur_time_t getRDPReportTimeout() const {return RDP_REPORT_TIMEOUT;} - inline ur_time_t getRDPAttackTimeout() const {return RDP_ATTACK_TIMEOUT;} + inline ur_time_t getRDPAttackTimeout() const { return RDP_ATTACK_TIMEOUT; } // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) - inline uint16_t getRDPIncMinPackets() const {return RDP_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getRDPIncMaxPackets() const {return RDP_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getRDPIncMinBytes() const {return RDP_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getRDPIncMaxBytes() const {return RDP_BRUTEFORCE_INC_MAX_BYTES;} - - // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) - inline uint16_t getRDPOutMinPackets() const {return RDP_BRUTEFORCE_OUT_MIN_PACKETS;} - inline uint16_t getRDPOutMaxPackets() const {return RDP_BRUTEFORCE_OUT_MAX_PACKETS;} - inline uint16_t getRDPOutMinBytes() const {return RDP_BRUTEFORCE_OUT_MIN_BYTES;} - inline uint32_t getRDPOutMaxBytes() const {return RDP_BRUTEFORCE_OUT_MAX_BYTES;} - - //TELNET - inline uint16_t getTELNETMaxListSize() const {return TELNET_LIST_SIZE;} - inline uint16_t getTELNETListThreshold() const {return TELNET_LIST_THRESHOLD;} - inline double getTELNETMatchedFlowRatio() const {return TELNET_MATCHED_FLOW_RATIO;} - - inline ur_time_t getTELNETRecordTimeout() const {return TELNET_RECORD_TIMEOUT;} - inline ur_time_t getTELNETHostDeleteTimeout()const {return TELNET_HOST_TIMEOUT;} - inline ur_time_t getTELNETReportTimeout() const {return TELNET_REPORT_TIMEOUT;} - inline ur_time_t getTELNETAttackTimeout() const {return TELNET_ATTACK_TIMEOUT;} - - inline uint16_t getTELNETIncMinPackets() const {return TELNET_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getTELNETIncMaxPackets() const {return TELNET_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getTELNETIncMinBytes() const {return TELNET_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getTELNETIncMaxBytes() const {return TELNET_BRUTEFORCE_INC_MAX_BYTES;} - - // TODO Where is telnet outgoing - - static Config& getInstance() - { + inline uint16_t getRDPIncMinPackets() const { return RDP_BRUTEFORCE_INC_MIN_PACKETS; } + + inline uint16_t getRDPIncMaxPackets() const { return RDP_BRUTEFORCE_INC_MAX_PACKETS; } + + inline uint16_t getRDPIncMinBytes() const { return RDP_BRUTEFORCE_INC_MIN_BYTES; } + + inline uint16_t getRDPIncMaxBytes() const { return RDP_BRUTEFORCE_INC_MAX_BYTES; } + + // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) + inline uint16_t getRDPOutMinPackets() const { return RDP_BRUTEFORCE_OUT_MIN_PACKETS; } + + inline uint16_t getRDPOutMaxPackets() const { return RDP_BRUTEFORCE_OUT_MAX_PACKETS; } + + inline uint16_t getRDPOutMinBytes() const { return RDP_BRUTEFORCE_OUT_MIN_BYTES; } + + inline uint32_t getRDPOutMaxBytes() const { return RDP_BRUTEFORCE_OUT_MAX_BYTES; } + + //TELNET + inline uint16_t getTELNETMaxRecords() const { return TELNET_MAX_RECORDS; } + + inline uint16_t getTELNETFlowThreshold() const { return TELNET_FLOW_THRESHOLD; } + + inline double getTELNETMatchedFlowRatio() const { return TELNET_MATCHED_FLOW_RATIO; } + + inline ur_time_t getTELNETRecordTimeout() const { return TELNET_RECORD_TIMEOUT; } + + inline ur_time_t getTELNETHostDeleteTimeout() const { return TELNET_HOST_TIMEOUT; } + + inline ur_time_t getTELNETReportTimeout() const { return TELNET_REPORT_TIMEOUT; } + + inline ur_time_t getTELNETAttackTimeout() const { return TELNET_ATTACK_TIMEOUT; } + + inline uint16_t getTELNETIncMinPackets() const { return TELNET_BRUTEFORCE_INC_MIN_PACKETS; } + + inline uint16_t getTELNETIncMaxPackets() const { return TELNET_BRUTEFORCE_INC_MAX_PACKETS; } + + inline uint16_t getTELNETIncMinBytes() const { return TELNET_BRUTEFORCE_INC_MIN_BYTES; } + + inline uint16_t getTELNETIncMaxBytes() const { return TELNET_BRUTEFORCE_INC_MAX_BYTES; } + + static Config &getInstance() { static Config instance; return instance; } @@ -135,33 +167,30 @@ class Config { private: Config(); + std::string configPath; //general ur_time_t GENERAL_CHECK_FOR_REPORT_TIMEOUT; ur_time_t GENERAL_CHECK_FOR_DELETE_TIMEOUT; - uint16_t GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; - double GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; - uint8_t GENERAL_IGNORE_FIRST_SEND; - // double GENERAL_MATCHED_FLOW_RATIO; + uint16_t GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; + double GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; + uint8_t GENERAL_IGNORE_FIRST_SEND; std::string kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT; std::string kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT; std::string kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; std::string kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; std::string kw_GENERAL_IGNORE_FIRST_SEND; - std::string kw_GENERAL_MATCHED_FLOW_RATIO; - //SSH - uint16_t SSH_LIST_SIZE; - uint16_t SSH_LIST_THRESHOLD; - uint16_t SSH_LIST_SIZE_BOTTOM_THRESHOLD; - double SSH_MATCHED_FLOW_RATIO; + uint16_t SSH_MAX_RECORDS; + uint16_t SSH_FLOW_THRESHOLD; + double SSH_MATCHED_FLOW_RATIO; - ur_time_t SSH_RECORD_TIMEOUT; + ur_time_t SSH_RECORD_TIMEOUT; ur_time_t SSH_HOST_TIMEOUT; ur_time_t SSH_REPORT_TIMEOUT; ur_time_t SSH_ATTACK_TIMEOUT; @@ -177,9 +206,8 @@ class Config { uint16_t SSH_BRUTEFORCE_OUT_MAX_BYTES; //SSH keywords - std::string kw_SSH_LIST_SIZE; - std::string kw_SSH_LIST_THRESHOLD; - std::string kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD; + std::string kw_SSH_MAX_RECORDS; + std::string kw_SSH_FLOW_THRESHOLD; std::string kw_SSH_MATCHED_FLOW_RATIO; std::string kw_SSH_RECORD_TIMEOUT; std::string kw_SSH_HOST_TIMEOUT; @@ -196,12 +224,11 @@ class Config { //RDP - uint16_t RDP_LIST_SIZE; - uint16_t RDP_LIST_SIZE_BOTTOM_THRESHOLD; - uint16_t RDP_LIST_THRESHOLD; - double RDP_MATCHED_FLOW_RATIO; + uint16_t RDP_MAX_RECORDS; + uint16_t RDP_FLOW_THRESHOLD; + double RDP_MATCHED_FLOW_RATIO; - ur_time_t RDP_RECORD_TIMEOUT; + ur_time_t RDP_RECORD_TIMEOUT; ur_time_t RDP_HOST_TIMEOUT; ur_time_t RDP_REPORT_TIMEOUT; ur_time_t RDP_ATTACK_TIMEOUT; @@ -217,9 +244,8 @@ class Config { uint32_t RDP_BRUTEFORCE_OUT_MAX_BYTES; //RDP keywords - std::string kw_RDP_LIST_SIZE; - std::string kw_RDP_LIST_THRESHOLD; - std::string kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD; + std::string kw_RDP_MAX_RECORDS; + std::string kw_RDP_FLOW_THRESHOLD; std::string kw_RDP_MATCHED_FLOW_RATIO; std::string kw_RDP_RECORD_TIMEOUT; std::string kw_RDP_HOST_TIMEOUT; @@ -235,36 +261,34 @@ class Config { std::string kw_RDP_ATTACK_TIMEOUT; - //TELNET - uint16_t TELNET_LIST_SIZE; - uint16_t TELNET_LIST_THRESHOLD; - uint16_t TELNET_LIST_SIZE_BOTTOM_THRESHOLD; - double TELNET_MATCHED_FLOW_RATIO; - - ur_time_t TELNET_RECORD_TIMEOUT; - ur_time_t TELNET_HOST_TIMEOUT; - ur_time_t TELNET_REPORT_TIMEOUT; - ur_time_t TELNET_ATTACK_TIMEOUT; - - uint16_t TELNET_BRUTEFORCE_INC_MIN_PACKETS; - uint16_t TELNET_BRUTEFORCE_INC_MAX_PACKETS; - uint16_t TELNET_BRUTEFORCE_INC_MIN_BYTES; - uint16_t TELNET_BRUTEFORCE_INC_MAX_BYTES; - - //TELNET keywords - std::string kw_TELNET_LIST_SIZE; - std::string kw_TELNET_LIST_THRESHOLD; - std::string kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD; - std::string kw_TELNET_MATCHED_FLOW_RATIO; - - std::string kw_TELNET_RECORD_TIMEOUT; - std::string kw_TELNET_HOST_TIMEOUT; - std::string kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS; - std::string kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS; - std::string kw_TELNET_BRUTEFORCE_INC_MIN_BYTES; - std::string kw_TELNET_BRUTEFORCE_INC_MAX_BYTES; - std::string kw_TELNET_REPORT_TIMEOUT; - std::string kw_TELNET_ATTACK_TIMEOUT; + //TELNET + uint16_t TELNET_MAX_RECORDS; + uint16_t TELNET_FLOW_THRESHOLD; + double TELNET_MATCHED_FLOW_RATIO; + + ur_time_t TELNET_RECORD_TIMEOUT; + ur_time_t TELNET_HOST_TIMEOUT; + ur_time_t TELNET_REPORT_TIMEOUT; + ur_time_t TELNET_ATTACK_TIMEOUT; + + uint16_t TELNET_BRUTEFORCE_INC_MIN_PACKETS; + uint16_t TELNET_BRUTEFORCE_INC_MAX_PACKETS; + uint16_t TELNET_BRUTEFORCE_INC_MIN_BYTES; + uint16_t TELNET_BRUTEFORCE_INC_MAX_BYTES; + + //TELNET keywords + std::string kw_TELNET_MAX_RECORDS; + std::string kw_TELNET_FLOW_THRESHOLD; + std::string kw_TELNET_MATCHED_FLOW_RATIO; + + std::string kw_TELNET_RECORD_TIMEOUT; + std::string kw_TELNET_HOST_TIMEOUT; + std::string kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS; + std::string kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS; + std::string kw_TELNET_BRUTEFORCE_INC_MIN_BYTES; + std::string kw_TELNET_BRUTEFORCE_INC_MAX_BYTES; + std::string kw_TELNET_REPORT_TIMEOUT; + std::string kw_TELNET_ATTACK_TIMEOUT; }; diff --git a/brute_force_detector/config/config.conf b/brute_force_detector/config/config.conf index f26e45e3..de871a35 100644 --- a/brute_force_detector/config/config.conf +++ b/brute_force_detector/config/config.conf @@ -65,12 +65,13 @@ ######################## ######### SSH ########## ######################## -#SSH_ATTACK_TIMEOUT = 600 -#SSH_LIST_SIZE = 100 -#SSH_LIST_THRESHOLD = 90 +#SSH_MAX_RECORDS = 500 +#SSH_FLOW_THRESHOLD = 90 #SSH_MATCHED_FLOW_RATIO = 0.9 -#SSH_RECORD_TIMEOUT = 1800 +#SSH_ATTACK_TIMEOUT = 600 +#SSH_RECORD_TIMEOUT = 3600 #SSH_HOST_TIMEOUT = 4200 +#SSH_REPORT_TIMEOUT = 300 #SSH_BRUTEFORCE_INC_MIN_PACKETS = 11 #SSH_BRUTEFORCE_INC_MAX_PACKETS = 30 #SSH_BRUTEFORCE_INC_MIN_BYTES = 1000 @@ -79,16 +80,16 @@ #SSH_BRUTEFORCE_OUT_MAX_PACKETS = 50 #SSH_BRUTEFORCE_OUT_MIN_BYTES = 1000 #SSH_BRUTEFORCE_OUT_MAX_BYTES = 11000 -#SSH_REPORT_TIMEOUT = 300 ######################## ######### RDP ########## ######################## -#RDP_ATTACK_TIMEOUT = 600 -#RDP_LIST_SIZE = 500 -#RDP_LIST_THRESHOLD = 90 +#RDP_MAX_RECORDS = 500 +#RDP_FLOW_THRESHOLD = 90 #RDP_MATCHED_FLOW_RATIO = 0.9 -#RDP_RECORD_TIMEOUT = 1800 +#RDP_ATTACK_TIMEOUT = 600 +#RDP_RECORD_TIMEOUT = 3600 #RDP_HOST_TIMEOUT = 4200 +#RDP_REPORT_TIMEOUT = 300 #RDP_BRUTEFORCE_INC_MIN_PACKETS = 20 #RDP_BRUTEFORCE_INC_MAX_PACKETS = 100 #RDP_BRUTEFORCE_INC_MIN_BYTES = 2200 @@ -97,19 +98,18 @@ #RDP_BRUTEFORCE_OUT_MAX_PACKETS = 190 #RDP_BRUTEFORCE_OUT_MIN_BYTES = 3000 #RDP_BRUTEFORCE_OUT_MAX_BYTES = 180000 -#RDP_REPORT_TIMEOUT = 300 ######################## ######## Telnet ######## ######################## -#TELNET_LIST_SIZE = 100 -#TELNET_LIST_THRESHOLD = 90 +#TELNET_MAX_RECORDS = 500 +#TELNET_FLOW_THRESHOLD = 90 #TELNET_MATCHED_FLOW_RATIO = 0.9 -#TELNET_RECORD_TIMEOUT = 1800 +#TELNET_ATTACK_TIMEOUT = 600 +#TELNET_RECORD_TIMEOUT = 3600 #TELNET_HOST_TIMEOUT = 4200 +#TELNET_REPORT_TIMEOUT = 300 #TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9 #TELNET_BRUTEFORCE_INC_MAX_PACKETS = 50 #TELNET_BRUTEFORCE_INC_MIN_BYTES = 450 #TELNET_BRUTEFORCE_INC_MAX_BYTES = 3000 ## Outgoing direction is not supported -#TELNET_ATTACK_TIMEOUT = 600 -#TELNET_REPORT_TIMEOUT = 300 diff --git a/brute_force_detector/config/whitelist.wl b/brute_force_detector/config/whitelist.wl index cb1626eb..75d85a7a 100644 --- a/brute_force_detector/config/whitelist.wl +++ b/brute_force_detector/config/whitelist.wl @@ -19,7 +19,7 @@ dst 131.103.20.160/28/22 #bitbucket src 166.88.20.3/32 # EGIHosting (USA) ?, valid communication to 195.113.184.18, src 195.113.44.19/32 # Charles University (CZ), valid(???) communication to 88.208.125.10 & 88.208.125.11, - +179.176.223.171 diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 1657317e..e957fdd1 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -53,17 +53,21 @@ bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) { // ignore port-scans if (isFlowScan(&st.packets, &st.flags)) { return false; - } else if (st.packets == 1 && st.flags == 0b00010000) // skip ack only packet + } + else if (st.packets == 1 && st.flags == 0b00010000) // skip ack only packet { return false; - } else if (st.packets == 4 && st.flags == 0b00000010) // 4 packet SYN request + } + else if (st.packets == 4 && st.flags == 0b00000010) // 4 packet SYN request { return false; - } else { - timeOfLastReceivedRecord = st.flowLastSeen; + } + else { + timeOfLastReceivedRecord = st.lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - } else { + } + else { recordListOutgoing.addRecord(record, isReported()); } @@ -87,21 +91,24 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); // is flow count over a minimum threshold and is a big enough part of it matched? - if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold() && + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHFlowThreshold() && (topMatchedRatio >= Config::getInstance().getSSHMatchedFlowRatio())) { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return SSHHost::REPORT_NEW_ATTACK; - } else { + } + else { return SSHHost::NO_ATTACK; } - } else // isReported + } + else // isReported { // host is attacking, wait for timeout to report again if (!canReportAgain(actualTime)) { return SSHHost::ATTACK_REPORT_WAIT; - } else { + } + else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); @@ -125,7 +132,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return SSHHost::REPORT_END_OF_ATTACK; - } else { + } + else { return SSHHost::END_OF_ATTACK; } } @@ -133,7 +141,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return SSHHost::REPORT_ATTACK; - } else { + } + else { return SSHHost::ATTACK_MIN_EVENTS_WAIT; } } @@ -149,11 +158,13 @@ bool RDPHost::addRecord(RDPRecord *record, void *structure, uint8_t direction) { // ignore port-scans if (isFlowScan(&st.packets, &st.flags)) { return false; - } else { - timeOfLastReceivedRecord = st.flowLastSeen; + } + else { + timeOfLastReceivedRecord = st.lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - } else { + } + else { recordListOutgoing.addRecord(record, isReported()); } return true; @@ -174,22 +185,25 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); // is flow count over a minimum threshold and is a big enough part of it matched? - if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold() && + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPFlowThreshold() && (topMatchedRatio >= Config::getInstance().getRDPMatchedFlowRatio())) { recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return RDPHost::REPORT_NEW_ATTACK; - } else { + } + else { return RDPHost::NO_ATTACK; } - } else // isReported + } + else // isReported { // host is attacking, wait for timeout to report again if (!canReportAgain(actualTime)) { return RDPHost::ATTACK_REPORT_WAIT; - } else { + } + else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); @@ -213,7 +227,8 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return RDPHost::REPORT_END_OF_ATTACK; - } else { + } + else { return RDPHost::END_OF_ATTACK; } } @@ -221,7 +236,8 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return RDPHost::REPORT_ATTACK; - } else { + } + else { return RDPHost::ATTACK_MIN_EVENTS_WAIT; } } @@ -237,11 +253,13 @@ bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direct // ignore port-scans if (isFlowScan(&st.packets, &st.flags)) { return false; - } else { - timeOfLastReceivedRecord = st.flowLastSeen; + } + else { + timeOfLastReceivedRecord = st.lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - } else { + } + else { recordListOutgoing.addRecord(record, isReported()); } return true; @@ -261,21 +279,24 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); // is flow count over a minimum threshold and is a big enough part of it matched? - if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold() && + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETFlowThreshold() && (topMatchedRatio >= Config::getInstance().getTELNETMatchedFlowRatio())) { recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return TELNETHost::REPORT_NEW_ATTACK; - } else { + } + else { return TELNETHost::NO_ATTACK; } - } else // isReported + } + else // isReported { // host is attacking, wait for timeout to report again if (!canReportAgain(actualTime)) { return TELNETHost::ATTACK_REPORT_WAIT; - } else { + } + else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); @@ -298,7 +319,8 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return TELNETHost::REPORT_END_OF_ATTACK; - } else { + } + else { return TELNETHost::END_OF_ATTACK; } } @@ -306,7 +328,8 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return TELNETHost::REPORT_ATTACK; - } else { + } + else { return TELNETHost::ATTACK_MIN_EVENTS_WAIT; } } @@ -321,19 +344,21 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { ip = structure->srcIp; - } else { + } + else { ip = structure->dstIp; } - auto it = hostMap.find(ip); + std::map::iterator it = hostMap.find(ip); SSHHost *host; if (it == hostMap.end()) { // not found, create new host - host = new SSHHost(ip, structure->flowFirstSeen); + host = new SSHHost(ip, structure->firstSeen); hostMap.insert(std::pair(ip, host)); - } else { + } + else { host = it->second; } @@ -341,8 +366,8 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct } void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for (const auto &it : hostMap) { - SSHHost *host = it.second; + for (std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) { + SSHHost *host = it->second; if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); @@ -367,19 +392,21 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { ip = structure->srcIp; - } else { + } + else { ip = structure->dstIp; // attacker is now destination address } - auto it = hostMap.find(ip); + std::map::iterator it = hostMap.find(ip); RDPHost *host; if (it == hostMap.end()) { // not found, create new host - host = new RDPHost(ip, structure->flowFirstSeen); + host = new RDPHost(ip, structure->firstSeen); hostMap.insert(std::pair(ip, host)); - } else { + } + else { host = it->second; } @@ -387,8 +414,9 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct } void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for (const auto &it : hostMap) { - RDPHost *host = it.second; + for(std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) + { + RDPHost *host = it->second; if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); @@ -413,19 +441,21 @@ TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { ip = structure->srcIp; - } else { + } + else { ip = structure->dstIp; // attacker is now destination address } - auto it = hostMap.find(ip); + std::map::iterator it = hostMap.find(ip); TELNETHost *host; if (it == hostMap.end()) { // not found, create new host - host = new TELNETHost(ip, structure->flowFirstSeen); + host = new TELNETHost(ip, structure->firstSeen); hostMap.insert(std::pair(ip, host)); - } else { + } + else { host = it->second; } @@ -433,8 +463,9 @@ TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t } void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for (const auto &it : hostMap) { - TELNETHost *host = it.second; + for(std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) + { + TELNETHost *host = it->second; if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 743e1ec6..712abda9 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -56,16 +56,14 @@ #include "brute_force_detector.h" - /** * Base class for host */ -template +template class IHost { public: - IHost(ip_addr_t _hostIp, ur_time_t _firstSeen) - { + IHost(ip_addr_t _hostIp, ur_time_t _firstSeen) { hostIp = _hostIp; firstSeen = _firstSeen; timeOfLastReport = 0; @@ -75,51 +73,50 @@ class IHost { virtual ~IHost() = default; - enum ATTACK_STATE { NO_ATTACK, - REPORT_NEW_ATTACK, // send report - ATTACK_REPORT_WAIT, - REPORT_ATTACK, // send report - ATTACK_MIN_EVENTS_WAIT, - END_OF_ATTACK, - REPORT_END_OF_ATTACK // send report + enum ATTACK_STATE { + NO_ATTACK, + REPORT_NEW_ATTACK, // send report + ATTACK_REPORT_WAIT, + REPORT_ATTACK, // send report + ATTACK_MIN_EVENTS_WAIT, + END_OF_ATTACK, + REPORT_END_OF_ATTACK // send report }; inline ip_addr_t getHostIp() { return hostIp; } + inline ur_time_t getTimeOfLastReport() { return timeOfLastReport; } + inline bool isReported() { return timeOfLastReport != 0; } - inline void setReportTime(ur_time_t actualTime) { timeOfLastReport = actualTime; } - inline void setNotReported() - { - recordListIncoming.clearTotalTargetsSinceAttack(); - recordListOutgoing.clearTotalTargetsSinceAttack(); + + inline void setReportTime(ur_time_t actualTime) { timeOfLastReport = actualTime; } + + inline void setNotReported() { + recordListIncoming.clearTotalTargetsSinceAttack(); + recordListOutgoing.clearTotalTargetsSinceAttack(); timeOfLastReport = 0; } inline bool getHostScannedNetwork() { return scanned; } - virtual bool addRecord(T record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) - { - if(direction == FLOW_INCOMING_DIRECTION) - { - recordListIncoming.addRecord(record, isReported()); - } - else - { - recordListOutgoing.addRecord(record, isReported()); - } + virtual bool addRecord(T record, void *structure, uint8_t direction) { + if (direction == FLOW_INCOMING_DIRECTION) { + recordListIncoming.addRecord(record, isReported()); + } + else { + recordListOutgoing.addRecord(record, isReported()); + } return true; } - void clearOldRecords(ur_time_t actualTime) - { - recordListIncoming.clearOldRecords(actualTime); - recordListOutgoing.clearOldRecords(actualTime); + void clearOldRecords(ur_time_t actualTime) { + recordListIncoming.clearOldRecords(actualTime); + recordListOutgoing.clearOldRecords(actualTime); } virtual ur_time_t getHostDeleteTimeout() = 0; - virtual bool canDeleteHost(ur_time_t actualTime) - { + virtual bool canDeleteHost(ur_time_t actualTime) { ur_time_t timer = getHostDeleteTimeout(); return checkForTimeout(timeOfLastReceivedRecord, timer, actualTime); @@ -127,43 +124,43 @@ class IHost { virtual ur_time_t getHostReportTimeout() = 0; - virtual bool canReportAgain(ur_time_t actualTime) - { + virtual bool canReportAgain(ur_time_t actualTime) { ur_time_t timer = getHostReportTimeout(); return checkForTimeout(timeOfLastReport, timer, actualTime); } virtual ur_time_t getHostAttackTimeout() = 0; - virtual bool checkForAttackTimeout(ur_time_t actualTime) - { + virtual bool checkForAttackTimeout(ur_time_t actualTime) { ur_time_t timer = getHostAttackTimeout(); return checkForTimeout(timeOfLastReport, timer, actualTime); } virtual ATTACK_STATE checkForAttack(ur_time_t actualTime) = 0; - RecordList* getPointerToIncomingRecordList() { return &recordListIncoming; } - RecordList* getPointerToOutgoingRecordList() { return &recordListOutgoing; } + RecordList *getPointerToIncomingRecordList() { return &recordListIncoming; } + + RecordList *getPointerToOutgoingRecordList() { return &recordListOutgoing; } - virtual void clearAllRecords() { recordListIncoming.clearAllRecords(); recordListOutgoing.clearAllRecords();} + virtual void clearAllRecords() { + recordListIncoming.clearAllRecords(); + recordListOutgoing.clearAllRecords(); + } - bool isFlowScan(const uint32_t *packets, const uint8_t *flags) - { - if( (*packets == 1 && *flags == 0b00000010) // SYN - || (*packets == 1 && *flags == 0b00010010) // SYN + ACK - || (*packets == 1 && *flags == 0b00010100) // RST + ACK - || (*packets == 2 && *flags == 0b00000010) // SYN - || (*packets == 2 && *flags == 0b00000110) // SYN + RST - || (*packets == 3 && *flags == 0b00000010)) // 3 SYN packets + bool isFlowScan(const uint32_t *packets, const uint8_t *flags) { + if ((*packets == 1 && *flags == 0b00000010) // SYN + || (*packets == 1 && *flags == 0b00010010) // SYN + ACK + || (*packets == 1 && *flags == 0b00010100) // RST + ACK + || (*packets == 2 && *flags == 0b00000010) // SYN + || (*packets == 2 && *flags == 0b00000110) // SYN + RST + || (*packets == 3 && *flags == 0b00000010)) // 3 SYN packets { scanned = true; return true; } - else - { - return false; - } + else { + return false; + } } protected: @@ -171,7 +168,7 @@ class IHost { bool scanned; ip_addr_t hostIp; - ur_time_t firstSeen; // TODO purpose? + ur_time_t firstSeen; // TODO unused ur_time_t timeOfLastReport; ur_time_t timeOfLastReceivedRecord; RecordList recordListIncoming; // direction to victim (attacker -> victim) @@ -179,40 +176,52 @@ class IHost { }; -class SSHHost : public IHost { +class SSHHost : public IHost { public: - SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} + SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} + + bool addRecord(SSHRecord *record, void *structure, uint8_t direction) override; + + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostDeleteTimeout(); } - bool addRecord(SSHRecord *record, void *structure, uint8_t direction) override; - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getSSHReportTimeout(); } + ur_time_t getHostAttackTimeout() override { return Config::getInstance().getSSHAttackTimeout(); } }; -class RDPHost : public IHost { +class RDPHost : public IHost { public: - RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} + RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} + + bool addRecord(RDPRecord *record, void *structure, uint8_t direction) override; + + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostDeleteTimeout(); } - bool addRecord(RDPRecord *record, void *structure, uint8_t direction) override; - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getRDPReportTimeout(); } + ur_time_t getHostAttackTimeout() override { return Config::getInstance().getRDPAttackTimeout(); } }; -class TELNETHost : public IHost { +class TELNETHost : public IHost { public: - TELNETHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} + TELNETHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} + + bool addRecord(TELNETRecord *record, void *structure, uint8_t direction) override; + + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostDeleteTimeout(); } + + ur_time_t getHostReportTimeout() override { return Config::getInstance().getTELNETReportTimeout(); } - bool addRecord(TELNETRecord *record, void *structure, uint8_t direction) override; - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostDeleteTimeout(); } - ur_time_t getHostReportTimeout() override { return Config::getInstance().getTELNETReportTimeout(); } ur_time_t getHostAttackTimeout() override { return Config::getInstance().getTELNETAttackTimeout(); } }; @@ -224,26 +233,25 @@ class IHostMap { public: IHostMap() = default; - ~IHostMap() = default; - virtual void clear() = 0; - virtual inline uint16_t size() = 0; + ~IHostMap() = default; + + virtual void clear() = 0; + + virtual inline uint16_t size() = 0; - virtual void deleteOldRecordAndHosts(ur_time_t actualTime) = 0; - virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) = 0; + virtual void deleteOldRecordAndHosts(ur_time_t actualTime) = 0; + + virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) = 0; protected: template - void clearMap(Container *c) - { - auto it = c->begin(); - - while(it != c->end()) - { - if(it->second) // TODO harmless to remove this? - delete it->second; + void clearMap(Container *c) { + typename Container::iterator it = c->begin(); + while (it != c->end()) { + delete it->second; it++; } c->clear(); @@ -257,26 +265,22 @@ class IHostMap { * @param actualTime */ template - void clearOldRecAndHost(Container *c, ur_time_t actualTime) - { + void clearOldRecAndHost(Container *c, ur_time_t actualTime) { typename Container::iterator it = c->begin(); - // iterating over map (or RDPHost* or TELNETHost*) + // iterating over map (or RDPHost* or TELNETHost*) - while(it != c->end()) - { + while (it != c->end()) { it->second->clearOldRecords(actualTime); bool canDelete = it->second->canDeleteHost(actualTime); - if(canDelete) - { + if (canDelete) { delete it->second; c->erase(it++); } - else - { - it++; - } + else { + it++; + } } } }; @@ -285,72 +289,76 @@ class SSHHostMap : public IHostMap { public: SSHHostMap() = default; + ~SSHHostMap() = default; - void clear() override - { - IHostMap::clearMap(&hostMap); - } - inline uint16_t size() override - { + void clear() override { + IHostMap::clearMap(&hostMap); + } + + inline uint16_t size() override { return hostMap.size(); } SSHHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: - map hostMap; + map hostMap; }; -class RDPHostMap: public IHostMap { +class RDPHostMap : public IHostMap { public: RDPHostMap() = default; + ~RDPHostMap() = default; - void clear() override - { - IHostMap::clearMap(&hostMap); - } + void clear() override { + IHostMap::clearMap(&hostMap); + } - inline uint16_t size() override - { + inline uint16_t size() override { return hostMap.size(); } RDPHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: - map hostMap; + map hostMap; }; -class TELNETHostMap: public IHostMap { +class TELNETHostMap : public IHostMap { public: TELNETHostMap() = default; + ~TELNETHostMap() = default; - void clear() override - { - IHostMap::clearMap(&hostMap); + void clear() override { + IHostMap::clearMap(&hostMap); } - inline uint16_t size() override - { + inline uint16_t size() override { return hostMap.size(); } TELNETHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: - map hostMap; + map hostMap; }; #endif // HOST_H diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 4304e3b2..8744b749 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -48,62 +48,56 @@ // ************************ SSH RECORD ***********************/ // ************************************************************/ -SSHRecord::SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) -{ +SSHRecord::SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->dstIp = dstIp; this->flowLastSeen = flowLastSeen; } -bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; - if((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) - { - return false; - } + if ((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { + return false; + } - if(st.packets > Config::getInstance().getSSHIncMaxPackets() || st.packets < Config::getInstance().getSSHIncMinPackets()) - { - return false; - } + if (st.packets > Config::getInstance().getSSHIncMaxPackets() || + st.packets < Config::getInstance().getSSHIncMinPackets()) { + return false; + } - if(st.bytes > Config::getInstance().getSSHIncMaxBytes() || st.bytes < Config::getInstance().getSSHIncMinBytes()) - { - return false; - } + if (st.bytes > Config::getInstance().getSSHIncMaxBytes() || st.bytes < Config::getInstance().getSSHIncMinBytes()) { + return false; + } - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { + std::cerr << "w\n"; return false; } + signatureMatched = true; return true; } -bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); - if((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) - { - return false; - } + if ((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { + return false; + } - if(st.packets > Config::getInstance().getSSHOutMaxPackets() || st.packets < Config::getInstance().getSSHOutMinPackets()) - { - return false; - } + if (st.packets > Config::getInstance().getSSHOutMaxPackets() || + st.packets < Config::getInstance().getSSHOutMinPackets()) { + return false; + } - if(st.bytes > Config::getInstance().getSSHOutMaxBytes() || st.bytes < Config::getInstance().getSSHOutMinBytes()) - { - return false; - } + if (st.bytes > Config::getInstance().getSSHOutMaxBytes() || st.bytes < Config::getInstance().getSSHOutMinBytes()) { + return false; + } - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -117,30 +111,25 @@ bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) // ************************ RDP RECORD ***********************/ // ************************************************************/ -RDPRecord::RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) -{ +RDPRecord::RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->dstIp = dstIp; this->flowLastSeen = flowLastSeen; } -bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; // Win8 manual input - if((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) - { - // s port, d port, packets, bytes, flags + if ((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) { + // s port, d port, packets, bytes, flags // 42315, 3389, 8, 1691, 30 // 42345, 3389, 9, 1747, 30 - if(st.packets >= 7 && st.packets <= 11 && st.bytes >= 1500 && st.bytes <= 2000) - { - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if (st.packets >= 7 && st.packets <= 11 && st.bytes >= 1500 && st.bytes <= 2000) { + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { return false; } signatureMatched = true; @@ -150,15 +139,12 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) // Ncrack/thc hydra to win8 unsuccessful connection - if((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) - { - // s port, d port, packets, bytes, flags + if ((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { + // s port, d port, packets, bytes, flags // 37501, 3389, 3, 165, 26 - if(st.packets == 3 && ( st.bytes >= 100 && st.bytes <= 200)) - { - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if (st.packets == 3 && (st.bytes >= 100 && st.bytes <= 200)) { + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { return false; } signatureMatched = true; @@ -167,22 +153,19 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) } - if((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) - { - return false; - } + if ((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { + return false; + } - if(st.packets > Config::getInstance().getRDPIncMaxPackets() || st.packets < Config::getInstance().getRDPIncMinPackets()) - { - return false; - } - if(st.bytes > Config::getInstance().getRDPIncMaxBytes() || st.bytes < Config::getInstance().getRDPIncMinBytes()) - { - return false; - } + if (st.packets > Config::getInstance().getRDPIncMaxPackets() || + st.packets < Config::getInstance().getRDPIncMinPackets()) { + return false; + } + if (st.bytes > Config::getInstance().getRDPIncMaxBytes() || st.bytes < Config::getInstance().getRDPIncMinBytes()) { + return false; + } - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { return false; } @@ -190,23 +173,20 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return true; } -bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; // Win8 manual input - if((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) - { - // s port, d port, packets, bytes, flags + if ((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) { + // s port, d port, packets, bytes, flags // 3389, 42320, 7, 1882, 26 // 3389, 42303, 7, 1951, 26 - if(st.packets == 7 && st.bytes >= 1700 && st.bytes <= 2200) - { - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (st.packets == 7 && st.bytes >= 1700 && st.bytes <= 2200) { + if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -217,14 +197,12 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) // Ncrack/thc hydra to win8 unsuccessful connection - if((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) - { - // s port, d port, packets, bytes, flags + if ((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { + // s port, d port, packets, bytes, flags // 3389, 37639, 2, 92, 22 - if(st.packets == 2 && ( st.bytes > 80 && st.bytes < 120)) - { - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (st.packets == 2 && (st.bytes > 80 && st.bytes < 120)) { + if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -233,22 +211,20 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) } } - if((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) - { - return false; - } + if ((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { + return false; + } - if(st.packets > Config::getInstance().getRDPOutMaxPackets() || st.packets < Config::getInstance().getRDPOutMinPackets()) - { - return false; - } - if(st.bytes > Config::getInstance().getRDPOutMaxBytes() || st.bytes < Config::getInstance().getRDPOutMinBytes()) - { - return false; - } + if (st.packets > Config::getInstance().getRDPOutMaxPackets() || + st.packets < Config::getInstance().getRDPOutMinPackets()) { + return false; + } + if (st.bytes > Config::getInstance().getRDPOutMaxBytes() || st.bytes < Config::getInstance().getRDPOutMinBytes()) { + return false; + } - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -262,34 +238,30 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) // ********************** TELNET RECORD **********************/ // ************************************************************/ -TELNETRecord::TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) -{ +TELNETRecord::TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->dstIp = dstIp; this->flowLastSeen = flowLastSeen; } -bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; - if((st.flags & TELNETRecord::signatureFlags) != TELNETRecord::signatureFlags) - { - return false; - } - - if(st.packets > Config::getInstance().getTELNETIncMaxPackets() || st.packets < Config::getInstance().getTELNETIncMinPackets()) - { - return false; - } - if(st.bytes > Config::getInstance().getTELNETIncMaxBytes() || st.bytes < Config::getInstance().getTELNETIncMinBytes()) - { - return false; - } - - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if ((st.flags & TELNETRecord::signatureFlags) != TELNETRecord::signatureFlags) { + return false; + } + + if (st.packets > Config::getInstance().getTELNETIncMaxPackets() || + st.packets < Config::getInstance().getTELNETIncMinPackets()) { + return false; + } + if (st.bytes > Config::getInstance().getTELNETIncMaxBytes() || + st.bytes < Config::getInstance().getTELNETIncMinBytes()) { + return false; + } + + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { return false; } @@ -298,42 +270,35 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) } -bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; - if((st.flags & TELNETRecord::signatureFlagsFin) != TELNETRecord::signatureFlagsFin) - { + if ((st.flags & TELNETRecord::signatureFlagsFin) != TELNETRecord::signatureFlagsFin) { return false; - } + } - TelnetServerProfile * TSPProfile = TSPMap.findProfile(st.srcIp); - if(TSPProfile == nullptr) - { - TSPProfile = TSPMap.createProfile(st.srcIp, st.flowFirstSeen); - } + TelnetServerProfile *TSPProfile = TSPMap.findProfile(st.srcIp); + if (TSPProfile == NULL) { + TSPProfile = TSPMap.createProfile(st.srcIp, st.firstSeen); + } TSPProfile->profileWithNewData(st.packets, st.bytes); - if(st.packets < 6) // FIXME magic constant - { + if (st.packets < TELNET_OUTGOING_MIN_PACKETS) { return false; - } + } //for max range only - if(TSPProfile->isProfiled()) - { - if(st.packets > TSPProfile->getMaxPackets() || st.bytes > TSPProfile->getMaxBytes()) - { + if (TSPProfile->isProfiled()) { + if (st.packets > TSPProfile->getMaxPackets() || st.bytes > TSPProfile->getMaxBytes()) { return false; - } + } } - else - { + else { return false; - } + } signatureMatched = true; return true; diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index e922431b..5d7e4a01 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -61,10 +61,8 @@ // class TelnetServerProfileMap #include "telnet_server_profile.h" -// TODO find better place to put this as a global function -inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTime) -{ - return oldTime + timer <= newTime; +inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTime) { + return oldTime + timer <= newTime; } /** @@ -73,16 +71,19 @@ inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTim class IRecord { public: - IRecord () : signatureMatched(false) {} + IRecord() : signatureMatched(false) {} + virtual ~IRecord() = default; + virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl) = 0; + virtual bool matchWithOutgoingSignature(void *structure, Whitelist *wl) = 0; inline bool isMatched() { return signatureMatched; } + virtual ur_time_t getRecordTimeout() = 0; - struct MatchStructure - { + struct MatchStructure { uint8_t flags; uint32_t packets; uint64_t bytes; @@ -90,13 +91,13 @@ class IRecord { ip_addr_t dstIp; uint16_t srcPort; uint16_t dstPort; - ur_time_t flowFirstSeen; - ur_time_t flowLastSeen; + ur_time_t firstSeen; + ur_time_t lastSeen; }; // May seem unused, actually are passed to reporting functions - ip_addr_t dstIp{}; - ur_time_t flowLastSeen{}; + ip_addr_t dstIp{}; + ur_time_t flowLastSeen{}; protected: @@ -108,8 +109,11 @@ class SSHRecord : public IRecord { public: SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getSSHRecordTimeout(); } const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH @@ -120,11 +124,14 @@ class RDPRecord : public IRecord { public: RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } - const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; // SYN + ACK + PSH + RST const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; // SYN + ACK + PSH }; @@ -134,12 +141,15 @@ class TELNETRecord : public IRecord { public: TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getTELNETRecordTimeout(); } - const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH - const static uint8_t signatureFlagsFin = 0b00011011; // SYN + ACK + PSH + FIN + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH + const static uint8_t signatureFlagsFin = 0b00011011; // SYN + ACK + PSH + FIN private: static TelnetServerProfileMap TSPMap; @@ -150,29 +160,42 @@ class RecordList { public: RecordList(); + ~RecordList(); void addRecord(T record, bool isHostReported); + void setNewMaxListSize(uint16_t newMaxListSize); + void clearOldRecords(ur_time_t actualTime); + void clearAllRecords(); + ur_time_t getTimeOfLastRecord(); inline uint16_t getActualListSize() { return actualListSize; }; + inline uint16_t getActualMatchedFlows() { return actualMatchedFlows; } + inline uint32_t getMatchedFlowsSinceLastReport() { return matchedFlowsSinceLastReport; } + inline uint32_t getTotalFlowsSinceLastReport() { return totalFlowsSinceLastReport; } + inline void clearMatchedFlowsSinceLastReport() { matchedFlowsSinceLastReport = 0; } + inline void clearTotalFlowsSinceLastReport() { totalFlowsSinceLastReport = 0; } - inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } - inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } + inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } + + inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } + + inline uint16_t getCurrentTargets(); // TODO unused - inline uint16_t getCurrentTargets(); // TODO never used, investigate + inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } - inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } - inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } - inline void initTotalTargetsSet(); + inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } + + inline void initTotalTargetsSet(); std::vector getIpsOfVictims(); @@ -184,63 +207,54 @@ class RecordList { uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; - uint32_t flowCounter; - uint32_t flowMatchedCounter; + uint32_t flowCounter; + uint32_t flowMatchedCounter; - // These keep track of all IPs, even after the host becomes inactive, for output log - std::set hashedDstIPSet; - std::set hashedDstTotalIPSet; + // These keep track of all IPs, even after the host becomes inactive, for output log + std::set hashedDstIPSet; + std::set hashedDstTotalIPSet; char victimIP[46]{}; }; -template -RecordList::RecordList() -{ +template +RecordList::RecordList() { actualListSize = 0; actualMatchedFlows = 0; matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; - flowCounter = 0; - flowMatchedCounter = 0; - - if(typeid(T) == typeid(SSHRecord*)) - { - maxListSize = Config::getInstance().getSSHMaxListSize(); - } - else if(typeid(T) == typeid(RDPRecord*)) - { - maxListSize = Config::getInstance().getRDPMaxListSize(); - } - else if(typeid(T) == typeid(TELNETRecord*)) - { - maxListSize = Config::getInstance().getTELNETMaxListSize(); - } - else - { + flowCounter = 0; + flowMatchedCounter = 0; + + if (typeid(T) == typeid(SSHRecord *)) { + maxListSize = Config::getInstance().getSSHMaxRecords(); + } + else if (typeid(T) == typeid(RDPRecord *)) { + maxListSize = Config::getInstance().getRDPMaxRecords(); + } + else if (typeid(T) == typeid(TELNETRecord *)) { + maxListSize = Config::getInstance().getTELNETMaxRecords(); + } + else { std::cerr << "Error record.h: Max list size for class " << typeid(T).name() << " is not defined!\n"; std::terminate(); } } -template -RecordList::~RecordList() -{ - while(!list.empty()) - { +template +RecordList::~RecordList() { + while (!list.empty()) { T recToDel = list.front(); list.pop_front(); delete recToDel; } } -template -void RecordList::clearAllRecords() -{ - while(!list.empty()) - { +template +void RecordList::clearAllRecords() { + while (!list.empty()) { T recToDel = list.front(); list.pop_front(); delete recToDel; @@ -249,73 +263,62 @@ void RecordList::clearAllRecords() actualListSize = 0; actualMatchedFlows = 0; - flowCounter = 0; - flowMatchedCounter = 0; + flowCounter = 0; + flowMatchedCounter = 0; - matchedFlowsSinceLastReport = 0; + matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; } -template -void RecordList::addRecord(T record, bool isHostReported) -{ +template +void RecordList::addRecord(T record, bool isHostReported) { actualListSize++; - flowCounter++; + flowCounter++; - if(actualListSize > maxListSize) - { - // list is full + if (actualListSize > maxListSize) { + // list is full // delete first record - if((*list.begin())->isMatched()) - { - actualMatchedFlows--; - } + if ((*list.begin())->isMatched()) { + actualMatchedFlows--; + } T recToDelete = list.front(); delete recToDelete; list.pop_front(); actualListSize--; - // TODO Missing if(isHostReported) { totalFlowsSinceLastReport--; } ? } - if(record->isMatched()) - { + if (record->isMatched()) { actualMatchedFlows++; - flowMatchedCounter++; - } + flowMatchedCounter++; + } - if(isHostReported) - { + if (isHostReported) { totalFlowsSinceLastReport++; - if(record->isMatched()) - { + if (record->isMatched()) { matchedFlowsSinceLastReport++; - hashedDstIPSet.insert(record->dstIp); - hashedDstTotalIPSet.insert(record->dstIp); + hashedDstIPSet.insert(record->dstIp); + hashedDstTotalIPSet.insert(record->dstIp); } } list.push_back(record); } -template -void RecordList::setNewMaxListSize(uint16_t newMaxListSize) -{ +template +void RecordList::setNewMaxListSize(uint16_t newMaxListSize) { uint32_t currentMaxSize = maxListSize; - if (currentMaxSize > newMaxListSize) - { - while (actualListSize > newMaxListSize) - { + if (currentMaxSize > newMaxListSize) { + while (actualListSize > newMaxListSize) { // delete first record T recToDelete = list.front(); - if (recToDelete->isMatched()) - { - actualMatchedFlows--; - } + if (recToDelete->isMatched()) { + actualMatchedFlows--; + } delete recToDelete; list.pop_front(); @@ -331,27 +334,22 @@ void RecordList::setNewMaxListSize(uint16_t newMaxListSize) * @tparam T * @param actualTime */ -template -void RecordList::clearOldRecords(ur_time_t actualTime) -{ - if(list.empty()) - { - return; - } +template +void RecordList::clearOldRecords(ur_time_t actualTime) { + if (list.empty()) { + return; + } T rec = list.front(); ur_time_t timer = rec->getRecordTimeout(); typename std::list::iterator it = list.begin(); - while(it != list.end()) - { + while (it != list.end()) { ur_time_t flowTime = (*it)->flowLastSeen; - if (checkForTimeout(flowTime, timer, actualTime)) - { - if ((*it)->isMatched()) - { + if (checkForTimeout(flowTime, timer, actualTime)) { + if ((*it)->isMatched()) { actualMatchedFlows--; } @@ -360,64 +358,52 @@ void RecordList::clearOldRecords(ur_time_t actualTime) delete *it; list.erase(it++); } - else - { - break; - } + else { + break; + } } } -template -ur_time_t RecordList::getTimeOfLastRecord() -{ - if(!list.empty()) - { - return list.back()->flowLastSeen; - } - else - { - return 0; - } +template +ur_time_t RecordList::getTimeOfLastRecord() { + if (!list.empty()) { + return list.back()->flowLastSeen; + } + else { + return 0; + } } template -uint16_t RecordList::getCurrentTargets() -{ - std::set dstIpSet; - for(const auto & it : list) - { - if(it->isMatched()) - { - dstIpSet.insert(it->dstIp); - } - } - return dstIpSet.size(); +uint16_t RecordList::getCurrentTargets() { + std::set dstIpSet; + for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) + { + if ((*it).isMatched()) { + dstIpSet.insert((*it)->dstIp); + } + } + return dstIpSet.size(); } template -void RecordList::initTotalTargetsSet() -{ - for(const auto & it : list) - { - if(it->isMatched()) - { - // TODO Why is TotalIPSet filled with matched flows only? - hashedDstTotalIPSet.insert(it->dstIp); - } - } -} +void RecordList::initTotalTargetsSet() { + for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) + if ((*it)->isMatched()) { + hashedDstTotalIPSet.insert((*it)->dstIp); + } + } + template -std::vector RecordList::getIpsOfVictims() -{ +std::vector RecordList::getIpsOfVictims() { std::vector tmpIpsOfVictims; - for(const auto& it : list) + for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) { - if(it->isMatched()) - { - ip_to_str(&(it->dstIp), victimIP); + if ((*it)->isMatched()) { + ip_to_str(&((*it)->dstIp), victimIP); tmpIpsOfVictims.push_back(std::string(victimIP)); } diff --git a/brute_force_detector/sender.cpp b/brute_force_detector/sender.cpp index 8d4553fb..7c0f7582 100644 --- a/brute_force_detector/sender.cpp +++ b/brute_force_detector/sender.cpp @@ -45,35 +45,37 @@ #include "sender.h" UR_FIELDS( - time DETECTION_TIME, // Timestamp of the detection of some event - uint8 WARDEN_TYPE, // Type of event (see Warden README for more information) - ipaddr SRC_IP, // Source address of a flow - uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) - uint16 DST_PORT, // Destination transport-layer port - uint32 EVENT_SCALE, // Attack intensity - string NOTE, // Generic string note + time + DETECTION_TIME, // Timestamp of the detection of some event + uint8 + WARDEN_TYPE, // Type of event (see Warden README for more information) + ipaddr + SRC_IP, // Source address of a flow + uint8 + PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint16 + DST_PORT, // Destination transport-layer port + uint32 + EVENT_SCALE, // Attack intensity + string NOTE, // Generic string note ) -Sender::Sender(bool *success) -{ +Sender::Sender(bool *success) { std::string unirecSpecifier = "DETECTION_TIME,WARDEN_TYPE,SRC_IP,PROTOCOL,DST_PORT,EVENT_SCALE,NOTE"; - outTemplate = ur_create_output_template(0, unirecSpecifier.c_str(), nullptr); - if(outTemplate == nullptr) - { + outTemplate = ur_create_output_template(0, unirecSpecifier.c_str(), NULL); + if (outTemplate == NULL) { *success = false; return; } *success = true; } -Sender::~Sender() -{ - if(outTemplate != nullptr) - { - ur_free_template (outTemplate); - } +Sender::~Sender() { + if (outTemplate != NULL) { + ur_free_template(outTemplate); + } } diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index 66522eb9..963c2134 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -64,6 +64,7 @@ extern "C" { #endif // __cplusplus #include + using namespace std; // WARDEN_TYPE @@ -72,45 +73,41 @@ using namespace std; /** * @desc Class for handling output messages */ -class Sender -{ +class Sender { public: explicit Sender(bool *success); + ~Sender(); - template - int firstReport(Host *host, uint16_t dstPort, ur_time_t actualTime, uint16_t detectionThreshold) - { - if(Config::getInstance().getGlobalIgnoreFirstSend()) - { - // Ignore first report + template + int firstReport(Host *host, uint16_t dstPort, ur_time_t actualTime, uint16_t detectionThreshold) { + if (Config::getInstance().getGlobalIgnoreFirstSend()) { + // Ignore first report host->setReportTime(actualTime); return TRAP_E_OK; } - //TODO test if output correct - uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); - uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); + uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); + uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); - string sNote; + string sNote; - return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), false, sNote); + return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), false, sNote); } - template - int continuingReport(Host *host, uint16_t dstPort, ur_time_t actualTime, bool endOfAttack = false) - { + template + int continuingReport(Host *host, uint16_t dstPort, ur_time_t actualTime, bool endOfAttack = false) { uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); string sNote; - host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); - host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToIncomingRecordList()->clearTotalFlowsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToOutgoingRecordList()->clearTotalFlowsSinceLastReport(); return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), endOfAttack, sNote); @@ -119,9 +116,9 @@ class Sender private: ur_template_t *outTemplate; - template - int send(Host *host, uint16_t dstPort, ur_time_t actualTime, uint32_t intensity, bool endOfAttack = false, const string& stringNote = string()) - { + template + int send(Host *host, uint16_t dstPort, ur_time_t actualTime, uint32_t intensity, bool endOfAttack = false, + const string &stringNote = string()) { vector incIpsVictims = host->getPointerToIncomingRecordList()->getIpsOfVictims(); vector outIpsVictims = host->getPointerToOutgoingRecordList()->getIpsOfVictims(); string note; @@ -134,20 +131,20 @@ class Sender // Incoming note.append("I:"); - for (const auto & incIpsVictim : incIpsVictims) { - note.append(incIpsVictim); + for (unsigned long i = 0; i < incIpsVictims.size(); i++) { + note.append(incIpsVictims.at(i)); note.append(","); } - // Outgoing + //Outgoing note.append("O:"); - for (const auto & outIpsVictim : outIpsVictims) { - note.append(outIpsVictim); + for (unsigned long i = 0; i < outIpsVictims.size(); i++) { + note.append(outIpsVictims.at(i)); note.append(","); } - note.erase(note.length(),1); + note.erase(note.length(), 1); - // get size of note + // get size of note uint16_t noteSize = note.size() + 1; // plus '\0' void *rec = ur_create_record(outTemplate, noteSize); diff --git a/brute_force_detector/telnet_server_profile.cpp b/brute_force_detector/telnet_server_profile.cpp index c78f75d4..bee78182 100644 --- a/brute_force_detector/telnet_server_profile.cpp +++ b/brute_force_detector/telnet_server_profile.cpp @@ -43,11 +43,12 @@ */ #include "telnet_server_profile.h" + using namespace std; + #include -void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) -{ +void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) { // at least 6 packets from server to client // 1. syn+ack // 2. supported configuration @@ -57,14 +58,14 @@ void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) // 4/6. ack password // 5/7. information about successfull/failed login // 6/8. FIN packet - if(packets < 6) // FIXME magic constant + if (packets < TELNET_OUTGOING_MIN_PACKETS) { return; + } static uint16_t profileCounter = 0; profileCounter++; - if(listSize >= TSPArraySize) - { + if (listSize >= TSPArraySize) { byteList.pop_front(); packetList.pop_front(); listSize--; @@ -74,57 +75,47 @@ void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) packetList.push_back(packets); listSize++; - if(!profiled && listSize == TSPArraySize) - { + if (!profiled && listSize == TSPArraySize) { countNewMaxValues(); profiled = true; } - else if(profiled && profileCounter == profileEvery) - { + else if (profiled && profileCounter == profileEvery) { countNewMaxValues(); profileCounter = 0; } } -void TelnetServerProfile::countNewMaxValues() -{ +void TelnetServerProfile::countNewMaxValues() { size_t n = packetList.size() / 2; vector packetVector; vector byteVector; copy(packetList.begin(), packetList.end(), back_inserter(packetVector)); - copy(byteList.begin(), byteList.end(), back_inserter(byteVector)); + copy(byteList.begin(), byteList.end(), back_inserter(byteVector)); // median - nth_element(byteVector.begin(), byteVector.begin() + n, byteVector.end()); + nth_element(byteVector.begin(), byteVector.begin() + n, byteVector.end()); nth_element(packetVector.begin(), packetVector.begin() + n, packetVector.end()); maxPackets = packetVector[n] + 5; - maxBytes = byteVector[n] + 500; - - // char *c = new char[55]; - // ip_to_str(&serverIp,c); - // std::cout<<"Profilovano "<(ip, TSP)); + TSPMap.insert(std::pair(ip, TSP)); return TSP; } -TelnetServerProfile * TelnetServerProfileMap::findProfile(ip_addr_t & hostIp) const -{ - auto it = TSPMap.find(hostIp); - if(it == TSPMap.end()) - { - return nullptr; - } +TelnetServerProfile *TelnetServerProfileMap::findProfile(ip_addr_t &hostIp) const { + std::map::const_iterator it = TSPMap.find(hostIp); + if (it == TSPMap.end()) { + return NULL; + } return it->second; } diff --git a/brute_force_detector/telnet_server_profile.h b/brute_force_detector/telnet_server_profile.h index 9761fdde..145ee74a 100644 --- a/brute_force_detector/telnet_server_profile.h +++ b/brute_force_detector/telnet_server_profile.h @@ -45,7 +45,6 @@ #ifndef TELNET_SERVER_PROFILE_H #define TELNET_SERVER_PROFILE_H -//#include "record.h" #include "brute_force_detector.h" #include //ip_addr_t #include //ur_time_t @@ -58,40 +57,46 @@ const static uint16_t TSPArraySize = 15; const static uint8_t profileEvery = 10; -class TelnetServerProfile -{ -public: +class TelnetServerProfile { +public: TelnetServerProfile(ur_time_t firstSeen, ip_addr_t ip) : timeOfCreation(firstSeen), serverIp(ip), profiled(false), listSize(0), maxBytes(0), maxPackets(0) {} - bool isProfiled() const {return profiled;} + + bool isProfiled() const { return profiled; } + uint32_t getMaxPackets() const { return maxPackets; } + uint64_t getMaxBytes() const { return maxBytes; } + void profileWithNewData(uint32_t packets, uint64_t bytes); - - + + + private: ur_time_t timeOfCreation; ip_addr_t serverIp; bool profiled; - + std::list byteList; std::list packetList; uint16_t listSize; - + uint64_t maxBytes; uint32_t maxPackets; - void countNewMaxValues(); + + void countNewMaxValues(); }; -class TelnetServerProfileMap -{ +class TelnetServerProfileMap { public: TelnetServerProfileMap() {}; - TelnetServerProfile * createProfile(ip_addr_t ip, ur_time_t firstSeen); - TelnetServerProfile * findProfile(ip_addr_t & hostIp) const; - + + TelnetServerProfile *createProfile(ip_addr_t ip, ur_time_t firstSeen); + + TelnetServerProfile *findProfile(ip_addr_t &hostIp) const; + private: - std::map TSPMap; + std::map TSPMap; }; -#endif +#endif diff --git a/brute_force_detector/whitelist.cpp b/brute_force_detector/whitelist.cpp index f797b4b4..539ed59b 100644 --- a/brute_force_detector/whitelist.cpp +++ b/brute_force_detector/whitelist.cpp @@ -52,66 +52,59 @@ using namespace std; // ********************* WHITELISTEDPORTS ********************/ // ************************************************************/ -WhitelistedPorts::WhitelistedPorts() -{ +WhitelistedPorts::WhitelistedPorts() { } -bool WhitelistedPorts::findPort(uint16_t port) -{ - return inRange(portRangeList, port); +bool WhitelistedPorts::findPort(uint16_t port) { + return inRange(portRangeList, port); } -void WhitelistedPorts::addPortRange(uint16_t from, uint16_t to) -{ - portRangeList.insert(Range(from, to)); +void WhitelistedPorts::addPortRange(uint16_t from, uint16_t to) { + portRangeList.insert(Range(from, to)); } -void WhitelistedPorts::addSinglePort(uint16_t port) -{ - addPortRange(port, port); +void WhitelistedPorts::addSinglePort(uint16_t port) { + addPortRange(port, port); } // ************************************************************/ // ************************ IPTRIE ***************************/ // ************************************************************/ -IPTrie::IPTrie() -{ - left = NULL; - right = NULL; - allPorts = false; - set = false; - whitelistedPorts = NULL; +IPTrie::IPTrie() { + left = NULL; + right = NULL; + allPorts = false; + set = false; + whitelistedPorts = NULL; } -IPTrie::~IPTrie() -{ - if (left != NULL) { - delete left; - } +IPTrie::~IPTrie() { + if (left != NULL) { + delete left; + } - if (right != NULL) { - delete right; - } + if (right != NULL) { + delete right; + } - if (whitelistedPorts != NULL) { - delete whitelistedPorts; - } + if (whitelistedPorts != NULL) { + delete whitelistedPorts; + } } // ************************************************************/ // ******************** WHITELISTPARSER **********************/ // ************************************************************/ -void WhitelistParser::init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IPTrie *ipv6Dst) -{ - this->ipv4Src = ipv4Src; - this->ipv4Dst = ipv4Dst; - this->ipv6Src = ipv6Src; - this->ipv6Dst = ipv6Dst; +void WhitelistParser::init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IPTrie *ipv6Dst) { + this->ipv4Src = ipv4Src; + this->ipv4Dst = ipv4Dst; + this->ipv6Src = ipv6Src; + this->ipv6Dst = ipv6Dst; - rulesCounter = 0; + rulesCounter = 0; } @@ -120,410 +113,420 @@ void WhitelistParser::init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IP // ************************************************************/ -Whitelist::Whitelist() -{ - locked = false; - wlFileName = NULL; +Whitelist::Whitelist() { + locked = false; + wlFileName = NULL; - ipv4Src = new IPTrie(); - ipv4Dst = new IPTrie(); - ipv6Src = new IPTrie(); - ipv6Dst = new IPTrie(); + ipv4Src = new IPTrie(); + ipv4Dst = new IPTrie(); + ipv6Src = new IPTrie(); + ipv6Dst = new IPTrie(); - parser.init(ipv4Src, ipv4Dst, ipv6Src, ipv6Dst); + parser.init(ipv4Src, ipv4Dst, ipv6Src, ipv6Dst); } -Whitelist::~Whitelist() -{ - delete ipv4Src; - delete ipv4Dst; - delete ipv6Src; - delete ipv6Dst; +Whitelist::~Whitelist() { + delete ipv4Src; + delete ipv4Dst; + delete ipv6Src; + delete ipv6Dst; } -bool Whitelist::init(char *fileName, bool verbose) -{ - wlFileName = fileName; - ifstream ifs; - ifs.open(fileName, ifstream::in); - if (!ifs.is_open()) { - return false; - } +bool Whitelist::init(char *fileName, bool verbose) { + wlFileName = fileName; + ifstream ifs; + ifs.open(fileName, ifstream::in); + if (!ifs.is_open()) { + return false; + } - parser.parse(&ifs, verbose); - ifs.close(); + parser.parse(&ifs, verbose); + ifs.close(); - return true; + return true; } -bool Whitelist::isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, uint16_t srcPort, uint16_t dstPort) -{ - locked = true; - bool found = false; - - if (ip_is4(srcIp)) { - // ipv4 - // check src addr first - found = trieSearch(ipv4Src, (uint8_t*) srcIp + 8, 4, srcPort); - if (found) { - locked = false; - return true; - } - - found = trieSearch(ipv4Dst, (uint8_t*) dstIp + 8, 4, dstPort); - if (found) { - locked = false; - return true; - } - } else { // ipv6 - // check src addr first - found = trieSearch(ipv6Src, (uint8_t*) srcIp, 6, srcPort); - if (found) { - locked = false; - return true; - } - - // check dst addr - found = trieSearch(ipv6Dst, (uint8_t*) dstIp, 6, dstPort); - if (found) { - locked = false; - return true; - } - } - - locked = false; - return false; +bool Whitelist::isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, uint16_t srcPort, uint16_t dstPort) { + locked = true; + bool found = false; + + if (ip_is4(srcIp)) { + // ipv4 + // check src addr first + found = trieSearch(ipv4Src, (uint8_t *) srcIp + 8, 4, srcPort); + if (found) { + locked = false; + return true; + } + + found = trieSearch(ipv4Dst, (uint8_t *) dstIp + 8, 4, dstPort); + if (found) { + locked = false; + return true; + } + } + else { // ipv6 + // check src addr first + found = trieSearch(ipv6Src, (uint8_t *) srcIp, 6, srcPort); + if (found) { + locked = false; + return true; + } + + // check dst addr + found = trieSearch(ipv6Dst, (uint8_t *) dstIp, 6, dstPort); + if (found) { + locked = false; + return true; + } + } + + locked = false; + return false; } -bool Whitelist::trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t port) -{ - IPTrie *currentNode = ipTrie; - int iRange = (ipType == 4) ? 32 : 128; - - for (int i = 0; i < iRange; i++) { - for (int u = 7; u >= 0; u--) { - // change last known node - if (currentNode->set) { - // vsechny porty - if (currentNode->allPorts) { - return true; +bool Whitelist::trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t port) { + IPTrie *currentNode = ipTrie; + int iRange = (ipType == 4) ? 32 : 128; + + for (int i = 0; i < iRange; i++) { + for (int u = 7; u >= 0; u--) { + // change last known node + if (currentNode->set) { + // vsechny porty + if (currentNode->allPorts) { + return true; + } + if (currentNode->whitelistedPorts != NULL) { + if ((currentNode->whitelistedPorts->findPort(port)) == true) { + return true; + } + } } - if (currentNode->whitelistedPorts != NULL) { - if ((currentNode->whitelistedPorts->findPort(port)) == true) { - return true; - } - } - } - // search right - if (((ip[i] >> u) & 1) > 0) { - currentNode = currentNode->right; - } else { // search left - currentNode = currentNode->left; - } + // search right + if (((ip[i] >> u) & 1) > 0) { + currentNode = currentNode->right; + } + else { // search left + currentNode = currentNode->left; + } - if (currentNode == NULL) { - return false; - } - } - } + if (currentNode == NULL) { + return false; + } + } + } - return false; + return false; } -void Whitelist::reloadWhitelist() -{ - if (wlFileName != NULL) { - ifstream ifs; - ifs.open(wlFileName, ifstream::in); - if (!ifs.is_open()) { - cerr << "Error Whitelist: Cannot open whitelist file!\n"; - return; - } - - delete ipv4Src; - delete ipv4Dst; - delete ipv6Src; - delete ipv6Dst; - - ipv4Src = new IPTrie(); - ipv4Dst = new IPTrie(); - ipv6Src = new IPTrie(); - ipv6Dst = new IPTrie(); - - parser.init(ipv4Src, ipv4Dst, ipv6Src, ipv6Dst); - parser.parse(&ifs, false); - - ifs.close(); - - cout << "Whitelist: Whitelist reloaded successfully.\n"; - } else { - cerr << "Error Whitelist: Whitelist path is not set!\n"; - } +void Whitelist::reloadWhitelist() { + if (wlFileName != NULL) { + ifstream ifs; + ifs.open(wlFileName, ifstream::in); + if (!ifs.is_open()) { + cerr << "Error Whitelist: Cannot open whitelist file!\n"; + return; + } + + delete ipv4Src; + delete ipv4Dst; + delete ipv6Src; + delete ipv6Dst; + + ipv4Src = new IPTrie(); + ipv4Dst = new IPTrie(); + ipv6Src = new IPTrie(); + ipv6Dst = new IPTrie(); + + parser.init(ipv4Src, ipv4Dst, ipv6Src, ipv6Dst); + parser.parse(&ifs, false); + + ifs.close(); + + cout << "Whitelist: Whitelist reloaded successfully.\n"; + } + else { + cerr << "Error Whitelist: Whitelist path is not set!\n"; + } } // ************************************************************/ // ********************* WHITELIST PARSER *********************/ // ************************************************************/ -void WhitelistParser::parse(ifstream *ifs, bool verboseMode) -{ - static bool verbose = verboseMode; - this->verbose = verbose; - string line; - uint8_t direction; - - if (verbose) { - cout << "Parsing whitelist file...\n"; - } - - while (std::getline((*ifs), line).good()) { - if (line.empty()) { - continue; - } - - if (line[0] == WHITELIST_PARSER_COMMENT_DELIM) { // skip comment line - continue; - } - - // substring before comment delim if exists - size_t pos = line.find_first_of(WHITELIST_PARSER_COMMENT_DELIM); - if (pos != string::npos) { - line = line.substr(0, pos); - } - - // now check for src or dst direction - if (line.size() < 4) { - if(verbose) { - cout << "Invalid line: " << line << endl; - } - - continue; - } - - string sDirection = line.substr(0, 3); - - if (sDirection == WHITELIST_PARSER_IP_DIRECTION_KEYWORD_SRC) { - direction = WHITELIST_PARSER_IP_DIRECTION_SRC; - line = line.substr(4); - } else if (sDirection == WHITELIST_PARSER_IP_DIRECTION_KEYWORD_DST) { - direction = WHITELIST_PARSER_IP_DIRECTION_DST; - line = line.substr(4); - } else { - direction = WHITELIST_PARSER_IP_DIRECTION_ALL; - } - - // now ip check parse - pos = line.find_first_of(WHITELIST_PARSER_PREFIX_DELIM); - if (pos != string::npos) { - string ipstring = line.substr(0, pos); - ip_addr_t ip; - if (ip_from_str(ipstring.c_str(), &ip)) { - // ip ok, now parse prefix and ports - string prefixAndPorts = line.substr(pos + 1); - if (!prefixAndPorts.empty()) { - if (verbose) { - cout << "IP: " << ipstring << endl; - } - - pos = prefixAndPorts.find_first_of(WHITELIST_PARSER_PORTS_DELIM); - string ports = string(); - if (pos != string::npos) { - string prefixStr = prefixAndPorts.substr(0, pos); - int prefix = atoi(prefixStr.c_str()); - // get ports now - ports = prefixAndPorts.substr(pos + 1); - if (ports.empty()) { - if (verbose) { - cout << "Invalid line: " << line << endl; - } - } else { - if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { - if (verbose) { - cout << "Invalid line: " << line << endl; +void WhitelistParser::parse(ifstream *ifs, bool verboseMode) { + static bool verbose = verboseMode; + this->verbose = verbose; + string line; + uint8_t direction; + + if (verbose) { + cout << "Parsing whitelist file...\n"; + } + + while (std::getline((*ifs), line).good()) { + if (line.empty()) { + continue; + } + + if (line[0] == WHITELIST_PARSER_COMMENT_DELIM) { // skip comment line + continue; + } + + // substring before comment delim if exists + size_t pos = line.find_first_of(WHITELIST_PARSER_COMMENT_DELIM); + if (pos != string::npos) { + line = line.substr(0, pos); + } + + // now check for src or dst direction + if (line.size() < 4) { + if (verbose) { + cout << "Invalid line: " << line << endl; + } + + continue; + } + + string sDirection = line.substr(0, 3); + + if (sDirection == WHITELIST_PARSER_IP_DIRECTION_KEYWORD_SRC) { + direction = WHITELIST_PARSER_IP_DIRECTION_SRC; + line = line.substr(4); + } + else if (sDirection == WHITELIST_PARSER_IP_DIRECTION_KEYWORD_DST) { + direction = WHITELIST_PARSER_IP_DIRECTION_DST; + line = line.substr(4); + } + else { + direction = WHITELIST_PARSER_IP_DIRECTION_ALL; + } + + // now ip check parse + pos = line.find_first_of(WHITELIST_PARSER_PREFIX_DELIM); + if (pos != string::npos) { + string ipstring = line.substr(0, pos); + ip_addr_t ip; + if (ip_from_str(ipstring.c_str(), &ip)) { + // ip ok, now parse prefix and ports + string prefixAndPorts = line.substr(pos + 1); + if (!prefixAndPorts.empty()) { + if (verbose) { + cout << "IP: " << ipstring << endl; + } + + pos = prefixAndPorts.find_first_of(WHITELIST_PARSER_PORTS_DELIM); + string ports = string(); + if (pos != string::npos) { + string prefixStr = prefixAndPorts.substr(0, pos); + int prefix = atoi(prefixStr.c_str()); + // get ports now + ports = prefixAndPorts.substr(pos + 1); + if (ports.empty()) { + if (verbose) { + cout << "Invalid line: " << line << endl; + } + } + else { + if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { + if (verbose) { + cout << "Invalid line: " << line << endl; + } + } } - } - } - } else { // ??? mtva vezev? - int prefix = atoi(prefixAndPorts.c_str()); - if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { - if (verbose) { - cout << "Invalid line: " << line << endl; - } - } - } - } else if (verbose) { - cout << "Invalid line: " << line << endl; + } + else { // ??? mtva vezev? + int prefix = atoi(prefixAndPorts.c_str()); + if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { + if (verbose) { + cout << "Invalid line: " << line << endl; + } + } + } + } + else if (verbose) { + cout << "Invalid line: " << line << endl; + } + } + else if (verbose) { // invalid ip + cout << "Invalid line: " << line << endl; } - } else if (verbose) { // invalid ip + } + else if (verbose) { cout << "Invalid line: " << line << endl; - } - } else if (verbose) { - cout << "Invalid line: " << line << endl; - } - } - - if (verbose) { - cout << "Total rules added: " << rulesCounter << endl; - cout << "Parsing whitelist file done" << endl; - } + } + } + + if (verbose) { + cout << "Total rules added: " << rulesCounter << endl; + cout << "Parsing whitelist file done" << endl; + } } -bool WhitelistParser::checkPrefixAndPortsAndAdd(ip_addr_t &addr, uint8_t direction, uint8_t prefix, string &ports) -{ - bool ipv4 = ip_is4(&addr); - if ((ipv4 && prefix > 32) || (!ipv4 && prefix > 128)) { - return false; - } +bool WhitelistParser::checkPrefixAndPortsAndAdd(ip_addr_t &addr, uint8_t direction, uint8_t prefix, string &ports) { + bool ipv4 = ip_is4(&addr); + if ((ipv4 && prefix > 32) || (!ipv4 && prefix > 128)) { + return false; + } - prepareAddIPAndPorts(addr, direction, prefix, ports); - return true; + prepareAddIPAndPorts(addr, direction, prefix, ports); + return true; } -void WhitelistParser::prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, uint8_t prefix, string &ports) -{ - if (ip_is4(&addr)) { - if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { - addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Src, ports); - addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Dst, ports); - } else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { - addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Src, ports); - } else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST - addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Dst, ports); - } - } else { // ipv6 - if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { - addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Src, ports); - addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Dst, ports); - } else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { - addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Src, ports); - } else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST - addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Dst, ports); - } - } +void WhitelistParser::prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, uint8_t prefix, string &ports) { + if (ip_is4(&addr)) { + if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { + addIPAndSelectedPorts((uint8_t *) &addr + 8, prefix, ipv4Src, ports); + addIPAndSelectedPorts((uint8_t *) &addr + 8, prefix, ipv4Dst, ports); + } + else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { + addIPAndSelectedPorts((uint8_t *) &addr + 8, prefix, ipv4Src, ports); + } + else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST + addIPAndSelectedPorts((uint8_t *) &addr + 8, prefix, ipv4Dst, ports); + } + } + else { // ipv6 + if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { + addIPAndSelectedPorts((uint8_t *) &addr, prefix, ipv6Src, ports); + addIPAndSelectedPorts((uint8_t *) &addr, prefix, ipv6Dst, ports); + } + else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { + addIPAndSelectedPorts((uint8_t *) &addr, prefix, ipv6Src, ports); + } + else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST + addIPAndSelectedPorts((uint8_t *) &addr, prefix, ipv6Dst, ports); + } + } } -void WhitelistParser::addPorts(IPTrie *currentNode, string ports) -{ - WhitelistedPorts *whitelistedPorts = currentNode->whitelistedPorts; - - if(ports.empty()) { - return; - } - - size_t pos; - pos = ports.find_first_of(WHITELIST_PARSER_NEXT_PORT_DELIM); - if (pos != string::npos) { - string portString = ports.substr(0, pos); - ports = ports.substr(pos + 1); - - pos = portString.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); - if (pos != string::npos) { // range - string firstStringPort = portString.substr(0, pos); - string secondStringPort = portString.substr(pos + 1); - if (secondStringPort.empty()) { - if(verbose) { - cout << "Invalid ports range: " << portString << endl; +void WhitelistParser::addPorts(IPTrie *currentNode, string ports) { + WhitelistedPorts *whitelistedPorts = currentNode->whitelistedPorts; + + if (ports.empty()) { + return; + } + + size_t pos; + pos = ports.find_first_of(WHITELIST_PARSER_NEXT_PORT_DELIM); + if (pos != string::npos) { + string portString = ports.substr(0, pos); + ports = ports.substr(pos + 1); + + pos = portString.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); + if (pos != string::npos) { // range + string firstStringPort = portString.substr(0, pos); + string secondStringPort = portString.substr(pos + 1); + if (secondStringPort.empty()) { + if (verbose) { + cout << "Invalid ports range: " << portString << endl; + } + + return; } - return; - } - - uint16_t port = atoi(firstStringPort.c_str()); - uint16_t port2 = atoi(secondStringPort.c_str()); - - whitelistedPorts->addPortRange(port, port2); - rulesCounter++; - if (verbose) { - cout << "Adding port range " << portString << endl; - } - } else { // single port - uint16_t port = atoi(portString.c_str()); - whitelistedPorts->addSinglePort(port); - if(verbose) { - cout << "Adding single port " << port << endl; - } - } - - addPorts(currentNode, ports); - } else { - pos = ports.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); - if (pos != string::npos) { // range - string firstStringPort = ports.substr(0, pos); - string secondStringPort = ports.substr(pos + 1); - if (secondStringPort.empty()) { + uint16_t port = atoi(firstStringPort.c_str()); + uint16_t port2 = atoi(secondStringPort.c_str()); + + whitelistedPorts->addPortRange(port, port2); + rulesCounter++; if (verbose) { - cout << "Invalid ports range: " << ports << endl; + cout << "Adding port range " << portString << endl; + } + } + else { // single port + uint16_t port = atoi(portString.c_str()); + whitelistedPorts->addSinglePort(port); + if (verbose) { + cout << "Adding single port " << port << endl; + } + } + + addPorts(currentNode, ports); + } + else { + pos = ports.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); + if (pos != string::npos) { // range + string firstStringPort = ports.substr(0, pos); + string secondStringPort = ports.substr(pos + 1); + if (secondStringPort.empty()) { + if (verbose) { + cout << "Invalid ports range: " << ports << endl; + } + + addPorts(currentNode, ports); + return; } - addPorts(currentNode, ports); - return; - } - - uint16_t port = atoi(firstStringPort.c_str()); - uint16_t port2 = atoi(secondStringPort.c_str()); - - whitelistedPorts->addPortRange(port, port2); - rulesCounter++; - if (verbose) { - cout << "Adding port range " << ports << endl; - } - } else { // single port - uint16_t port = atoi(ports.c_str()); - whitelistedPorts->addSinglePort(port); - if (verbose) { - cout << "Adding single port " << port << endl; - } - } - } + uint16_t port = atoi(firstStringPort.c_str()); + uint16_t port2 = atoi(secondStringPort.c_str()); + + whitelistedPorts->addPortRange(port, port2); + rulesCounter++; + if (verbose) { + cout << "Adding port range " << ports << endl; + } + } + else { // single port + uint16_t port = atoi(ports.c_str()); + whitelistedPorts->addSinglePort(port); + if (verbose) { + cout << "Adding single port " << port << endl; + } + } + } } -void WhitelistParser::addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie *trie, string ports) -{ - IPTrie *currentNode = trie; - for (int i = 0; i < prefix; i++) { +void WhitelistParser::addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie *trie, string ports) { + IPTrie *currentNode = trie; + for (int i = 0; i < prefix; i++) { // bitset go right - if (((ip[i / 8] >> (7 - i % 8)) & 1) > 0) { - if (currentNode->right == NULL) { - currentNode->right = new IPTrie(); - } - // next - currentNode = currentNode->right; - } else { // go left - if (currentNode->left == NULL) { - currentNode->left = new IPTrie(); - } - // next - currentNode = currentNode->left; - } - - if ((i + 1) == prefix) { // last pos - if(currentNode->whitelistedPorts == NULL) { + if (((ip[i / 8] >> (7 - i % 8)) & 1) > 0) { + if (currentNode->right == NULL) { + currentNode->right = new IPTrie(); + } + // next + currentNode = currentNode->right; + } + else { // go left + if (currentNode->left == NULL) { + currentNode->left = new IPTrie(); + } + // next + currentNode = currentNode->left; + } + + if ((i + 1) == prefix) { // last pos + if (currentNode->whitelistedPorts == NULL) { + currentNode->whitelistedPorts = new WhitelistedPorts; + } + + if (ports.empty()) { + currentNode->allPorts = true; + } + else { + addPorts(currentNode, ports); + } + + currentNode->set = true; + rulesCounter++; + } + } + // prefix 0 + if (prefix == 0) { + if (currentNode->whitelistedPorts == NULL) { currentNode->whitelistedPorts = new WhitelistedPorts; - } + } - if (ports.empty()) { + if (ports.empty()) { currentNode->allPorts = true; - } else { + } + else { addPorts(currentNode, ports); - } - - currentNode->set = true; - rulesCounter++; - } - } - // prefix 0 - if (prefix == 0) { - if (currentNode->whitelistedPorts == NULL) { - currentNode->whitelistedPorts = new WhitelistedPorts; - } - - if (ports.empty()) { - currentNode->allPorts = true; - } else { - addPorts(currentNode, ports); - } - - currentNode->set = true; - rulesCounter++; - } + } + + currentNode->set = true; + rulesCounter++; + } } diff --git a/brute_force_detector/whitelist.h b/brute_force_detector/whitelist.h index f8483e21..ff201cd4 100644 --- a/brute_force_detector/whitelist.h +++ b/brute_force_detector/whitelist.h @@ -48,11 +48,11 @@ #include #include -#include +#include #include #include #include -#include +#include //WHITELIST PARSER VARIABLES @@ -63,10 +63,10 @@ const static uint8_t WHITELIST_PARSER_IP_DIRECTION_ALL = 0; const static uint8_t WHITELIST_PARSER_IP_DIRECTION_SRC = 1; const static uint8_t WHITELIST_PARSER_IP_DIRECTION_DST = 2; -const static uint8_t WHITELIST_PARSER_COMMENT_DELIM = '#'; -const static uint8_t WHITELIST_PARSER_PREFIX_DELIM = '/'; -const static uint8_t WHITELIST_PARSER_PORTS_DELIM = '/'; -const static uint8_t WHITELIST_PARSER_NEXT_PORT_DELIM = ','; +const static uint8_t WHITELIST_PARSER_COMMENT_DELIM = '#'; +const static uint8_t WHITELIST_PARSER_PREFIX_DELIM = '/'; +const static uint8_t WHITELIST_PARSER_PORTS_DELIM = '/'; +const static uint8_t WHITELIST_PARSER_NEXT_PORT_DELIM = ','; const static uint8_t WHITELIST_PARSER_PORT_RANGE_DELIM = '-'; @@ -77,42 +77,43 @@ const static uint8_t WHITELIST_PARSER_PORT_RANGE_DELIM = '-'; /** * @desc Class storage of white listed ports. Single port or portRange can be added */ -class WhitelistedPorts -{ +class WhitelistedPorts { public: - WhitelistedPorts(); - /** - * @desc Add port range to whitelisted ports - * @param from Port from (start of range) - * @param to Port to (end of range) - */ - void addPortRange(uint16_t from, uint16_t to); - /** - * @desc Add single port to whitelisted ports - * @param port Port to add - */ - void addSinglePort(uint16_t port); - /** - * @desc Find port if is whitelisted - * @param port Port to find - */ - bool findPort(uint16_t port); + WhitelistedPorts(); + + /** + * @desc Add port range to whitelisted ports + * @param from Port from (start of range) + * @param to Port to (end of range) + */ + void addPortRange(uint16_t from, uint16_t to); + + /** + * @desc Add single port to whitelisted ports + * @param port Port to add + */ + void addSinglePort(uint16_t port); + + /** + * @desc Find port if is whitelisted + * @param port Port to find + */ + bool findPort(uint16_t port); private: - typedef std::pair Range; - struct RangeCompare - { - bool operator()(const Range& r1, const Range& r2) const - { - return r1.second < r2.first; - } - }; - std::set portRangeList; - - bool inRange(const std::set& ranges, uint16_t port) - { - return ranges.find(Range(port, port)) != ranges.end(); - } + typedef std::pair Range; + + struct RangeCompare { + bool operator()(const Range &r1, const Range &r2) const { + return r1.second < r2.first; + } + }; + + std::set portRangeList; + + bool inRange(const std::set &ranges, uint16_t port) { + return ranges.find(Range(port, port)) != ranges.end(); + } }; // ************************************************************/ @@ -121,16 +122,17 @@ class WhitelistedPorts class IPTrie { public: - IPTrie(); - ~IPTrie(); + IPTrie(); - IPTrie *left; - IPTrie *right; + ~IPTrie(); - bool allPorts; - bool set; + IPTrie *left; + IPTrie *right; - WhitelistedPorts *whitelistedPorts; + bool allPorts; + bool set; + + WhitelistedPorts *whitelistedPorts; }; // ************************************************************/ @@ -141,58 +143,57 @@ class IPTrie { */ class WhitelistParser { public: - WhitelistParser() - { - rulesCounter = 0; - verbose = false; - } - - /** - * @desc Init parser with two IP tries, first for IPv4, second for IPv6 - */ - void init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IPTrie *ipv6Dst); - /** - * @desc Parse input filestream and add rules into IP Tries, detection mode must be set - */ - void parse(std::ifstream *ifs, bool verboseMode); - - /** - * \brief Only for unit testing! - * - * Only for unit testing! - */ - bool addSelectedPortRule(ip_addr_t ip, uint8_t direction, uint8_t prefix, std::string &ports) - { - return checkPrefixAndPortsAndAdd(ip, direction, prefix, ports); - } + WhitelistParser() { + rulesCounter = 0; + verbose = false; + } + + /** + * @desc Init parser with two IP tries, first for IPv4, second for IPv6 + */ + void init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IPTrie *ipv6Dst); + + /** + * @desc Parse input filestream and add rules into IP Tries, detection mode must be set + */ + void parse(std::ifstream *ifs, bool verboseMode); + + /** + * \brief Only for unit testing! + * + * Only for unit testing! + */ + bool addSelectedPortRule(ip_addr_t ip, uint8_t direction, uint8_t prefix, std::string &ports) { + return checkPrefixAndPortsAndAdd(ip, direction, prefix, ports); + } private: - IPTrie *ipv4Src; - IPTrie *ipv4Dst; - IPTrie *ipv6Src; - IPTrie *ipv6Dst; - bool verbose; - uint32_t rulesCounter; - - /** - * @desc Add ip and ports into whitelist - */ - void prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, uint8_t prefix, std::string &ports); - - /** - * @desc Add ip and selected ports into whitelist - */ - void addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie *trie, std::string ports); - - /** - * @desc Add ports into IP trie - */ - void addPorts(IPTrie *currentNode, std::string ports); - - /** - * @desc Check ip prefix, then add ip and ports into whitelist - */ - bool checkPrefixAndPortsAndAdd(ip_addr_t &addr, uint8_t direction, uint8_t prefix, std::string &ports); + IPTrie *ipv4Src; + IPTrie *ipv4Dst; + IPTrie *ipv6Src; + IPTrie *ipv6Dst; + bool verbose; + uint32_t rulesCounter; + + /** + * @desc Add ip and ports into whitelist + */ + void prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, uint8_t prefix, std::string &ports); + + /** + * @desc Add ip and selected ports into whitelist + */ + void addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie *trie, std::string ports); + + /** + * @desc Add ports into IP trie + */ + void addPorts(IPTrie *currentNode, std::string ports); + + /** + * @desc Check ip prefix, then add ip and ports into whitelist + */ + bool checkPrefixAndPortsAndAdd(ip_addr_t &addr, uint8_t direction, uint8_t prefix, std::string &ports); }; // ************************************************************/ @@ -204,63 +205,63 @@ class WhitelistParser { */ class Whitelist { public: - Whitelist(); - ~Whitelist(); - - /** - * @desc init whitelist - * @param fileName name of whitelist file - * @param detectionMode detection mode - */ - bool init(char *fileName, bool verbose); - - /** - * @desc check given record and host source ip if is whitelisted - * @param Record record - * @param srcip source ip address - */ - bool isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, uint16_t srcPort, uint16_t dstPort); - - /** - * @desc get status for configuration reload - */ - sig_atomic_t isLockedForConfigurationReload() - { - return locked; - } - - /** - * @desc reaload whitelist, all previous configuration will be erased - */ - void reloadWhitelist(); - - /** - * \brief Only for unit testing! - * - * Only for unit testing! - */ - WhitelistParser *getPointerToParser() - { - return &parser; - } + Whitelist(); + + ~Whitelist(); + + /** + * @desc init whitelist + * @param fileName name of whitelist file + * @param detectionMode detection mode + */ + bool init(char *fileName, bool verbose); + + /** + * @desc check given record and host source ip if is whitelisted + * @param Record record + * @param srcip source ip address + */ + bool isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, uint16_t srcPort, uint16_t dstPort); + + /** + * @desc get status for configuration reload + */ + sig_atomic_t isLockedForConfigurationReload() { + return locked; + } + + /** + * @desc reaload whitelist, all previous configuration will be erased + */ + void reloadWhitelist(); + + /** + * \brief Only for unit testing! + * + * Only for unit testing! + */ + WhitelistParser *getPointerToParser() { + return &parser; + } + private: - /** - * @desc Find given ip address and port inside IP trie structure - * @param ipTrie IP trie - * @param ip IP address as array - * @param ipType Type of IP address 4 or 6 - * @param port Searched port - * @return true if port or ip is filtered, false otherwise - */ - bool trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t port); - - WhitelistParser parser; - IPTrie *ipv4Src; - IPTrie *ipv4Dst; - IPTrie *ipv6Src; - IPTrie *ipv6Dst; - sig_atomic_t locked; - char *wlFileName; + /** + * @desc Find given ip address and port inside IP trie structure + * @param ipTrie IP trie + * @param ip IP address as array + * @param ipType Type of IP address 4 or 6 + * @param port Searched port + * @return true if port or ip is filtered, false otherwise + */ + bool trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t port); + + WhitelistParser parser; + IPTrie *ipv4Src; + IPTrie *ipv4Dst; + IPTrie *ipv6Src; + IPTrie *ipv6Dst; + sig_atomic_t locked; + char *wlFileName; }; #endif // WHITELIST_H diff --git a/brute_force_detector/whitelist_unit_test.cpp b/brute_force_detector/whitelist_unit_test.cpp index dd85324b..adb6f932 100644 --- a/brute_force_detector/whitelist_unit_test.cpp +++ b/brute_force_detector/whitelist_unit_test.cpp @@ -48,38 +48,37 @@ using namespace std; //init and delete WL for new test instance -#define WL() { \ - if(wl!=nullptr) \ - { \ - delete wl; \ - wl = nullptr; \ - } \ - if(wl == nullptr) \ - { \ - wl = new Whitelist(); \ - } \ - parser = wl->getPointerToParser(); \ +#define WL() { \ + if(wl!=NULL) \ + { \ + delete wl; \ + wl = NULL; \ + } \ + if(wl == NULL) \ + { \ + wl = new Whitelist(); \ + } \ + parser = wl->getPointerToParser(); \ } //parser->setVerbose(); //print test number #define TEST(x) { WL(); } // cout << "Test " << x << ":" << endl; } -uint16_t getRandomPort(){return rand() % 65536;} +uint16_t getRandomPort() { return rand() % 65536; } int failCounter = 0; -void subTestRes(int testNum, const string& state) -{ +void subTestRes(int testNum, const string &state) { //cout <<"Subtest "<< testNum <<": "<< state << endl; - if (state == "fail") - failCounter++; + if (state == "fail") { + failCounter++; + } } -int main() -{ - Whitelist *wl = nullptr; +int main() { + Whitelist *wl = NULL; WhitelistParser *parser; srand(0); // TODO constant value as random seed @@ -106,38 +105,46 @@ int main() ip_from_str("255.255.255.255", &ip5); - /******************************************* - ***************** TEST 1 ****************** - ****** TEST FOR ALL PORTS, ALL DIR ******** - *******************************************/ + /******************************************* + ***************** TEST 1 ****************** + ****** TEST FOR ALL PORTS, ALL DIR ******** + *******************************************/ TEST(1); string ports = string(); //empty string behaves like all port rule parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_ALL, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&ip1, &zeroIp, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&ip1, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip2, &zeroIp, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&ip2, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should be whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), getRandomPort())) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), getRandomPort())) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } /******************************************* ***************** TEST 2 ****************** @@ -146,22 +153,28 @@ int main() TEST(2); parser->addSelectedPortRule(ip2, WHITELIST_PARSER_IP_DIRECTION_SRC, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&ip2, &zeroIp, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&ip2, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip1, &zeroIp, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&ip1, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip3, &zeroIp, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&ip3, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 3 ****************** @@ -170,22 +183,28 @@ int main() TEST(3); parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_DST, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), getRandomPort())) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), getRandomPort())) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip3, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&zeroIp, &ip3, getRandomPort(), getRandomPort())) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 4 ****************** @@ -196,34 +215,44 @@ int main() parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_ALL, 32, ports); //ip port should be whitelisted - if(wl->isWhitelisted(&ip1, &zeroIp, 80, zeroPort)) + if (wl->isWhitelisted(&ip1, &zeroIp, 80, zeroPort)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip2, &zeroIp, 80, 80)) + if (!wl->isWhitelisted(&ip2, &zeroIp, 80, 80)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip port should be whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, zeroPort, 80)) + if (wl->isWhitelisted(&zeroIp, &ip1, zeroPort, 80)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, 80, 80)) + if (!wl->isWhitelisted(&zeroIp, &ip2, 80, 80)) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip1, 79, 79)) + if (!wl->isWhitelisted(&zeroIp, &ip1, 79, 79)) { subTestRes(5, "passed"); - else + } + else { subTestRes(5, "fail"); + } /******************************************* ***************** TEST 5 ****************** @@ -233,22 +262,28 @@ int main() ports = "80"; parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_SRC, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&ip1, &zeroIp, 80, getRandomPort())) + if (wl->isWhitelisted(&ip1, &zeroIp, 80, getRandomPort())) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip1, &zeroIp, 79, 80)) + if (!wl->isWhitelisted(&ip1, &zeroIp, 79, 80)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip3, &zeroIp, 80, 80)) + if (!wl->isWhitelisted(&ip3, &zeroIp, 80, 80)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 6 ****************** @@ -258,22 +293,28 @@ int main() ports = "80"; parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_DST, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 80)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 80)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 80)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 80)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 79)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 79)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 7 ****************** @@ -283,40 +324,52 @@ int main() ports = "80-100"; parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_DST, 32, ports); //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 95)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 95)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 80)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 80)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 100)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 100)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } //outside 80-100 range - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 79)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 79)) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } //outside 80-100 range - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 101)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 101)) { subTestRes(5, "passed"); - else + } + else { subTestRes(5, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 80)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 80)) { subTestRes(6, "passed"); - else + } + else { subTestRes(6, "fail"); + } /******************************************* ***************** TEST 8 ****************** @@ -327,34 +380,44 @@ int main() ports = "50,10-20,1000"; parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_DST, 32, ports); //1000 whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 1000)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 1000)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 10)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 10)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 18)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 18)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } //50 whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 50)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 50)) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 50)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 50)) { subTestRes(5, "passed"); - else + } + else { subTestRes(5, "fail"); + } /******************************************* ***************** TEST 9 ****************** @@ -366,35 +429,47 @@ int main() ports = string(); parser->addSelectedPortRule(ip3, WHITELIST_PARSER_IP_DIRECTION_DST, 16, ports); - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 15)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 15)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } - if(wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 15)) + if (wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 15)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 21)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 21)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } - if(wl->isWhitelisted(&zeroIp, &ip3, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&zeroIp, &ip3, getRandomPort(), getRandomPort())) { subTestRes(5, "passed"); - else + } + else { subTestRes(5, "fail"); + } - if(wl->isWhitelisted(&zeroIp, &ip4, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&zeroIp, &ip4, getRandomPort(), getRandomPort())) { subTestRes(6, "passed"); - else + } + else { subTestRes(6, "fail"); + } /******************************************* ***************** TEST 10 ****************** @@ -404,22 +479,28 @@ int main() ports = "10-20"; parser->addSelectedPortRule(ip5, WHITELIST_PARSER_IP_DIRECTION_DST, 0, ports); - if(wl->isWhitelisted(&zeroIp, &ip4, getRandomPort(), 10)) + if (wl->isWhitelisted(&zeroIp, &ip4, getRandomPort(), 10)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } ports = string(); parser->addSelectedPortRule(ip3, WHITELIST_PARSER_IP_DIRECTION_DST, 0, ports); - if(wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) + if (wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 11 ***************** @@ -429,20 +510,26 @@ int main() ports = "25"; parser->addSelectedPortRule(ip5, WHITELIST_PARSER_IP_DIRECTION_DST, 8, ports); - if(wl->isWhitelisted(&zeroIp, &ip5, getRandomPort(), 25)) + if (wl->isWhitelisted(&zeroIp, &ip5, getRandomPort(), 25)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip5, 25, 0)) + if (!wl->isWhitelisted(&zeroIp, &ip5, 25, 0)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 25)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 25)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /* if(failCounter == 0) From dd11d1f6cfc2c39f7f5b5a6d7815c8f8691bc5b0 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Fri, 20 Sep 2019 16:07:11 +0200 Subject: [PATCH 35/40] Reformatting, var names changes, fixes to default config --- brute_force_detector/brute_force_detector.cpp | 175 ++-- brute_force_detector/brute_force_detector.h | 102 +-- brute_force_detector/config.cpp | 135 ++- brute_force_detector/config.h | 248 +++--- brute_force_detector/config/config.conf | 30 +- brute_force_detector/config/whitelist.wl | 2 +- brute_force_detector/host.cpp | 125 +-- brute_force_detector/host.h | 236 +++--- brute_force_detector/record.cpp | 243 +++--- brute_force_detector/record.h | 280 +++--- brute_force_detector/sender.cpp | 38 +- brute_force_detector/sender.h | 57 +- .../telnet_server_profile.cpp | 47 +- brute_force_detector/telnet_server_profile.h | 39 +- brute_force_detector/whitelist.cpp | 797 +++++++++--------- brute_force_detector/whitelist.h | 305 +++---- brute_force_detector/whitelist_unit_test.cpp | 309 ++++--- 17 files changed, 1647 insertions(+), 1521 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index bde29eed..f4364062 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -106,7 +106,7 @@ UR_FIELDS( /* ************************************************************************* */ // Struct with information about module -trap_module_info_t *module_info = nullptr; +trap_module_info_t *module_info = NULL; #define MODULE_BASIC_INFO(BASIC) \ @@ -130,18 +130,23 @@ void signalHandler(int signal) { if (signal == SIGTERM || signal == SIGINT) { stop = 1; trap_terminate(); - } else if (signal == SIGUSR1) { + } + else if (signal == SIGUSR1) { Config::getInstance().reloadConfig(); - } else if (signal == SIGUSR2) { + } + else if (signal == SIGUSR2) { if (!whitelist.isLockedForConfigurationReload()) { whitelist.reloadWhitelist(); - } else { + } + else { alarm(1); // cannot reload now.. wait } - } else if (signal == SIGALRM) { + } + else if (signal == SIGALRM) { if (!whitelist.isLockedForConfigurationReload()) { whitelist.reloadWhitelist(); - } else { + } + else { alarm(1); // wait another second } } @@ -188,11 +193,11 @@ int main(int argc, char **argv) { sigaddset(&sigAction.sa_mask, SIGALRM); // register signal handler - sigaction (SIGTERM, &sigAction, nullptr); - sigaction (SIGINT , &sigAction, nullptr); - sigaction (SIGUSR1, &sigAction, nullptr); - sigaction (SIGUSR2, &sigAction, nullptr); - sigaction (SIGALRM, &sigAction, nullptr); + sigaction (SIGTERM, &sigAction, NULL); + sigaction (SIGINT , &sigAction, NULL); + sigaction (SIGUSR1, &sigAction, NULL); + sigaction (SIGUSR2, &sigAction, NULL); + sigaction (SIGALRM, &sigAction, NULL); #else signal(SIGTERM, signalHandler); signal(SIGINT, signalHandler); @@ -203,8 +208,8 @@ int main(int argc, char **argv) { // ***** Parsing non TRAP arguments ***** signed char opt; - char *configFilePath = nullptr; - char *whitelistFilePath = nullptr; + char *configFilePath = NULL; + char *whitelistFilePath = NULL; bool whitelistParserVerbose = false; bool RDP = false, SSH = false, TELNET = false; while ((opt = TRAP_GETOPT(argc, argv, module_getopt_string, long_options)) != -1) { @@ -241,7 +246,7 @@ int main(int argc, char **argv) { } // ***** Config init ***** - if (configFilePath != nullptr) { + if (configFilePath != NULL) { bool state = Config::getInstance().initFromFile(configFilePath); if (!state) { cerr << "Error: Cannot open configuration file \"" << configFilePath << "\".\n"; @@ -251,7 +256,7 @@ int main(int argc, char **argv) { } // ***** Whitelist init ***** - if (whitelistFilePath != nullptr) { + if (whitelistFilePath != NULL) { bool state = whitelist.init(whitelistFilePath, whitelistParserVerbose); if (!state) { cerr << "Error: Cannot open whitelist file.\n"; @@ -263,11 +268,11 @@ int main(int argc, char **argv) { // ***** Create UniRec template for input ***** std::string unirecSpecifier = "SRC_IP,DST_IP,SRC_PORT,DST_PORT,PROTOCOL,PACKETS,BYTES,TIME_FIRST,TIME_LAST,TCP_FLAGS"; - char *errstr = nullptr; + char *errstr = NULL; ur_template_t *tmplt = ur_create_input_template(0, unirecSpecifier.c_str(), &errstr); - if (tmplt == nullptr) { + if (tmplt == NULL) { cerr << "Error: Invalid UniRec specifier." << endl; - if (errstr != nullptr) { + if (errstr != NULL) { fprintf(stderr, "%s\n", errstr); free(errstr); } @@ -279,7 +284,7 @@ int main(int argc, char **argv) { // ***** Init UniRec template for sender ***** bool senderState; - auto sender = new Sender(&senderState); + Sender *sender = new Sender(&senderState); if (!senderState) { cerr << "Error: Invalid output UniRec specifier. Check sender.cpp file.\n"; delete sender; @@ -314,7 +319,8 @@ int main(int argc, char **argv) { if (data_size < ur_rec_fixlen_size(tmplt)) { if (data_size <= 1) { break; // End of data (used for testing purposes) - } else { + } + else { cerr << "Error: data with wrong size received (expected size: >= " << ur_rec_fixlen_size(tmplt) << ", received size: " << data_size << ")\n"; @@ -338,7 +344,8 @@ int main(int argc, char **argv) { uint8_t direction; if (dstPort == TCP_SSH_PORT || dstPort == TCP_TELNET_PORT || dstPort == TCP_RDP_PORT) { direction = FLOW_INCOMING_DIRECTION; - } else { + } + else { direction = FLOW_OUTGOING_DIRECTION; } @@ -351,8 +358,8 @@ int main(int argc, char **argv) { .dstIp = ur_get(tmplt, data, F_DST_IP), .srcPort = srcPort, .dstPort = dstPort, - .flowFirstSeen = ur_get(tmplt, data, F_TIME_FIRST), - .flowLastSeen = ur_get(tmplt, data, F_TIME_LAST), + .firstSeen = ur_get(tmplt, data, F_TIME_FIRST), + .lastSeen = ur_get(tmplt, data, F_TIME_LAST), }; ret = 0; @@ -364,15 +371,16 @@ int main(int argc, char **argv) { SSHRecord *record; if (direction == FLOW_INCOMING_DIRECTION) { - record = new SSHRecord(flow.dstIp, flow.flowLastSeen); + record = new SSHRecord(flow.dstIp, flow.lastSeen); is_matched = record->matchWithIncomingSignature(&flow, &whitelist); if (is_matched) { ssh.matchedIncomingFlows++; } ssh.incomingFlows++; - } else { + } + else { // FLOW_OUTGOING_DIRECTION - record = new SSHRecord(flow.srcIp, flow.flowLastSeen); + record = new SSHRecord(flow.srcIp, flow.lastSeen); is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); if (is_matched) { ssh.matchedOutgoingFlows++; @@ -392,30 +400,35 @@ int main(int argc, char **argv) { if (is_portscan) { delete record; - } else { + } + else { // check for attack - auto attackState = host->checkForAttack(flow.flowLastSeen); + SSHHost::ATTACK_STATE attackState = host->checkForAttack(flow.lastSeen); if (attackState != SSHHost::NO_ATTACK) { if (attackState == SSHHost::REPORT_NEW_ATTACK) { - ret = sender->firstReport(host, TCP_SSH_PORT, flow.flowLastSeen, - Config::getInstance().getSSHListThreshold()); - } else if (attackState == SSHHost::ATTACK_REPORT_WAIT || - attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) { + ret = sender->firstReport(host, TCP_SSH_PORT, flow.lastSeen, + Config::getInstance().getSSHFlowThreshold()); + } + else if (attackState == SSHHost::ATTACK_REPORT_WAIT || + attackState == SSHHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } else if (attackState == SSHHost::END_OF_ATTACK) { + } + else if (attackState == SSHHost::END_OF_ATTACK) { // clear list host->clearAllRecords(); host->setNotReported(); - } else if (attackState == SSHHost::REPORT_END_OF_ATTACK) { + } + else if (attackState == SSHHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_SSH_PORT, flow.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_SSH_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); - } else if (attackState == SSHHost::REPORT_ATTACK) { - ret = sender->continuingReport(host, TCP_SSH_PORT, flow.flowLastSeen); + } + else if (attackState == SSHHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_SSH_PORT, flow.lastSeen); } } } @@ -428,15 +441,16 @@ int main(int argc, char **argv) { RDPRecord *record; if (direction == FLOW_INCOMING_DIRECTION) { - record = new RDPRecord(flow.dstIp, flow.flowLastSeen); + record = new RDPRecord(flow.dstIp, flow.lastSeen); is_matched = record->matchWithIncomingSignature(&flow, &whitelist); if (is_matched) { rdp.matchedIncomingFlows++; } rdp.incomingFlows++; - } else { + } + else { // FLOW_OUTGOING_DIRECTION - record = new RDPRecord(flow.srcIp, flow.flowLastSeen); + record = new RDPRecord(flow.srcIp, flow.lastSeen); is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); if (is_matched) { rdp.matchedOutgoingFlows++; @@ -454,28 +468,33 @@ int main(int argc, char **argv) { is_portscan = !host->addRecord(record, &flow, direction); if (is_portscan) { delete record; - } else { + } + else { // check for attack - RDPHost::ATTACK_STATE attackState = host->checkForAttack(flow.flowLastSeen); + RDPHost::ATTACK_STATE attackState = host->checkForAttack(flow.lastSeen); if (attackState != RDPHost::NO_ATTACK) { if (attackState == RDPHost::REPORT_NEW_ATTACK) { - ret = sender->firstReport(host, TCP_RDP_PORT, flow.flowLastSeen, - Config::getInstance().getRDPListThreshold()); - } else if (attackState == RDPHost::ATTACK_REPORT_WAIT || - attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) { + ret = sender->firstReport(host, TCP_RDP_PORT, flow.lastSeen, + Config::getInstance().getRDPFlowThreshold()); + } + else if (attackState == RDPHost::ATTACK_REPORT_WAIT || + attackState == RDPHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } else if (attackState == RDPHost::END_OF_ATTACK) { + } + else if (attackState == RDPHost::END_OF_ATTACK) { host->clearAllRecords(); host->setNotReported(); - } else if (attackState == RDPHost::REPORT_END_OF_ATTACK) { + } + else if (attackState == RDPHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_RDP_PORT, flow.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_RDP_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); - } else if (attackState == RDPHost::REPORT_ATTACK) { - ret = sender->continuingReport(host, TCP_RDP_PORT, flow.flowLastSeen); + } + else if (attackState == RDPHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_RDP_PORT, flow.lastSeen); } } } @@ -488,15 +507,16 @@ int main(int argc, char **argv) { TELNETRecord *record; if (direction == FLOW_INCOMING_DIRECTION) { - record = new TELNETRecord(flow.dstIp, flow.flowLastSeen); + record = new TELNETRecord(flow.dstIp, flow.lastSeen); is_matched = record->matchWithIncomingSignature(&flow, &whitelist); if (is_matched) { telnet.matchedIncomingFlows++; } telnet.incomingFlows++; - } else { + } + else { // FLOW_OUTGOING_DIRECTION - record = new TELNETRecord(flow.srcIp, flow.flowLastSeen); + record = new TELNETRecord(flow.srcIp, flow.lastSeen); is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); if (is_matched) { telnet.matchedOutgoingFlows++; @@ -514,58 +534,63 @@ int main(int argc, char **argv) { is_portscan = !host->addRecord(record, &flow, direction); if (is_portscan) { delete record; - } else { + } + else { // check for attack - TELNETHost::ATTACK_STATE attackState = host->checkForAttack(flow.flowLastSeen); + TELNETHost::ATTACK_STATE attackState = host->checkForAttack(flow.lastSeen); if (attackState != TELNETHost::NO_ATTACK) { if (attackState == TELNETHost::REPORT_NEW_ATTACK) { - ret = sender->firstReport(host, TCP_TELNET_PORT, flow.flowLastSeen, - Config::getInstance().getTELNETListThreshold()); - } else if (attackState == TELNETHost::ATTACK_REPORT_WAIT || - attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) { + ret = sender->firstReport(host, TCP_TELNET_PORT, flow.lastSeen, + Config::getInstance().getTELNETFlowThreshold()); + } + else if (attackState == TELNETHost::ATTACK_REPORT_WAIT || + attackState == TELNETHost::ATTACK_MIN_EVENTS_WAIT) { // waiting for report timeout or min events to report // no action - } else if (attackState == TELNETHost::END_OF_ATTACK) { + } + else if (attackState == TELNETHost::END_OF_ATTACK) { host->clearAllRecords(); host->setNotReported(); - } else if (attackState == TELNETHost::REPORT_END_OF_ATTACK) { + } + else if (attackState == TELNETHost::REPORT_END_OF_ATTACK) { // report and clear list - ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.flowLastSeen, true); + ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); - } else if (attackState == TELNETHost::REPORT_ATTACK) { - ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.flowLastSeen); + } + else if (attackState == TELNETHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.lastSeen); } } } } - if (checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flow.flowLastSeen)) { - timeOfLastReportCheck = flow.flowLastSeen; + if (checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flow.lastSeen)) { + timeOfLastReportCheck = flow.lastSeen; if (SSH) { - sshHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + sshHostMap.checkForAttackTimeout(flow.lastSeen, sender); } if (RDP) { - rdpHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + rdpHostMap.checkForAttackTimeout(flow.lastSeen, sender); } if (TELNET) { - telnetHostMap.checkForAttackTimeout(flow.flowLastSeen, sender); + telnetHostMap.checkForAttackTimeout(flow.lastSeen, sender); } } - if (checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, flow.flowLastSeen)) { - timeOfLastDeleteCheck = flow.flowLastSeen; + if (checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, flow.lastSeen)) { + timeOfLastDeleteCheck = flow.lastSeen; if (SSH) { - sshHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + sshHostMap.deleteOldRecordAndHosts(flow.lastSeen); } if (RDP) { - rdpHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + rdpHostMap.deleteOldRecordAndHosts(flow.lastSeen); } if (TELNET) { - telnetHostMap.deleteOldRecordAndHosts(flow.flowLastSeen); + telnetHostMap.deleteOldRecordAndHosts(flow.lastSeen); } } diff --git a/brute_force_detector/brute_force_detector.h b/brute_force_detector/brute_force_detector.h index c18af9cc..4165b9c9 100644 --- a/brute_force_detector/brute_force_detector.h +++ b/brute_force_detector/brute_force_detector.h @@ -49,74 +49,76 @@ #include #include //ip_addr_t -const static uint8_t TCP_PROTOCOL_NUM = 6; -const static uint16_t TCP_SSH_PORT = 22; -const static uint16_t TCP_TELNET_PORT = 23; -const static uint16_t TCP_RDP_PORT = 3389; +const static uint8_t TCP_PROTOCOL_NUM = 6; +const static uint16_t TCP_SSH_PORT = 22; +const static uint16_t TCP_TELNET_PORT = 23; +const static uint16_t TCP_RDP_PORT = 3389; const static uint8_t FLOW_INCOMING_DIRECTION = 1; const static uint8_t FLOW_OUTGOING_DIRECTION = 2; -void printFlowPercent(uint64_t b, uint64_t p, const std::string& comment = ""); +static const uint16_t TELNET_OUTGOING_MIN_PACKETS = 6; + + +void printFlowPercent(uint64_t b, uint64_t p, const std::string &comment = ""); //ip address comparison for std::map and std::set struct cmpByIpAddr { - bool operator ()(const ip_addr_t& a, const ip_addr_t& b) const { - return (memcmp((char*)&a, (char*)&b, sizeof(ip_addr_t)) < 0); + bool operator()(const ip_addr_t &a, const ip_addr_t &b) const { + return (memcmp((char *) &a, (char *) &b, sizeof(ip_addr_t)) < 0); } }; struct thousandsSeparator : std::numpunct { - // use dot as separator - char do_thousands_sep() const override { return '.'; } + // use dot as separator + char do_thousands_sep() const override { return '.'; } - // digits are grouped by 3 digits each - std::string do_grouping() const override { return "\3"; } + // digits are grouped by 3 digits each + std::string do_grouping() const override { return "\3"; } }; class logInfo { public: - explicit logInfo(std::string _protocolName) : protocolName(std::move(_protocolName)), - flows(0), - incomingFlows(0), - outgoingFlows(0), - matchedFlows(0), - matchedIncomingFlows(0), - matchedOutgoingFlows(0) - {}; - - void printLogInfo(){ - std::cout << this->protocolName << std::endl; - std::cout.imbue(std::locale(std::locale(), new thousandsSeparator)); // TODO move elsewhere - std::cout << " Total Flows: " << this->flows << std::endl; - std::cout << " Incoming Flows: " << this->incomingFlows; - printFlowPercent(this->flows, this->incomingFlows); - std::cout << std::endl; - std::cout << " Outgoing Flows: " << this->outgoingFlows; - printFlowPercent(this->flows, this->outgoingFlows); - std::cout << std::endl; - std::cout << " Matched Flows: " << this->matchedFlows; - printFlowPercent(this->flows, this->matchedFlows); - std::cout << std::endl; - std::cout << " Matched Incoming Flows: " << this->matchedIncomingFlows; - printFlowPercent(this->matchedFlows, this->matchedIncomingFlows, " from matched"); - printFlowPercent(this->flows, this->matchedIncomingFlows, " from incoming"); - std::cout << std::endl; - std::cout << " Matched Outgoing Flows: " << this->matchedOutgoingFlows; - printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows, " from matched"); - printFlowPercent(this->flows, this->matchedOutgoingFlows, " from outgoing"); - std::cout << std::endl; - } - - std::string protocolName; - uint64_t flows; - uint64_t incomingFlows; - uint64_t outgoingFlows; - uint64_t matchedFlows ; - uint64_t matchedIncomingFlows; - uint64_t matchedOutgoingFlows; + explicit logInfo(std::string _protocolName) : protocolName(std::move(_protocolName)), + flows(0), + incomingFlows(0), + outgoingFlows(0), + matchedFlows(0), + matchedIncomingFlows(0), + matchedOutgoingFlows(0) {}; + + void printLogInfo() { + std::cout << this->protocolName << std::endl; + std::cout.imbue(std::locale(std::locale(), new thousandsSeparator)); + std::cout << " Total Flows: " << this->flows << std::endl; + std::cout << " Incoming Flows: " << this->incomingFlows; + printFlowPercent(this->flows, this->incomingFlows); + std::cout << std::endl; + std::cout << " Outgoing Flows: " << this->outgoingFlows; + printFlowPercent(this->flows, this->outgoingFlows); + std::cout << std::endl; + std::cout << " Matched Flows: " << this->matchedFlows; + printFlowPercent(this->flows, this->matchedFlows); + std::cout << std::endl; + std::cout << " Matched Incoming Flows: " << this->matchedIncomingFlows; + printFlowPercent(this->matchedFlows, this->matchedIncomingFlows, " from matched"); + printFlowPercent(this->flows, this->matchedIncomingFlows, " from incoming"); + std::cout << std::endl; + std::cout << " Matched Outgoing Flows: " << this->matchedOutgoingFlows; + printFlowPercent(this->matchedFlows, this->matchedOutgoingFlows, " from matched"); + printFlowPercent(this->flows, this->matchedOutgoingFlows, " from outgoing"); + std::cout << std::endl; + } + + std::string protocolName; + uint64_t flows; + uint64_t incomingFlows; + uint64_t outgoingFlows; + uint64_t matchedFlows; + uint64_t matchedIncomingFlows; + uint64_t matchedOutgoingFlows; }; #endif diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index 65769491..eb1ffa0f 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -56,8 +56,8 @@ Config::Config() { GENERAL_IGNORE_FIRST_SEND = 0; //SSH - SSH_LIST_SIZE = 1000; - SSH_LIST_THRESHOLD = 90; + SSH_MAX_RECORDS = 500; + SSH_FLOW_THRESHOLD = 90; SSH_MATCHED_FLOW_RATIO = 0.9; SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); @@ -77,8 +77,8 @@ Config::Config() { SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(600, 0); //RDP - RDP_LIST_SIZE = 1000; - RDP_LIST_THRESHOLD = 90; + RDP_MAX_RECORDS = 500; + RDP_FLOW_THRESHOLD = 90; RDP_MATCHED_FLOW_RATIO = 0.9; RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); @@ -99,8 +99,8 @@ Config::Config() { RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(600, 0); //TELNET - TELNET_LIST_SIZE = 1000; - TELNET_LIST_THRESHOLD = 90; + TELNET_MAX_RECORDS = 500; + TELNET_FLOW_THRESHOLD = 90; TELNET_MATCHED_FLOW_RATIO = 0.9; TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(3600, 0); @@ -120,12 +120,11 @@ Config::Config() { kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = "GENERAL_ATTACK_MIN_EVENTS_TO_REPORT"; kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = "GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST"; kw_GENERAL_IGNORE_FIRST_SEND = "GENERAL_IGNORE_FIRST_SEND"; - kw_GENERAL_MATCHED_FLOW_RATIO = "GENERAL_MATCHED_FLOW_RATIO"; //SSH - kw_SSH_LIST_SIZE = "SSH_LIST_SIZE"; - kw_SSH_LIST_THRESHOLD = "SSH_LIST_THRESHOLD"; - kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD = "SSH_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_SSH_MAX_RECORDS = "SSH_MAX_RECORDS"; + kw_SSH_FLOW_THRESHOLD = "SSH_FLOW_THRESHOLD"; + kw_SSH_MATCHED_FLOW_RATIO = "SSH_MATCHED_FLOW_RATIO"; kw_SSH_RECORD_TIMEOUT = "SSH_RECORD_TIMEOUT"; kw_SSH_HOST_TIMEOUT = "SSH_HOST_TIMEOUT"; @@ -143,9 +142,9 @@ Config::Config() { kw_SSH_BRUTEFORCE_OUT_MAX_BYTES = "SSH_BRUTEFORCE_OUT_MAX_BYTES"; //RDP - kw_RDP_LIST_SIZE = "RDP_LIST_SIZE"; - kw_RDP_LIST_THRESHOLD = "RDP_LIST_THRESHOLD"; - kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD = "RDP_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_RDP_MAX_RECORDS = "RDP_MAX_RECORDS"; + kw_RDP_FLOW_THRESHOLD = "RDP_FLOW_THRESHOLD"; + kw_RDP_MATCHED_FLOW_RATIO = "RDP_MATCHED_FLOW_RATIO"; kw_RDP_RECORD_TIMEOUT = "RDP_RECORD_TIMEOUT"; kw_RDP_HOST_TIMEOUT = "RDP_HOST_TIMEOUT"; @@ -163,9 +162,9 @@ Config::Config() { kw_RDP_BRUTEFORCE_OUT_MAX_BYTES = "RDP_BRUTEFORCE_OUT_MAX_BYTES"; //TELNET - kw_TELNET_LIST_SIZE = "TELNET_LIST_SIZE"; - kw_TELNET_LIST_THRESHOLD = "TELNET_LIST_THRESHOLD"; - kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD = "TELNET_LIST_SIZE_BOTTOM_THRESHOLD"; + kw_TELNET_MAX_RECORDS = "TELNET_MAX_RECORDS"; + kw_TELNET_FLOW_THRESHOLD = "TELNET_FLOW_THRESHOLD"; + kw_TELNET_MATCHED_FLOW_RATIO = "TELNET_MATCHED_FLOW_RATIO"; kw_TELNET_RECORD_TIMEOUT = "TELNET_RECORD_TIMEOUT"; kw_TELNET_HOST_TIMEOUT = "TELNET_HOST_TIMEOUT"; @@ -233,169 +232,169 @@ bool Config::initFromFile(const string &path) { // ****** GENERAL ****** // ********************* if (keyword == kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) { - GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = std::stoul(value, nullptr); + GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = std::stoul(value, NULL); } else if (keyword == kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) { - GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = std::stod(value, nullptr); + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = std::stod(value, NULL); } else if (keyword == kw_GENERAL_IGNORE_FIRST_SEND) { - GENERAL_IGNORE_FIRST_SEND = std::stoul(value, nullptr); + GENERAL_IGNORE_FIRST_SEND = std::stoul(value, NULL); } // ********************* // ******* SSH ********* // ********************* - else if (keyword == kw_SSH_LIST_SIZE) { - SSH_LIST_SIZE = std::stoul(value, nullptr); + else if (keyword == kw_SSH_MAX_RECORDS) { + SSH_MAX_RECORDS = std::stoul(value, NULL); } - else if (keyword == kw_SSH_LIST_THRESHOLD) { - SSH_LIST_THRESHOLD = std::stoul(value, nullptr); + else if (keyword == kw_SSH_FLOW_THRESHOLD) { + SSH_FLOW_THRESHOLD = std::stoul(value, NULL); } else if (keyword == kw_SSH_MATCHED_FLOW_RATIO) { - SSH_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + SSH_MATCHED_FLOW_RATIO = std::stod(value, NULL); } else if (keyword == kw_SSH_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); SSH_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) { - SSH_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); + SSH_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) { - SSH_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); + SSH_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_BYTES) { - SSH_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); + SSH_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_BYTES) { - SSH_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); + SSH_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); } // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) { - SSH_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, nullptr); + SSH_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) { - SSH_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, nullptr); + SSH_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) { - SSH_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, nullptr); + SSH_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) { - SSH_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, nullptr); + SSH_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, NULL); } // ********************* // ******* RDP ********* // ********************* - else if (keyword == kw_RDP_LIST_SIZE) { - RDP_LIST_SIZE = std::stoul(value, nullptr); + else if (keyword == kw_RDP_MAX_RECORDS) { + RDP_MAX_RECORDS = std::stoul(value, NULL); } - else if (keyword == kw_RDP_LIST_THRESHOLD) { - RDP_LIST_THRESHOLD = std::stoul(value, nullptr); + else if (keyword == kw_RDP_FLOW_THRESHOLD) { + RDP_FLOW_THRESHOLD = std::stoul(value, NULL); } else if (keyword == kw_RDP_MATCHED_FLOW_RATIO) { - RDP_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + RDP_MATCHED_FLOW_RATIO = std::stod(value, NULL); } else if (keyword == kw_RDP_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); RDP_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) { - RDP_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); + RDP_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) { - RDP_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); + RDP_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_BYTES) { - RDP_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); + RDP_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_BYTES) { - RDP_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); + RDP_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); } // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) { - RDP_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, nullptr); + RDP_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) { - RDP_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, nullptr); + RDP_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) { - RDP_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, nullptr); + RDP_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) { - RDP_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, nullptr); + RDP_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, NULL); } // ********************* // ****** TELNET ******* // ********************* - else if (keyword == kw_TELNET_LIST_SIZE) { - TELNET_LIST_SIZE = std::stoul(value, nullptr); + else if (keyword == kw_TELNET_MAX_RECORDS) { + TELNET_MAX_RECORDS = std::stoul(value, NULL); } - else if (keyword == kw_TELNET_LIST_THRESHOLD) { - TELNET_LIST_THRESHOLD = std::stoul(value, nullptr); + else if (keyword == kw_TELNET_FLOW_THRESHOLD) { + TELNET_FLOW_THRESHOLD = std::stoul(value, NULL); } else if (keyword == kw_TELNET_MATCHED_FLOW_RATIO) { - TELNET_MATCHED_FLOW_RATIO = std::stod(value, nullptr); + TELNET_MATCHED_FLOW_RATIO = std::stod(value, NULL); } else if (keyword == kw_TELNET_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, nullptr); + uint32_t sec = std::stoul(value, NULL); TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) { - TELNET_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, nullptr); + TELNET_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) { - TELNET_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, nullptr); + TELNET_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) { - TELNET_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, nullptr); + TELNET_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) { - TELNET_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, nullptr); + TELNET_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); } // ********************* // ******* UNKNOWN ***** diff --git a/brute_force_detector/config.h b/brute_force_detector/config.h index 7a76ee8b..d3d47ff8 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -56,77 +56,109 @@ class Config { public: - bool initFromFile(const std::string& path); + bool initFromFile(const std::string &path); - inline ur_time_t getGlobalTimerForReportCheck() const {return GENERAL_CHECK_FOR_REPORT_TIMEOUT;} - inline ur_time_t getGlobalTimerForDeleteCheck() const {return GENERAL_CHECK_FOR_DELETE_TIMEOUT;} - inline ur_time_t getGlobalAttackMinEvToReport() const {return GENERAL_ATTACK_MIN_EVENTS_TO_REPORT;} - inline double getGlobalAttackMinRatioToKeepTrackingHost() const {return GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST;} - inline int getGlobalIgnoreFirstSend() const {return GENERAL_IGNORE_FIRST_SEND;} + inline ur_time_t getGlobalTimerForReportCheck() const { return GENERAL_CHECK_FOR_REPORT_TIMEOUT; } - //SSH - inline uint16_t getSSHMaxListSize() const {return SSH_LIST_SIZE;} - inline uint16_t getSSHListThreshold() const {return SSH_LIST_THRESHOLD;} - inline double getSSHMatchedFlowRatio() const {return SSH_MATCHED_FLOW_RATIO;} + inline ur_time_t getGlobalTimerForDeleteCheck() const { return GENERAL_CHECK_FOR_DELETE_TIMEOUT; } - inline ur_time_t getSSHRecordTimeout() const {return SSH_RECORD_TIMEOUT;} - inline ur_time_t getSSHHostDeleteTimeout() const {return SSH_HOST_TIMEOUT;} - inline ur_time_t getSSHReportTimeout() const {return SSH_REPORT_TIMEOUT;} - inline ur_time_t getSSHAttackTimeout() const {return SSH_ATTACK_TIMEOUT;} + inline ur_time_t getGlobalAttackMinEvToReport() const { return GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; } + + inline double + getGlobalAttackMinRatioToKeepTrackingHost() const { return GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; } + + inline int getGlobalIgnoreFirstSend() const { return GENERAL_IGNORE_FIRST_SEND; } + + //SSH + inline uint16_t getSSHMaxRecords() const { return SSH_MAX_RECORDS; } + + inline uint16_t getSSHFlowThreshold() const { return SSH_FLOW_THRESHOLD; } + + inline double getSSHMatchedFlowRatio() const { return SSH_MATCHED_FLOW_RATIO; } + + inline ur_time_t getSSHRecordTimeout() const { return SSH_RECORD_TIMEOUT; } + + inline ur_time_t getSSHHostDeleteTimeout() const { return SSH_HOST_TIMEOUT; } + + inline ur_time_t getSSHReportTimeout() const { return SSH_REPORT_TIMEOUT; } + + inline ur_time_t getSSHAttackTimeout() const { return SSH_ATTACK_TIMEOUT; } // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) - inline uint16_t getSSHIncMinPackets() const {return SSH_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getSSHIncMaxPackets() const {return SSH_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getSSHIncMinBytes() const {return SSH_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getSSHIncMaxBytes() const {return SSH_BRUTEFORCE_INC_MAX_BYTES;} + inline uint16_t getSSHIncMinPackets() const { return SSH_BRUTEFORCE_INC_MIN_PACKETS; } + + inline uint16_t getSSHIncMaxPackets() const { return SSH_BRUTEFORCE_INC_MAX_PACKETS; } + + inline uint16_t getSSHIncMinBytes() const { return SSH_BRUTEFORCE_INC_MIN_BYTES; } + + inline uint16_t getSSHIncMaxBytes() const { return SSH_BRUTEFORCE_INC_MAX_BYTES; } // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) - inline uint16_t getSSHOutMinPackets() const {return SSH_BRUTEFORCE_OUT_MIN_PACKETS;} - inline uint16_t getSSHOutMaxPackets() const {return SSH_BRUTEFORCE_OUT_MAX_PACKETS;} - inline uint16_t getSSHOutMinBytes() const {return SSH_BRUTEFORCE_OUT_MIN_BYTES;} - inline uint16_t getSSHOutMaxBytes() const {return SSH_BRUTEFORCE_OUT_MAX_BYTES;} + inline uint16_t getSSHOutMinPackets() const { return SSH_BRUTEFORCE_OUT_MIN_PACKETS; } + + inline uint16_t getSSHOutMaxPackets() const { return SSH_BRUTEFORCE_OUT_MAX_PACKETS; } + + inline uint16_t getSSHOutMinBytes() const { return SSH_BRUTEFORCE_OUT_MIN_BYTES; } + + inline uint16_t getSSHOutMaxBytes() const { return SSH_BRUTEFORCE_OUT_MAX_BYTES; } + + //RDP + inline uint16_t getRDPMaxRecords() const { return RDP_MAX_RECORDS; } + + inline uint16_t getRDPFlowThreshold() const { return RDP_FLOW_THRESHOLD; } + + inline double getRDPMatchedFlowRatio() const { return RDP_MATCHED_FLOW_RATIO; } + + inline ur_time_t getRDPRecordTimeout() const { return RDP_RECORD_TIMEOUT; } + + inline ur_time_t getRDPHostDeleteTimeout() const { return RDP_HOST_TIMEOUT; } - //RDP - inline uint16_t getRDPMaxListSize() const {return RDP_LIST_SIZE;} - inline uint16_t getRDPListThreshold() const {return RDP_LIST_THRESHOLD;} - inline double getRDPMatchedFlowRatio() const {return RDP_MATCHED_FLOW_RATIO;} + inline ur_time_t getRDPReportTimeout() const { return RDP_REPORT_TIMEOUT; } - inline ur_time_t getRDPRecordTimeout() const {return RDP_RECORD_TIMEOUT;} - inline ur_time_t getRDPHostDeleteTimeout() const {return RDP_HOST_TIMEOUT;} - inline ur_time_t getRDPReportTimeout() const {return RDP_REPORT_TIMEOUT;} - inline ur_time_t getRDPAttackTimeout() const {return RDP_ATTACK_TIMEOUT;} + inline ur_time_t getRDPAttackTimeout() const { return RDP_ATTACK_TIMEOUT; } // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) - inline uint16_t getRDPIncMinPackets() const {return RDP_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getRDPIncMaxPackets() const {return RDP_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getRDPIncMinBytes() const {return RDP_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getRDPIncMaxBytes() const {return RDP_BRUTEFORCE_INC_MAX_BYTES;} - - // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) - inline uint16_t getRDPOutMinPackets() const {return RDP_BRUTEFORCE_OUT_MIN_PACKETS;} - inline uint16_t getRDPOutMaxPackets() const {return RDP_BRUTEFORCE_OUT_MAX_PACKETS;} - inline uint16_t getRDPOutMinBytes() const {return RDP_BRUTEFORCE_OUT_MIN_BYTES;} - inline uint32_t getRDPOutMaxBytes() const {return RDP_BRUTEFORCE_OUT_MAX_BYTES;} - - //TELNET - inline uint16_t getTELNETMaxListSize() const {return TELNET_LIST_SIZE;} - inline uint16_t getTELNETListThreshold() const {return TELNET_LIST_THRESHOLD;} - inline double getTELNETMatchedFlowRatio() const {return TELNET_MATCHED_FLOW_RATIO;} - - inline ur_time_t getTELNETRecordTimeout() const {return TELNET_RECORD_TIMEOUT;} - inline ur_time_t getTELNETHostDeleteTimeout()const {return TELNET_HOST_TIMEOUT;} - inline ur_time_t getTELNETReportTimeout() const {return TELNET_REPORT_TIMEOUT;} - inline ur_time_t getTELNETAttackTimeout() const {return TELNET_ATTACK_TIMEOUT;} - - inline uint16_t getTELNETIncMinPackets() const {return TELNET_BRUTEFORCE_INC_MIN_PACKETS;} - inline uint16_t getTELNETIncMaxPackets() const {return TELNET_BRUTEFORCE_INC_MAX_PACKETS;} - inline uint16_t getTELNETIncMinBytes() const {return TELNET_BRUTEFORCE_INC_MIN_BYTES;} - inline uint16_t getTELNETIncMaxBytes() const {return TELNET_BRUTEFORCE_INC_MAX_BYTES;} - - // TODO Where is telnet outgoing - - static Config& getInstance() - { + inline uint16_t getRDPIncMinPackets() const { return RDP_BRUTEFORCE_INC_MIN_PACKETS; } + + inline uint16_t getRDPIncMaxPackets() const { return RDP_BRUTEFORCE_INC_MAX_PACKETS; } + + inline uint16_t getRDPIncMinBytes() const { return RDP_BRUTEFORCE_INC_MIN_BYTES; } + + inline uint16_t getRDPIncMaxBytes() const { return RDP_BRUTEFORCE_INC_MAX_BYTES; } + + // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) + inline uint16_t getRDPOutMinPackets() const { return RDP_BRUTEFORCE_OUT_MIN_PACKETS; } + + inline uint16_t getRDPOutMaxPackets() const { return RDP_BRUTEFORCE_OUT_MAX_PACKETS; } + + inline uint16_t getRDPOutMinBytes() const { return RDP_BRUTEFORCE_OUT_MIN_BYTES; } + + inline uint32_t getRDPOutMaxBytes() const { return RDP_BRUTEFORCE_OUT_MAX_BYTES; } + + //TELNET + inline uint16_t getTELNETMaxRecords() const { return TELNET_MAX_RECORDS; } + + inline uint16_t getTELNETFlowThreshold() const { return TELNET_FLOW_THRESHOLD; } + + inline double getTELNETMatchedFlowRatio() const { return TELNET_MATCHED_FLOW_RATIO; } + + inline ur_time_t getTELNETRecordTimeout() const { return TELNET_RECORD_TIMEOUT; } + + inline ur_time_t getTELNETHostDeleteTimeout() const { return TELNET_HOST_TIMEOUT; } + + inline ur_time_t getTELNETReportTimeout() const { return TELNET_REPORT_TIMEOUT; } + + inline ur_time_t getTELNETAttackTimeout() const { return TELNET_ATTACK_TIMEOUT; } + + inline uint16_t getTELNETIncMinPackets() const { return TELNET_BRUTEFORCE_INC_MIN_PACKETS; } + + inline uint16_t getTELNETIncMaxPackets() const { return TELNET_BRUTEFORCE_INC_MAX_PACKETS; } + + inline uint16_t getTELNETIncMinBytes() const { return TELNET_BRUTEFORCE_INC_MIN_BYTES; } + + inline uint16_t getTELNETIncMaxBytes() const { return TELNET_BRUTEFORCE_INC_MAX_BYTES; } + + static Config &getInstance() { static Config instance; return instance; } @@ -135,33 +167,30 @@ class Config { private: Config(); + std::string configPath; //general ur_time_t GENERAL_CHECK_FOR_REPORT_TIMEOUT; ur_time_t GENERAL_CHECK_FOR_DELETE_TIMEOUT; - uint16_t GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; - double GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; - uint8_t GENERAL_IGNORE_FIRST_SEND; - // double GENERAL_MATCHED_FLOW_RATIO; + uint16_t GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; + double GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; + uint8_t GENERAL_IGNORE_FIRST_SEND; std::string kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT; std::string kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT; std::string kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT; std::string kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST; std::string kw_GENERAL_IGNORE_FIRST_SEND; - std::string kw_GENERAL_MATCHED_FLOW_RATIO; - //SSH - uint16_t SSH_LIST_SIZE; - uint16_t SSH_LIST_THRESHOLD; - uint16_t SSH_LIST_SIZE_BOTTOM_THRESHOLD; - double SSH_MATCHED_FLOW_RATIO; + uint16_t SSH_MAX_RECORDS; + uint16_t SSH_FLOW_THRESHOLD; + double SSH_MATCHED_FLOW_RATIO; - ur_time_t SSH_RECORD_TIMEOUT; + ur_time_t SSH_RECORD_TIMEOUT; ur_time_t SSH_HOST_TIMEOUT; ur_time_t SSH_REPORT_TIMEOUT; ur_time_t SSH_ATTACK_TIMEOUT; @@ -177,9 +206,8 @@ class Config { uint16_t SSH_BRUTEFORCE_OUT_MAX_BYTES; //SSH keywords - std::string kw_SSH_LIST_SIZE; - std::string kw_SSH_LIST_THRESHOLD; - std::string kw_SSH_LIST_SIZE_BOTTOM_THRESHOLD; + std::string kw_SSH_MAX_RECORDS; + std::string kw_SSH_FLOW_THRESHOLD; std::string kw_SSH_MATCHED_FLOW_RATIO; std::string kw_SSH_RECORD_TIMEOUT; std::string kw_SSH_HOST_TIMEOUT; @@ -196,12 +224,11 @@ class Config { //RDP - uint16_t RDP_LIST_SIZE; - uint16_t RDP_LIST_SIZE_BOTTOM_THRESHOLD; - uint16_t RDP_LIST_THRESHOLD; - double RDP_MATCHED_FLOW_RATIO; + uint16_t RDP_MAX_RECORDS; + uint16_t RDP_FLOW_THRESHOLD; + double RDP_MATCHED_FLOW_RATIO; - ur_time_t RDP_RECORD_TIMEOUT; + ur_time_t RDP_RECORD_TIMEOUT; ur_time_t RDP_HOST_TIMEOUT; ur_time_t RDP_REPORT_TIMEOUT; ur_time_t RDP_ATTACK_TIMEOUT; @@ -217,9 +244,8 @@ class Config { uint32_t RDP_BRUTEFORCE_OUT_MAX_BYTES; //RDP keywords - std::string kw_RDP_LIST_SIZE; - std::string kw_RDP_LIST_THRESHOLD; - std::string kw_RDP_LIST_SIZE_BOTTOM_THRESHOLD; + std::string kw_RDP_MAX_RECORDS; + std::string kw_RDP_FLOW_THRESHOLD; std::string kw_RDP_MATCHED_FLOW_RATIO; std::string kw_RDP_RECORD_TIMEOUT; std::string kw_RDP_HOST_TIMEOUT; @@ -235,36 +261,34 @@ class Config { std::string kw_RDP_ATTACK_TIMEOUT; - //TELNET - uint16_t TELNET_LIST_SIZE; - uint16_t TELNET_LIST_THRESHOLD; - uint16_t TELNET_LIST_SIZE_BOTTOM_THRESHOLD; - double TELNET_MATCHED_FLOW_RATIO; - - ur_time_t TELNET_RECORD_TIMEOUT; - ur_time_t TELNET_HOST_TIMEOUT; - ur_time_t TELNET_REPORT_TIMEOUT; - ur_time_t TELNET_ATTACK_TIMEOUT; - - uint16_t TELNET_BRUTEFORCE_INC_MIN_PACKETS; - uint16_t TELNET_BRUTEFORCE_INC_MAX_PACKETS; - uint16_t TELNET_BRUTEFORCE_INC_MIN_BYTES; - uint16_t TELNET_BRUTEFORCE_INC_MAX_BYTES; - - //TELNET keywords - std::string kw_TELNET_LIST_SIZE; - std::string kw_TELNET_LIST_THRESHOLD; - std::string kw_TELNET_LIST_SIZE_BOTTOM_THRESHOLD; - std::string kw_TELNET_MATCHED_FLOW_RATIO; - - std::string kw_TELNET_RECORD_TIMEOUT; - std::string kw_TELNET_HOST_TIMEOUT; - std::string kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS; - std::string kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS; - std::string kw_TELNET_BRUTEFORCE_INC_MIN_BYTES; - std::string kw_TELNET_BRUTEFORCE_INC_MAX_BYTES; - std::string kw_TELNET_REPORT_TIMEOUT; - std::string kw_TELNET_ATTACK_TIMEOUT; + //TELNET + uint16_t TELNET_MAX_RECORDS; + uint16_t TELNET_FLOW_THRESHOLD; + double TELNET_MATCHED_FLOW_RATIO; + + ur_time_t TELNET_RECORD_TIMEOUT; + ur_time_t TELNET_HOST_TIMEOUT; + ur_time_t TELNET_REPORT_TIMEOUT; + ur_time_t TELNET_ATTACK_TIMEOUT; + + uint16_t TELNET_BRUTEFORCE_INC_MIN_PACKETS; + uint16_t TELNET_BRUTEFORCE_INC_MAX_PACKETS; + uint16_t TELNET_BRUTEFORCE_INC_MIN_BYTES; + uint16_t TELNET_BRUTEFORCE_INC_MAX_BYTES; + + //TELNET keywords + std::string kw_TELNET_MAX_RECORDS; + std::string kw_TELNET_FLOW_THRESHOLD; + std::string kw_TELNET_MATCHED_FLOW_RATIO; + + std::string kw_TELNET_RECORD_TIMEOUT; + std::string kw_TELNET_HOST_TIMEOUT; + std::string kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS; + std::string kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS; + std::string kw_TELNET_BRUTEFORCE_INC_MIN_BYTES; + std::string kw_TELNET_BRUTEFORCE_INC_MAX_BYTES; + std::string kw_TELNET_REPORT_TIMEOUT; + std::string kw_TELNET_ATTACK_TIMEOUT; }; diff --git a/brute_force_detector/config/config.conf b/brute_force_detector/config/config.conf index f26e45e3..de871a35 100644 --- a/brute_force_detector/config/config.conf +++ b/brute_force_detector/config/config.conf @@ -65,12 +65,13 @@ ######################## ######### SSH ########## ######################## -#SSH_ATTACK_TIMEOUT = 600 -#SSH_LIST_SIZE = 100 -#SSH_LIST_THRESHOLD = 90 +#SSH_MAX_RECORDS = 500 +#SSH_FLOW_THRESHOLD = 90 #SSH_MATCHED_FLOW_RATIO = 0.9 -#SSH_RECORD_TIMEOUT = 1800 +#SSH_ATTACK_TIMEOUT = 600 +#SSH_RECORD_TIMEOUT = 3600 #SSH_HOST_TIMEOUT = 4200 +#SSH_REPORT_TIMEOUT = 300 #SSH_BRUTEFORCE_INC_MIN_PACKETS = 11 #SSH_BRUTEFORCE_INC_MAX_PACKETS = 30 #SSH_BRUTEFORCE_INC_MIN_BYTES = 1000 @@ -79,16 +80,16 @@ #SSH_BRUTEFORCE_OUT_MAX_PACKETS = 50 #SSH_BRUTEFORCE_OUT_MIN_BYTES = 1000 #SSH_BRUTEFORCE_OUT_MAX_BYTES = 11000 -#SSH_REPORT_TIMEOUT = 300 ######################## ######### RDP ########## ######################## -#RDP_ATTACK_TIMEOUT = 600 -#RDP_LIST_SIZE = 500 -#RDP_LIST_THRESHOLD = 90 +#RDP_MAX_RECORDS = 500 +#RDP_FLOW_THRESHOLD = 90 #RDP_MATCHED_FLOW_RATIO = 0.9 -#RDP_RECORD_TIMEOUT = 1800 +#RDP_ATTACK_TIMEOUT = 600 +#RDP_RECORD_TIMEOUT = 3600 #RDP_HOST_TIMEOUT = 4200 +#RDP_REPORT_TIMEOUT = 300 #RDP_BRUTEFORCE_INC_MIN_PACKETS = 20 #RDP_BRUTEFORCE_INC_MAX_PACKETS = 100 #RDP_BRUTEFORCE_INC_MIN_BYTES = 2200 @@ -97,19 +98,18 @@ #RDP_BRUTEFORCE_OUT_MAX_PACKETS = 190 #RDP_BRUTEFORCE_OUT_MIN_BYTES = 3000 #RDP_BRUTEFORCE_OUT_MAX_BYTES = 180000 -#RDP_REPORT_TIMEOUT = 300 ######################## ######## Telnet ######## ######################## -#TELNET_LIST_SIZE = 100 -#TELNET_LIST_THRESHOLD = 90 +#TELNET_MAX_RECORDS = 500 +#TELNET_FLOW_THRESHOLD = 90 #TELNET_MATCHED_FLOW_RATIO = 0.9 -#TELNET_RECORD_TIMEOUT = 1800 +#TELNET_ATTACK_TIMEOUT = 600 +#TELNET_RECORD_TIMEOUT = 3600 #TELNET_HOST_TIMEOUT = 4200 +#TELNET_REPORT_TIMEOUT = 300 #TELNET_BRUTEFORCE_INC_MIN_PACKETS = 9 #TELNET_BRUTEFORCE_INC_MAX_PACKETS = 50 #TELNET_BRUTEFORCE_INC_MIN_BYTES = 450 #TELNET_BRUTEFORCE_INC_MAX_BYTES = 3000 ## Outgoing direction is not supported -#TELNET_ATTACK_TIMEOUT = 600 -#TELNET_REPORT_TIMEOUT = 300 diff --git a/brute_force_detector/config/whitelist.wl b/brute_force_detector/config/whitelist.wl index cb1626eb..75d85a7a 100644 --- a/brute_force_detector/config/whitelist.wl +++ b/brute_force_detector/config/whitelist.wl @@ -19,7 +19,7 @@ dst 131.103.20.160/28/22 #bitbucket src 166.88.20.3/32 # EGIHosting (USA) ?, valid communication to 195.113.184.18, src 195.113.44.19/32 # Charles University (CZ), valid(???) communication to 88.208.125.10 & 88.208.125.11, - +179.176.223.171 diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index 1657317e..e957fdd1 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -53,17 +53,21 @@ bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) { // ignore port-scans if (isFlowScan(&st.packets, &st.flags)) { return false; - } else if (st.packets == 1 && st.flags == 0b00010000) // skip ack only packet + } + else if (st.packets == 1 && st.flags == 0b00010000) // skip ack only packet { return false; - } else if (st.packets == 4 && st.flags == 0b00000010) // 4 packet SYN request + } + else if (st.packets == 4 && st.flags == 0b00000010) // 4 packet SYN request { return false; - } else { - timeOfLastReceivedRecord = st.flowLastSeen; + } + else { + timeOfLastReceivedRecord = st.lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - } else { + } + else { recordListOutgoing.addRecord(record, isReported()); } @@ -87,21 +91,24 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); // is flow count over a minimum threshold and is a big enough part of it matched? - if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHListThreshold() && + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getSSHFlowThreshold() && (topMatchedRatio >= Config::getInstance().getSSHMatchedFlowRatio())) { // crossed threshold, new attack detected recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return SSHHost::REPORT_NEW_ATTACK; - } else { + } + else { return SSHHost::NO_ATTACK; } - } else // isReported + } + else // isReported { // host is attacking, wait for timeout to report again if (!canReportAgain(actualTime)) { return SSHHost::ATTACK_REPORT_WAIT; - } else { + } + else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); @@ -125,7 +132,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return SSHHost::REPORT_END_OF_ATTACK; - } else { + } + else { return SSHHost::END_OF_ATTACK; } } @@ -133,7 +141,8 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return SSHHost::REPORT_ATTACK; - } else { + } + else { return SSHHost::ATTACK_MIN_EVENTS_WAIT; } } @@ -149,11 +158,13 @@ bool RDPHost::addRecord(RDPRecord *record, void *structure, uint8_t direction) { // ignore port-scans if (isFlowScan(&st.packets, &st.flags)) { return false; - } else { - timeOfLastReceivedRecord = st.flowLastSeen; + } + else { + timeOfLastReceivedRecord = st.lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - } else { + } + else { recordListOutgoing.addRecord(record, isReported()); } return true; @@ -174,22 +185,25 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); // is flow count over a minimum threshold and is a big enough part of it matched? - if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPListThreshold() && + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getRDPFlowThreshold() && (topMatchedRatio >= Config::getInstance().getRDPMatchedFlowRatio())) { recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return RDPHost::REPORT_NEW_ATTACK; - } else { + } + else { return RDPHost::NO_ATTACK; } - } else // isReported + } + else // isReported { // host is attacking, wait for timeout to report again if (!canReportAgain(actualTime)) { return RDPHost::ATTACK_REPORT_WAIT; - } else { + } + else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); @@ -213,7 +227,8 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return RDPHost::REPORT_END_OF_ATTACK; - } else { + } + else { return RDPHost::END_OF_ATTACK; } } @@ -221,7 +236,8 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return RDPHost::REPORT_ATTACK; - } else { + } + else { return RDPHost::ATTACK_MIN_EVENTS_WAIT; } } @@ -237,11 +253,13 @@ bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direct // ignore port-scans if (isFlowScan(&st.packets, &st.flags)) { return false; - } else { - timeOfLastReceivedRecord = st.flowLastSeen; + } + else { + timeOfLastReceivedRecord = st.lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - } else { + } + else { recordListOutgoing.addRecord(record, isReported()); } return true; @@ -261,21 +279,24 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { double topMatchedRatio = std::max(incomingMatchedRatio, outgoingMatchedRatio); // is flow count over a minimum threshold and is a big enough part of it matched? - if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETListThreshold() && + if (std::max(incomingMatched, outgoingMatched) >= Config::getInstance().getTELNETFlowThreshold() && (topMatchedRatio >= Config::getInstance().getTELNETMatchedFlowRatio())) { recordListIncoming.initTotalTargetsSet(); recordListOutgoing.initTotalTargetsSet(); return TELNETHost::REPORT_NEW_ATTACK; - } else { + } + else { return TELNETHost::NO_ATTACK; } - } else // isReported + } + else // isReported { // host is attacking, wait for timeout to report again if (!canReportAgain(actualTime)) { return TELNETHost::ATTACK_REPORT_WAIT; - } else { + } + else { uint32_t incomingMatchedNew = recordListIncoming.getMatchedFlowsSinceLastReport(); uint32_t incomingTotalNew = recordListIncoming.getTotalFlowsSinceLastReport(); @@ -298,7 +319,8 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return TELNETHost::REPORT_END_OF_ATTACK; - } else { + } + else { return TELNETHost::END_OF_ATTACK; } } @@ -306,7 +328,8 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { if (std::max(incomingMatchedNew, outgoingMatchedNew) >= Config::getInstance().getGlobalAttackMinEvToReport()) { return TELNETHost::REPORT_ATTACK; - } else { + } + else { return TELNETHost::ATTACK_MIN_EVENTS_WAIT; } } @@ -321,19 +344,21 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { ip = structure->srcIp; - } else { + } + else { ip = structure->dstIp; } - auto it = hostMap.find(ip); + std::map::iterator it = hostMap.find(ip); SSHHost *host; if (it == hostMap.end()) { // not found, create new host - host = new SSHHost(ip, structure->flowFirstSeen); + host = new SSHHost(ip, structure->firstSeen); hostMap.insert(std::pair(ip, host)); - } else { + } + else { host = it->second; } @@ -341,8 +366,8 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct } void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for (const auto &it : hostMap) { - SSHHost *host = it.second; + for (std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) { + SSHHost *host = it->second; if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); @@ -367,19 +392,21 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { ip = structure->srcIp; - } else { + } + else { ip = structure->dstIp; // attacker is now destination address } - auto it = hostMap.find(ip); + std::map::iterator it = hostMap.find(ip); RDPHost *host; if (it == hostMap.end()) { // not found, create new host - host = new RDPHost(ip, structure->flowFirstSeen); + host = new RDPHost(ip, structure->firstSeen); hostMap.insert(std::pair(ip, host)); - } else { + } + else { host = it->second; } @@ -387,8 +414,9 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct } void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for (const auto &it : hostMap) { - RDPHost *host = it.second; + for(std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) + { + RDPHost *host = it->second; if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); @@ -413,19 +441,21 @@ TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { ip = structure->srcIp; - } else { + } + else { ip = structure->dstIp; // attacker is now destination address } - auto it = hostMap.find(ip); + std::map::iterator it = hostMap.find(ip); TELNETHost *host; if (it == hostMap.end()) { // not found, create new host - host = new TELNETHost(ip, structure->flowFirstSeen); + host = new TELNETHost(ip, structure->firstSeen); hostMap.insert(std::pair(ip, host)); - } else { + } + else { host = it->second; } @@ -433,8 +463,9 @@ TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t } void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { - for (const auto &it : hostMap) { - TELNETHost *host = it.second; + for(std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) + { + TELNETHost *host = it->second; if (host->isReported() && host->checkForAttackTimeout(actualTime)) { uint32_t numOfEvents = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 743e1ec6..712abda9 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -56,16 +56,14 @@ #include "brute_force_detector.h" - /** * Base class for host */ -template +template class IHost { public: - IHost(ip_addr_t _hostIp, ur_time_t _firstSeen) - { + IHost(ip_addr_t _hostIp, ur_time_t _firstSeen) { hostIp = _hostIp; firstSeen = _firstSeen; timeOfLastReport = 0; @@ -75,51 +73,50 @@ class IHost { virtual ~IHost() = default; - enum ATTACK_STATE { NO_ATTACK, - REPORT_NEW_ATTACK, // send report - ATTACK_REPORT_WAIT, - REPORT_ATTACK, // send report - ATTACK_MIN_EVENTS_WAIT, - END_OF_ATTACK, - REPORT_END_OF_ATTACK // send report + enum ATTACK_STATE { + NO_ATTACK, + REPORT_NEW_ATTACK, // send report + ATTACK_REPORT_WAIT, + REPORT_ATTACK, // send report + ATTACK_MIN_EVENTS_WAIT, + END_OF_ATTACK, + REPORT_END_OF_ATTACK // send report }; inline ip_addr_t getHostIp() { return hostIp; } + inline ur_time_t getTimeOfLastReport() { return timeOfLastReport; } + inline bool isReported() { return timeOfLastReport != 0; } - inline void setReportTime(ur_time_t actualTime) { timeOfLastReport = actualTime; } - inline void setNotReported() - { - recordListIncoming.clearTotalTargetsSinceAttack(); - recordListOutgoing.clearTotalTargetsSinceAttack(); + + inline void setReportTime(ur_time_t actualTime) { timeOfLastReport = actualTime; } + + inline void setNotReported() { + recordListIncoming.clearTotalTargetsSinceAttack(); + recordListOutgoing.clearTotalTargetsSinceAttack(); timeOfLastReport = 0; } inline bool getHostScannedNetwork() { return scanned; } - virtual bool addRecord(T record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) - { - if(direction == FLOW_INCOMING_DIRECTION) - { - recordListIncoming.addRecord(record, isReported()); - } - else - { - recordListOutgoing.addRecord(record, isReported()); - } + virtual bool addRecord(T record, void *structure, uint8_t direction) { + if (direction == FLOW_INCOMING_DIRECTION) { + recordListIncoming.addRecord(record, isReported()); + } + else { + recordListOutgoing.addRecord(record, isReported()); + } return true; } - void clearOldRecords(ur_time_t actualTime) - { - recordListIncoming.clearOldRecords(actualTime); - recordListOutgoing.clearOldRecords(actualTime); + void clearOldRecords(ur_time_t actualTime) { + recordListIncoming.clearOldRecords(actualTime); + recordListOutgoing.clearOldRecords(actualTime); } virtual ur_time_t getHostDeleteTimeout() = 0; - virtual bool canDeleteHost(ur_time_t actualTime) - { + virtual bool canDeleteHost(ur_time_t actualTime) { ur_time_t timer = getHostDeleteTimeout(); return checkForTimeout(timeOfLastReceivedRecord, timer, actualTime); @@ -127,43 +124,43 @@ class IHost { virtual ur_time_t getHostReportTimeout() = 0; - virtual bool canReportAgain(ur_time_t actualTime) - { + virtual bool canReportAgain(ur_time_t actualTime) { ur_time_t timer = getHostReportTimeout(); return checkForTimeout(timeOfLastReport, timer, actualTime); } virtual ur_time_t getHostAttackTimeout() = 0; - virtual bool checkForAttackTimeout(ur_time_t actualTime) - { + virtual bool checkForAttackTimeout(ur_time_t actualTime) { ur_time_t timer = getHostAttackTimeout(); return checkForTimeout(timeOfLastReport, timer, actualTime); } virtual ATTACK_STATE checkForAttack(ur_time_t actualTime) = 0; - RecordList* getPointerToIncomingRecordList() { return &recordListIncoming; } - RecordList* getPointerToOutgoingRecordList() { return &recordListOutgoing; } + RecordList *getPointerToIncomingRecordList() { return &recordListIncoming; } + + RecordList *getPointerToOutgoingRecordList() { return &recordListOutgoing; } - virtual void clearAllRecords() { recordListIncoming.clearAllRecords(); recordListOutgoing.clearAllRecords();} + virtual void clearAllRecords() { + recordListIncoming.clearAllRecords(); + recordListOutgoing.clearAllRecords(); + } - bool isFlowScan(const uint32_t *packets, const uint8_t *flags) - { - if( (*packets == 1 && *flags == 0b00000010) // SYN - || (*packets == 1 && *flags == 0b00010010) // SYN + ACK - || (*packets == 1 && *flags == 0b00010100) // RST + ACK - || (*packets == 2 && *flags == 0b00000010) // SYN - || (*packets == 2 && *flags == 0b00000110) // SYN + RST - || (*packets == 3 && *flags == 0b00000010)) // 3 SYN packets + bool isFlowScan(const uint32_t *packets, const uint8_t *flags) { + if ((*packets == 1 && *flags == 0b00000010) // SYN + || (*packets == 1 && *flags == 0b00010010) // SYN + ACK + || (*packets == 1 && *flags == 0b00010100) // RST + ACK + || (*packets == 2 && *flags == 0b00000010) // SYN + || (*packets == 2 && *flags == 0b00000110) // SYN + RST + || (*packets == 3 && *flags == 0b00000010)) // 3 SYN packets { scanned = true; return true; } - else - { - return false; - } + else { + return false; + } } protected: @@ -171,7 +168,7 @@ class IHost { bool scanned; ip_addr_t hostIp; - ur_time_t firstSeen; // TODO purpose? + ur_time_t firstSeen; // TODO unused ur_time_t timeOfLastReport; ur_time_t timeOfLastReceivedRecord; RecordList recordListIncoming; // direction to victim (attacker -> victim) @@ -179,40 +176,52 @@ class IHost { }; -class SSHHost : public IHost { +class SSHHost : public IHost { public: - SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} + SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} + + bool addRecord(SSHRecord *record, void *structure, uint8_t direction) override; + + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostDeleteTimeout(); } - bool addRecord(SSHRecord *record, void *structure, uint8_t direction) override; - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getSSHReportTimeout(); } + ur_time_t getHostAttackTimeout() override { return Config::getInstance().getSSHAttackTimeout(); } }; -class RDPHost : public IHost { +class RDPHost : public IHost { public: - RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} + RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} + + bool addRecord(RDPRecord *record, void *structure, uint8_t direction) override; + + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostDeleteTimeout(); } - bool addRecord(RDPRecord *record, void *structure, uint8_t direction) override; - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostDeleteTimeout(); } ur_time_t getHostReportTimeout() override { return Config::getInstance().getRDPReportTimeout(); } + ur_time_t getHostAttackTimeout() override { return Config::getInstance().getRDPAttackTimeout(); } }; -class TELNETHost : public IHost { +class TELNETHost : public IHost { public: - TELNETHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost (hostIp, firstSeen) {} + TELNETHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} + + bool addRecord(TELNETRecord *record, void *structure, uint8_t direction) override; + + ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + + ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostDeleteTimeout(); } + + ur_time_t getHostReportTimeout() override { return Config::getInstance().getTELNETReportTimeout(); } - bool addRecord(TELNETRecord *record, void *structure, uint8_t direction) override; - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostDeleteTimeout(); } - ur_time_t getHostReportTimeout() override { return Config::getInstance().getTELNETReportTimeout(); } ur_time_t getHostAttackTimeout() override { return Config::getInstance().getTELNETAttackTimeout(); } }; @@ -224,26 +233,25 @@ class IHostMap { public: IHostMap() = default; - ~IHostMap() = default; - virtual void clear() = 0; - virtual inline uint16_t size() = 0; + ~IHostMap() = default; + + virtual void clear() = 0; + + virtual inline uint16_t size() = 0; - virtual void deleteOldRecordAndHosts(ur_time_t actualTime) = 0; - virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) = 0; + virtual void deleteOldRecordAndHosts(ur_time_t actualTime) = 0; + + virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) = 0; protected: template - void clearMap(Container *c) - { - auto it = c->begin(); - - while(it != c->end()) - { - if(it->second) // TODO harmless to remove this? - delete it->second; + void clearMap(Container *c) { + typename Container::iterator it = c->begin(); + while (it != c->end()) { + delete it->second; it++; } c->clear(); @@ -257,26 +265,22 @@ class IHostMap { * @param actualTime */ template - void clearOldRecAndHost(Container *c, ur_time_t actualTime) - { + void clearOldRecAndHost(Container *c, ur_time_t actualTime) { typename Container::iterator it = c->begin(); - // iterating over map (or RDPHost* or TELNETHost*) + // iterating over map (or RDPHost* or TELNETHost*) - while(it != c->end()) - { + while (it != c->end()) { it->second->clearOldRecords(actualTime); bool canDelete = it->second->canDeleteHost(actualTime); - if(canDelete) - { + if (canDelete) { delete it->second; c->erase(it++); } - else - { - it++; - } + else { + it++; + } } } }; @@ -285,72 +289,76 @@ class SSHHostMap : public IHostMap { public: SSHHostMap() = default; + ~SSHHostMap() = default; - void clear() override - { - IHostMap::clearMap(&hostMap); - } - inline uint16_t size() override - { + void clear() override { + IHostMap::clearMap(&hostMap); + } + + inline uint16_t size() override { return hostMap.size(); } SSHHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: - map hostMap; + map hostMap; }; -class RDPHostMap: public IHostMap { +class RDPHostMap : public IHostMap { public: RDPHostMap() = default; + ~RDPHostMap() = default; - void clear() override - { - IHostMap::clearMap(&hostMap); - } + void clear() override { + IHostMap::clearMap(&hostMap); + } - inline uint16_t size() override - { + inline uint16_t size() override { return hostMap.size(); } RDPHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: - map hostMap; + map hostMap; }; -class TELNETHostMap: public IHostMap { +class TELNETHostMap : public IHostMap { public: TELNETHostMap() = default; + ~TELNETHostMap() = default; - void clear() override - { - IHostMap::clearMap(&hostMap); + void clear() override { + IHostMap::clearMap(&hostMap); } - inline uint16_t size() override - { + inline uint16_t size() override { return hostMap.size(); } TELNETHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; private: - map hostMap; + map hostMap; }; #endif // HOST_H diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 4304e3b2..8744b749 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -48,62 +48,56 @@ // ************************ SSH RECORD ***********************/ // ************************************************************/ -SSHRecord::SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) -{ +SSHRecord::SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->dstIp = dstIp; this->flowLastSeen = flowLastSeen; } -bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; - if((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) - { - return false; - } + if ((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { + return false; + } - if(st.packets > Config::getInstance().getSSHIncMaxPackets() || st.packets < Config::getInstance().getSSHIncMinPackets()) - { - return false; - } + if (st.packets > Config::getInstance().getSSHIncMaxPackets() || + st.packets < Config::getInstance().getSSHIncMinPackets()) { + return false; + } - if(st.bytes > Config::getInstance().getSSHIncMaxBytes() || st.bytes < Config::getInstance().getSSHIncMinBytes()) - { - return false; - } + if (st.bytes > Config::getInstance().getSSHIncMaxBytes() || st.bytes < Config::getInstance().getSSHIncMinBytes()) { + return false; + } - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { + std::cerr << "w\n"; return false; } + signatureMatched = true; return true; } -bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); - if((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) - { - return false; - } + if ((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { + return false; + } - if(st.packets > Config::getInstance().getSSHOutMaxPackets() || st.packets < Config::getInstance().getSSHOutMinPackets()) - { - return false; - } + if (st.packets > Config::getInstance().getSSHOutMaxPackets() || + st.packets < Config::getInstance().getSSHOutMinPackets()) { + return false; + } - if(st.bytes > Config::getInstance().getSSHOutMaxBytes() || st.bytes < Config::getInstance().getSSHOutMinBytes()) - { - return false; - } + if (st.bytes > Config::getInstance().getSSHOutMaxBytes() || st.bytes < Config::getInstance().getSSHOutMinBytes()) { + return false; + } - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -117,30 +111,25 @@ bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) // ************************ RDP RECORD ***********************/ // ************************************************************/ -RDPRecord::RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) -{ +RDPRecord::RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->dstIp = dstIp; this->flowLastSeen = flowLastSeen; } -bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; // Win8 manual input - if((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) - { - // s port, d port, packets, bytes, flags + if ((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) { + // s port, d port, packets, bytes, flags // 42315, 3389, 8, 1691, 30 // 42345, 3389, 9, 1747, 30 - if(st.packets >= 7 && st.packets <= 11 && st.bytes >= 1500 && st.bytes <= 2000) - { - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if (st.packets >= 7 && st.packets <= 11 && st.bytes >= 1500 && st.bytes <= 2000) { + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { return false; } signatureMatched = true; @@ -150,15 +139,12 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) // Ncrack/thc hydra to win8 unsuccessful connection - if((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) - { - // s port, d port, packets, bytes, flags + if ((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { + // s port, d port, packets, bytes, flags // 37501, 3389, 3, 165, 26 - if(st.packets == 3 && ( st.bytes >= 100 && st.bytes <= 200)) - { - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if (st.packets == 3 && (st.bytes >= 100 && st.bytes <= 200)) { + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { return false; } signatureMatched = true; @@ -167,22 +153,19 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) } - if((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) - { - return false; - } + if ((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { + return false; + } - if(st.packets > Config::getInstance().getRDPIncMaxPackets() || st.packets < Config::getInstance().getRDPIncMinPackets()) - { - return false; - } - if(st.bytes > Config::getInstance().getRDPIncMaxBytes() || st.bytes < Config::getInstance().getRDPIncMinBytes()) - { - return false; - } + if (st.packets > Config::getInstance().getRDPIncMaxPackets() || + st.packets < Config::getInstance().getRDPIncMinPackets()) { + return false; + } + if (st.bytes > Config::getInstance().getRDPIncMaxBytes() || st.bytes < Config::getInstance().getRDPIncMinBytes()) { + return false; + } - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { return false; } @@ -190,23 +173,20 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return true; } -bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; // Win8 manual input - if((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) - { - // s port, d port, packets, bytes, flags + if ((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) { + // s port, d port, packets, bytes, flags // 3389, 42320, 7, 1882, 26 // 3389, 42303, 7, 1951, 26 - if(st.packets == 7 && st.bytes >= 1700 && st.bytes <= 2200) - { - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (st.packets == 7 && st.bytes >= 1700 && st.bytes <= 2200) { + if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -217,14 +197,12 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) // Ncrack/thc hydra to win8 unsuccessful connection - if((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) - { - // s port, d port, packets, bytes, flags + if ((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { + // s port, d port, packets, bytes, flags // 3389, 37639, 2, 92, 22 - if(st.packets == 2 && ( st.bytes > 80 && st.bytes < 120)) - { - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (st.packets == 2 && (st.bytes > 80 && st.bytes < 120)) { + if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -233,22 +211,20 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) } } - if((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) - { - return false; - } + if ((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { + return false; + } - if(st.packets > Config::getInstance().getRDPOutMaxPackets() || st.packets < Config::getInstance().getRDPOutMinPackets()) - { - return false; - } - if(st.bytes > Config::getInstance().getRDPOutMaxBytes() || st.bytes < Config::getInstance().getRDPOutMinBytes()) - { - return false; - } + if (st.packets > Config::getInstance().getRDPOutMaxPackets() || + st.packets < Config::getInstance().getRDPOutMinPackets()) { + return false; + } + if (st.bytes > Config::getInstance().getRDPOutMaxBytes() || st.bytes < Config::getInstance().getRDPOutMinBytes()) { + return false; + } - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port { return false; } @@ -262,34 +238,30 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) // ********************** TELNET RECORD **********************/ // ************************************************************/ -TELNETRecord::TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) -{ +TELNETRecord::TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->dstIp = dstIp; this->flowLastSeen = flowLastSeen; } -bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; - if((st.flags & TELNETRecord::signatureFlags) != TELNETRecord::signatureFlags) - { - return false; - } - - if(st.packets > Config::getInstance().getTELNETIncMaxPackets() || st.packets < Config::getInstance().getTELNETIncMinPackets()) - { - return false; - } - if(st.bytes > Config::getInstance().getTELNETIncMaxBytes() || st.bytes < Config::getInstance().getTELNETIncMinBytes()) - { - return false; - } - - if(wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) - { + if ((st.flags & TELNETRecord::signatureFlags) != TELNETRecord::signatureFlags) { + return false; + } + + if (st.packets > Config::getInstance().getTELNETIncMaxPackets() || + st.packets < Config::getInstance().getTELNETIncMinPackets()) { + return false; + } + if (st.bytes > Config::getInstance().getTELNETIncMaxBytes() || + st.bytes < Config::getInstance().getTELNETIncMinBytes()) { + return false; + } + + if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { return false; } @@ -298,42 +270,35 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) } -bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) -{ - IRecord::MatchStructure st = *(IRecord::MatchStructure*)(structure); +bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { + IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); signatureMatched = false; - if((st.flags & TELNETRecord::signatureFlagsFin) != TELNETRecord::signatureFlagsFin) - { + if ((st.flags & TELNETRecord::signatureFlagsFin) != TELNETRecord::signatureFlagsFin) { return false; - } + } - TelnetServerProfile * TSPProfile = TSPMap.findProfile(st.srcIp); - if(TSPProfile == nullptr) - { - TSPProfile = TSPMap.createProfile(st.srcIp, st.flowFirstSeen); - } + TelnetServerProfile *TSPProfile = TSPMap.findProfile(st.srcIp); + if (TSPProfile == NULL) { + TSPProfile = TSPMap.createProfile(st.srcIp, st.firstSeen); + } TSPProfile->profileWithNewData(st.packets, st.bytes); - if(st.packets < 6) // FIXME magic constant - { + if (st.packets < TELNET_OUTGOING_MIN_PACKETS) { return false; - } + } //for max range only - if(TSPProfile->isProfiled()) - { - if(st.packets > TSPProfile->getMaxPackets() || st.bytes > TSPProfile->getMaxBytes()) - { + if (TSPProfile->isProfiled()) { + if (st.packets > TSPProfile->getMaxPackets() || st.bytes > TSPProfile->getMaxBytes()) { return false; - } + } } - else - { + else { return false; - } + } signatureMatched = true; return true; diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index e922431b..5d7e4a01 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -61,10 +61,8 @@ // class TelnetServerProfileMap #include "telnet_server_profile.h" -// TODO find better place to put this as a global function -inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTime) -{ - return oldTime + timer <= newTime; +inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTime) { + return oldTime + timer <= newTime; } /** @@ -73,16 +71,19 @@ inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTim class IRecord { public: - IRecord () : signatureMatched(false) {} + IRecord() : signatureMatched(false) {} + virtual ~IRecord() = default; + virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl) = 0; + virtual bool matchWithOutgoingSignature(void *structure, Whitelist *wl) = 0; inline bool isMatched() { return signatureMatched; } + virtual ur_time_t getRecordTimeout() = 0; - struct MatchStructure - { + struct MatchStructure { uint8_t flags; uint32_t packets; uint64_t bytes; @@ -90,13 +91,13 @@ class IRecord { ip_addr_t dstIp; uint16_t srcPort; uint16_t dstPort; - ur_time_t flowFirstSeen; - ur_time_t flowLastSeen; + ur_time_t firstSeen; + ur_time_t lastSeen; }; // May seem unused, actually are passed to reporting functions - ip_addr_t dstIp{}; - ur_time_t flowLastSeen{}; + ip_addr_t dstIp{}; + ur_time_t flowLastSeen{}; protected: @@ -108,8 +109,11 @@ class SSHRecord : public IRecord { public: SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getSSHRecordTimeout(); } const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH @@ -120,11 +124,14 @@ class RDPRecord : public IRecord { public: RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } - const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; // SYN + ACK + PSH + RST const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; // SYN + ACK + PSH }; @@ -134,12 +141,15 @@ class TELNETRecord : public IRecord { public: TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); + bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + ur_time_t getRecordTimeout() override { return Config::getInstance().getTELNETRecordTimeout(); } - const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH - const static uint8_t signatureFlagsFin = 0b00011011; // SYN + ACK + PSH + FIN + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH + const static uint8_t signatureFlagsFin = 0b00011011; // SYN + ACK + PSH + FIN private: static TelnetServerProfileMap TSPMap; @@ -150,29 +160,42 @@ class RecordList { public: RecordList(); + ~RecordList(); void addRecord(T record, bool isHostReported); + void setNewMaxListSize(uint16_t newMaxListSize); + void clearOldRecords(ur_time_t actualTime); + void clearAllRecords(); + ur_time_t getTimeOfLastRecord(); inline uint16_t getActualListSize() { return actualListSize; }; + inline uint16_t getActualMatchedFlows() { return actualMatchedFlows; } + inline uint32_t getMatchedFlowsSinceLastReport() { return matchedFlowsSinceLastReport; } + inline uint32_t getTotalFlowsSinceLastReport() { return totalFlowsSinceLastReport; } + inline void clearMatchedFlowsSinceLastReport() { matchedFlowsSinceLastReport = 0; } + inline void clearTotalFlowsSinceLastReport() { totalFlowsSinceLastReport = 0; } - inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } - inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } + inline uint16_t getTargetsSinceLastReport() { return hashedDstIPSet.size(); } + + inline void clearTargetsSinceLastReport() { hashedDstIPSet.clear(); } + + inline uint16_t getCurrentTargets(); // TODO unused - inline uint16_t getCurrentTargets(); // TODO never used, investigate + inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } - inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } - inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } - inline void initTotalTargetsSet(); + inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } + + inline void initTotalTargetsSet(); std::vector getIpsOfVictims(); @@ -184,63 +207,54 @@ class RecordList { uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; - uint32_t flowCounter; - uint32_t flowMatchedCounter; + uint32_t flowCounter; + uint32_t flowMatchedCounter; - // These keep track of all IPs, even after the host becomes inactive, for output log - std::set hashedDstIPSet; - std::set hashedDstTotalIPSet; + // These keep track of all IPs, even after the host becomes inactive, for output log + std::set hashedDstIPSet; + std::set hashedDstTotalIPSet; char victimIP[46]{}; }; -template -RecordList::RecordList() -{ +template +RecordList::RecordList() { actualListSize = 0; actualMatchedFlows = 0; matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; - flowCounter = 0; - flowMatchedCounter = 0; - - if(typeid(T) == typeid(SSHRecord*)) - { - maxListSize = Config::getInstance().getSSHMaxListSize(); - } - else if(typeid(T) == typeid(RDPRecord*)) - { - maxListSize = Config::getInstance().getRDPMaxListSize(); - } - else if(typeid(T) == typeid(TELNETRecord*)) - { - maxListSize = Config::getInstance().getTELNETMaxListSize(); - } - else - { + flowCounter = 0; + flowMatchedCounter = 0; + + if (typeid(T) == typeid(SSHRecord *)) { + maxListSize = Config::getInstance().getSSHMaxRecords(); + } + else if (typeid(T) == typeid(RDPRecord *)) { + maxListSize = Config::getInstance().getRDPMaxRecords(); + } + else if (typeid(T) == typeid(TELNETRecord *)) { + maxListSize = Config::getInstance().getTELNETMaxRecords(); + } + else { std::cerr << "Error record.h: Max list size for class " << typeid(T).name() << " is not defined!\n"; std::terminate(); } } -template -RecordList::~RecordList() -{ - while(!list.empty()) - { +template +RecordList::~RecordList() { + while (!list.empty()) { T recToDel = list.front(); list.pop_front(); delete recToDel; } } -template -void RecordList::clearAllRecords() -{ - while(!list.empty()) - { +template +void RecordList::clearAllRecords() { + while (!list.empty()) { T recToDel = list.front(); list.pop_front(); delete recToDel; @@ -249,73 +263,62 @@ void RecordList::clearAllRecords() actualListSize = 0; actualMatchedFlows = 0; - flowCounter = 0; - flowMatchedCounter = 0; + flowCounter = 0; + flowMatchedCounter = 0; - matchedFlowsSinceLastReport = 0; + matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; } -template -void RecordList::addRecord(T record, bool isHostReported) -{ +template +void RecordList::addRecord(T record, bool isHostReported) { actualListSize++; - flowCounter++; + flowCounter++; - if(actualListSize > maxListSize) - { - // list is full + if (actualListSize > maxListSize) { + // list is full // delete first record - if((*list.begin())->isMatched()) - { - actualMatchedFlows--; - } + if ((*list.begin())->isMatched()) { + actualMatchedFlows--; + } T recToDelete = list.front(); delete recToDelete; list.pop_front(); actualListSize--; - // TODO Missing if(isHostReported) { totalFlowsSinceLastReport--; } ? } - if(record->isMatched()) - { + if (record->isMatched()) { actualMatchedFlows++; - flowMatchedCounter++; - } + flowMatchedCounter++; + } - if(isHostReported) - { + if (isHostReported) { totalFlowsSinceLastReport++; - if(record->isMatched()) - { + if (record->isMatched()) { matchedFlowsSinceLastReport++; - hashedDstIPSet.insert(record->dstIp); - hashedDstTotalIPSet.insert(record->dstIp); + hashedDstIPSet.insert(record->dstIp); + hashedDstTotalIPSet.insert(record->dstIp); } } list.push_back(record); } -template -void RecordList::setNewMaxListSize(uint16_t newMaxListSize) -{ +template +void RecordList::setNewMaxListSize(uint16_t newMaxListSize) { uint32_t currentMaxSize = maxListSize; - if (currentMaxSize > newMaxListSize) - { - while (actualListSize > newMaxListSize) - { + if (currentMaxSize > newMaxListSize) { + while (actualListSize > newMaxListSize) { // delete first record T recToDelete = list.front(); - if (recToDelete->isMatched()) - { - actualMatchedFlows--; - } + if (recToDelete->isMatched()) { + actualMatchedFlows--; + } delete recToDelete; list.pop_front(); @@ -331,27 +334,22 @@ void RecordList::setNewMaxListSize(uint16_t newMaxListSize) * @tparam T * @param actualTime */ -template -void RecordList::clearOldRecords(ur_time_t actualTime) -{ - if(list.empty()) - { - return; - } +template +void RecordList::clearOldRecords(ur_time_t actualTime) { + if (list.empty()) { + return; + } T rec = list.front(); ur_time_t timer = rec->getRecordTimeout(); typename std::list::iterator it = list.begin(); - while(it != list.end()) - { + while (it != list.end()) { ur_time_t flowTime = (*it)->flowLastSeen; - if (checkForTimeout(flowTime, timer, actualTime)) - { - if ((*it)->isMatched()) - { + if (checkForTimeout(flowTime, timer, actualTime)) { + if ((*it)->isMatched()) { actualMatchedFlows--; } @@ -360,64 +358,52 @@ void RecordList::clearOldRecords(ur_time_t actualTime) delete *it; list.erase(it++); } - else - { - break; - } + else { + break; + } } } -template -ur_time_t RecordList::getTimeOfLastRecord() -{ - if(!list.empty()) - { - return list.back()->flowLastSeen; - } - else - { - return 0; - } +template +ur_time_t RecordList::getTimeOfLastRecord() { + if (!list.empty()) { + return list.back()->flowLastSeen; + } + else { + return 0; + } } template -uint16_t RecordList::getCurrentTargets() -{ - std::set dstIpSet; - for(const auto & it : list) - { - if(it->isMatched()) - { - dstIpSet.insert(it->dstIp); - } - } - return dstIpSet.size(); +uint16_t RecordList::getCurrentTargets() { + std::set dstIpSet; + for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) + { + if ((*it).isMatched()) { + dstIpSet.insert((*it)->dstIp); + } + } + return dstIpSet.size(); } template -void RecordList::initTotalTargetsSet() -{ - for(const auto & it : list) - { - if(it->isMatched()) - { - // TODO Why is TotalIPSet filled with matched flows only? - hashedDstTotalIPSet.insert(it->dstIp); - } - } -} +void RecordList::initTotalTargetsSet() { + for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) + if ((*it)->isMatched()) { + hashedDstTotalIPSet.insert((*it)->dstIp); + } + } + template -std::vector RecordList::getIpsOfVictims() -{ +std::vector RecordList::getIpsOfVictims() { std::vector tmpIpsOfVictims; - for(const auto& it : list) + for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) { - if(it->isMatched()) - { - ip_to_str(&(it->dstIp), victimIP); + if ((*it)->isMatched()) { + ip_to_str(&((*it)->dstIp), victimIP); tmpIpsOfVictims.push_back(std::string(victimIP)); } diff --git a/brute_force_detector/sender.cpp b/brute_force_detector/sender.cpp index 8d4553fb..7c0f7582 100644 --- a/brute_force_detector/sender.cpp +++ b/brute_force_detector/sender.cpp @@ -45,35 +45,37 @@ #include "sender.h" UR_FIELDS( - time DETECTION_TIME, // Timestamp of the detection of some event - uint8 WARDEN_TYPE, // Type of event (see Warden README for more information) - ipaddr SRC_IP, // Source address of a flow - uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) - uint16 DST_PORT, // Destination transport-layer port - uint32 EVENT_SCALE, // Attack intensity - string NOTE, // Generic string note + time + DETECTION_TIME, // Timestamp of the detection of some event + uint8 + WARDEN_TYPE, // Type of event (see Warden README for more information) + ipaddr + SRC_IP, // Source address of a flow + uint8 + PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint16 + DST_PORT, // Destination transport-layer port + uint32 + EVENT_SCALE, // Attack intensity + string NOTE, // Generic string note ) -Sender::Sender(bool *success) -{ +Sender::Sender(bool *success) { std::string unirecSpecifier = "DETECTION_TIME,WARDEN_TYPE,SRC_IP,PROTOCOL,DST_PORT,EVENT_SCALE,NOTE"; - outTemplate = ur_create_output_template(0, unirecSpecifier.c_str(), nullptr); - if(outTemplate == nullptr) - { + outTemplate = ur_create_output_template(0, unirecSpecifier.c_str(), NULL); + if (outTemplate == NULL) { *success = false; return; } *success = true; } -Sender::~Sender() -{ - if(outTemplate != nullptr) - { - ur_free_template (outTemplate); - } +Sender::~Sender() { + if (outTemplate != NULL) { + ur_free_template(outTemplate); + } } diff --git a/brute_force_detector/sender.h b/brute_force_detector/sender.h index 66522eb9..963c2134 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -64,6 +64,7 @@ extern "C" { #endif // __cplusplus #include + using namespace std; // WARDEN_TYPE @@ -72,45 +73,41 @@ using namespace std; /** * @desc Class for handling output messages */ -class Sender -{ +class Sender { public: explicit Sender(bool *success); + ~Sender(); - template - int firstReport(Host *host, uint16_t dstPort, ur_time_t actualTime, uint16_t detectionThreshold) - { - if(Config::getInstance().getGlobalIgnoreFirstSend()) - { - // Ignore first report + template + int firstReport(Host *host, uint16_t dstPort, ur_time_t actualTime, uint16_t detectionThreshold) { + if (Config::getInstance().getGlobalIgnoreFirstSend()) { + // Ignore first report host->setReportTime(actualTime); return TRAP_E_OK; } - //TODO test if output correct - uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); - uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); + uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); + uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); - string sNote; + string sNote; - return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), false, sNote); + return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), false, sNote); } - template - int continuingReport(Host *host, uint16_t dstPort, ur_time_t actualTime, bool endOfAttack = false) - { + template + int continuingReport(Host *host, uint16_t dstPort, ur_time_t actualTime, bool endOfAttack = false) { uint32_t incomingMatched = host->getPointerToIncomingRecordList()->getMatchedFlowsSinceLastReport(); uint32_t outgoingMatched = host->getPointerToOutgoingRecordList()->getMatchedFlowsSinceLastReport(); string sNote; - host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); - host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToIncomingRecordList()->clearTotalFlowsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); host->getPointerToOutgoingRecordList()->clearTotalFlowsSinceLastReport(); return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), endOfAttack, sNote); @@ -119,9 +116,9 @@ class Sender private: ur_template_t *outTemplate; - template - int send(Host *host, uint16_t dstPort, ur_time_t actualTime, uint32_t intensity, bool endOfAttack = false, const string& stringNote = string()) - { + template + int send(Host *host, uint16_t dstPort, ur_time_t actualTime, uint32_t intensity, bool endOfAttack = false, + const string &stringNote = string()) { vector incIpsVictims = host->getPointerToIncomingRecordList()->getIpsOfVictims(); vector outIpsVictims = host->getPointerToOutgoingRecordList()->getIpsOfVictims(); string note; @@ -134,20 +131,20 @@ class Sender // Incoming note.append("I:"); - for (const auto & incIpsVictim : incIpsVictims) { - note.append(incIpsVictim); + for (unsigned long i = 0; i < incIpsVictims.size(); i++) { + note.append(incIpsVictims.at(i)); note.append(","); } - // Outgoing + //Outgoing note.append("O:"); - for (const auto & outIpsVictim : outIpsVictims) { - note.append(outIpsVictim); + for (unsigned long i = 0; i < outIpsVictims.size(); i++) { + note.append(outIpsVictims.at(i)); note.append(","); } - note.erase(note.length(),1); + note.erase(note.length(), 1); - // get size of note + // get size of note uint16_t noteSize = note.size() + 1; // plus '\0' void *rec = ur_create_record(outTemplate, noteSize); diff --git a/brute_force_detector/telnet_server_profile.cpp b/brute_force_detector/telnet_server_profile.cpp index c78f75d4..bee78182 100644 --- a/brute_force_detector/telnet_server_profile.cpp +++ b/brute_force_detector/telnet_server_profile.cpp @@ -43,11 +43,12 @@ */ #include "telnet_server_profile.h" + using namespace std; + #include -void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) -{ +void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) { // at least 6 packets from server to client // 1. syn+ack // 2. supported configuration @@ -57,14 +58,14 @@ void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) // 4/6. ack password // 5/7. information about successfull/failed login // 6/8. FIN packet - if(packets < 6) // FIXME magic constant + if (packets < TELNET_OUTGOING_MIN_PACKETS) { return; + } static uint16_t profileCounter = 0; profileCounter++; - if(listSize >= TSPArraySize) - { + if (listSize >= TSPArraySize) { byteList.pop_front(); packetList.pop_front(); listSize--; @@ -74,57 +75,47 @@ void TelnetServerProfile::profileWithNewData(uint32_t packets, uint64_t bytes) packetList.push_back(packets); listSize++; - if(!profiled && listSize == TSPArraySize) - { + if (!profiled && listSize == TSPArraySize) { countNewMaxValues(); profiled = true; } - else if(profiled && profileCounter == profileEvery) - { + else if (profiled && profileCounter == profileEvery) { countNewMaxValues(); profileCounter = 0; } } -void TelnetServerProfile::countNewMaxValues() -{ +void TelnetServerProfile::countNewMaxValues() { size_t n = packetList.size() / 2; vector packetVector; vector byteVector; copy(packetList.begin(), packetList.end(), back_inserter(packetVector)); - copy(byteList.begin(), byteList.end(), back_inserter(byteVector)); + copy(byteList.begin(), byteList.end(), back_inserter(byteVector)); // median - nth_element(byteVector.begin(), byteVector.begin() + n, byteVector.end()); + nth_element(byteVector.begin(), byteVector.begin() + n, byteVector.end()); nth_element(packetVector.begin(), packetVector.begin() + n, packetVector.end()); maxPackets = packetVector[n] + 5; - maxBytes = byteVector[n] + 500; - - // char *c = new char[55]; - // ip_to_str(&serverIp,c); - // std::cout<<"Profilovano "<(ip, TSP)); + TSPMap.insert(std::pair(ip, TSP)); return TSP; } -TelnetServerProfile * TelnetServerProfileMap::findProfile(ip_addr_t & hostIp) const -{ - auto it = TSPMap.find(hostIp); - if(it == TSPMap.end()) - { - return nullptr; - } +TelnetServerProfile *TelnetServerProfileMap::findProfile(ip_addr_t &hostIp) const { + std::map::const_iterator it = TSPMap.find(hostIp); + if (it == TSPMap.end()) { + return NULL; + } return it->second; } diff --git a/brute_force_detector/telnet_server_profile.h b/brute_force_detector/telnet_server_profile.h index 9761fdde..145ee74a 100644 --- a/brute_force_detector/telnet_server_profile.h +++ b/brute_force_detector/telnet_server_profile.h @@ -45,7 +45,6 @@ #ifndef TELNET_SERVER_PROFILE_H #define TELNET_SERVER_PROFILE_H -//#include "record.h" #include "brute_force_detector.h" #include //ip_addr_t #include //ur_time_t @@ -58,40 +57,46 @@ const static uint16_t TSPArraySize = 15; const static uint8_t profileEvery = 10; -class TelnetServerProfile -{ -public: +class TelnetServerProfile { +public: TelnetServerProfile(ur_time_t firstSeen, ip_addr_t ip) : timeOfCreation(firstSeen), serverIp(ip), profiled(false), listSize(0), maxBytes(0), maxPackets(0) {} - bool isProfiled() const {return profiled;} + + bool isProfiled() const { return profiled; } + uint32_t getMaxPackets() const { return maxPackets; } + uint64_t getMaxBytes() const { return maxBytes; } + void profileWithNewData(uint32_t packets, uint64_t bytes); - - + + + private: ur_time_t timeOfCreation; ip_addr_t serverIp; bool profiled; - + std::list byteList; std::list packetList; uint16_t listSize; - + uint64_t maxBytes; uint32_t maxPackets; - void countNewMaxValues(); + + void countNewMaxValues(); }; -class TelnetServerProfileMap -{ +class TelnetServerProfileMap { public: TelnetServerProfileMap() {}; - TelnetServerProfile * createProfile(ip_addr_t ip, ur_time_t firstSeen); - TelnetServerProfile * findProfile(ip_addr_t & hostIp) const; - + + TelnetServerProfile *createProfile(ip_addr_t ip, ur_time_t firstSeen); + + TelnetServerProfile *findProfile(ip_addr_t &hostIp) const; + private: - std::map TSPMap; + std::map TSPMap; }; -#endif +#endif diff --git a/brute_force_detector/whitelist.cpp b/brute_force_detector/whitelist.cpp index f797b4b4..539ed59b 100644 --- a/brute_force_detector/whitelist.cpp +++ b/brute_force_detector/whitelist.cpp @@ -52,66 +52,59 @@ using namespace std; // ********************* WHITELISTEDPORTS ********************/ // ************************************************************/ -WhitelistedPorts::WhitelistedPorts() -{ +WhitelistedPorts::WhitelistedPorts() { } -bool WhitelistedPorts::findPort(uint16_t port) -{ - return inRange(portRangeList, port); +bool WhitelistedPorts::findPort(uint16_t port) { + return inRange(portRangeList, port); } -void WhitelistedPorts::addPortRange(uint16_t from, uint16_t to) -{ - portRangeList.insert(Range(from, to)); +void WhitelistedPorts::addPortRange(uint16_t from, uint16_t to) { + portRangeList.insert(Range(from, to)); } -void WhitelistedPorts::addSinglePort(uint16_t port) -{ - addPortRange(port, port); +void WhitelistedPorts::addSinglePort(uint16_t port) { + addPortRange(port, port); } // ************************************************************/ // ************************ IPTRIE ***************************/ // ************************************************************/ -IPTrie::IPTrie() -{ - left = NULL; - right = NULL; - allPorts = false; - set = false; - whitelistedPorts = NULL; +IPTrie::IPTrie() { + left = NULL; + right = NULL; + allPorts = false; + set = false; + whitelistedPorts = NULL; } -IPTrie::~IPTrie() -{ - if (left != NULL) { - delete left; - } +IPTrie::~IPTrie() { + if (left != NULL) { + delete left; + } - if (right != NULL) { - delete right; - } + if (right != NULL) { + delete right; + } - if (whitelistedPorts != NULL) { - delete whitelistedPorts; - } + if (whitelistedPorts != NULL) { + delete whitelistedPorts; + } } // ************************************************************/ // ******************** WHITELISTPARSER **********************/ // ************************************************************/ -void WhitelistParser::init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IPTrie *ipv6Dst) -{ - this->ipv4Src = ipv4Src; - this->ipv4Dst = ipv4Dst; - this->ipv6Src = ipv6Src; - this->ipv6Dst = ipv6Dst; +void WhitelistParser::init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IPTrie *ipv6Dst) { + this->ipv4Src = ipv4Src; + this->ipv4Dst = ipv4Dst; + this->ipv6Src = ipv6Src; + this->ipv6Dst = ipv6Dst; - rulesCounter = 0; + rulesCounter = 0; } @@ -120,410 +113,420 @@ void WhitelistParser::init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IP // ************************************************************/ -Whitelist::Whitelist() -{ - locked = false; - wlFileName = NULL; +Whitelist::Whitelist() { + locked = false; + wlFileName = NULL; - ipv4Src = new IPTrie(); - ipv4Dst = new IPTrie(); - ipv6Src = new IPTrie(); - ipv6Dst = new IPTrie(); + ipv4Src = new IPTrie(); + ipv4Dst = new IPTrie(); + ipv6Src = new IPTrie(); + ipv6Dst = new IPTrie(); - parser.init(ipv4Src, ipv4Dst, ipv6Src, ipv6Dst); + parser.init(ipv4Src, ipv4Dst, ipv6Src, ipv6Dst); } -Whitelist::~Whitelist() -{ - delete ipv4Src; - delete ipv4Dst; - delete ipv6Src; - delete ipv6Dst; +Whitelist::~Whitelist() { + delete ipv4Src; + delete ipv4Dst; + delete ipv6Src; + delete ipv6Dst; } -bool Whitelist::init(char *fileName, bool verbose) -{ - wlFileName = fileName; - ifstream ifs; - ifs.open(fileName, ifstream::in); - if (!ifs.is_open()) { - return false; - } +bool Whitelist::init(char *fileName, bool verbose) { + wlFileName = fileName; + ifstream ifs; + ifs.open(fileName, ifstream::in); + if (!ifs.is_open()) { + return false; + } - parser.parse(&ifs, verbose); - ifs.close(); + parser.parse(&ifs, verbose); + ifs.close(); - return true; + return true; } -bool Whitelist::isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, uint16_t srcPort, uint16_t dstPort) -{ - locked = true; - bool found = false; - - if (ip_is4(srcIp)) { - // ipv4 - // check src addr first - found = trieSearch(ipv4Src, (uint8_t*) srcIp + 8, 4, srcPort); - if (found) { - locked = false; - return true; - } - - found = trieSearch(ipv4Dst, (uint8_t*) dstIp + 8, 4, dstPort); - if (found) { - locked = false; - return true; - } - } else { // ipv6 - // check src addr first - found = trieSearch(ipv6Src, (uint8_t*) srcIp, 6, srcPort); - if (found) { - locked = false; - return true; - } - - // check dst addr - found = trieSearch(ipv6Dst, (uint8_t*) dstIp, 6, dstPort); - if (found) { - locked = false; - return true; - } - } - - locked = false; - return false; +bool Whitelist::isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, uint16_t srcPort, uint16_t dstPort) { + locked = true; + bool found = false; + + if (ip_is4(srcIp)) { + // ipv4 + // check src addr first + found = trieSearch(ipv4Src, (uint8_t *) srcIp + 8, 4, srcPort); + if (found) { + locked = false; + return true; + } + + found = trieSearch(ipv4Dst, (uint8_t *) dstIp + 8, 4, dstPort); + if (found) { + locked = false; + return true; + } + } + else { // ipv6 + // check src addr first + found = trieSearch(ipv6Src, (uint8_t *) srcIp, 6, srcPort); + if (found) { + locked = false; + return true; + } + + // check dst addr + found = trieSearch(ipv6Dst, (uint8_t *) dstIp, 6, dstPort); + if (found) { + locked = false; + return true; + } + } + + locked = false; + return false; } -bool Whitelist::trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t port) -{ - IPTrie *currentNode = ipTrie; - int iRange = (ipType == 4) ? 32 : 128; - - for (int i = 0; i < iRange; i++) { - for (int u = 7; u >= 0; u--) { - // change last known node - if (currentNode->set) { - // vsechny porty - if (currentNode->allPorts) { - return true; +bool Whitelist::trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t port) { + IPTrie *currentNode = ipTrie; + int iRange = (ipType == 4) ? 32 : 128; + + for (int i = 0; i < iRange; i++) { + for (int u = 7; u >= 0; u--) { + // change last known node + if (currentNode->set) { + // vsechny porty + if (currentNode->allPorts) { + return true; + } + if (currentNode->whitelistedPorts != NULL) { + if ((currentNode->whitelistedPorts->findPort(port)) == true) { + return true; + } + } } - if (currentNode->whitelistedPorts != NULL) { - if ((currentNode->whitelistedPorts->findPort(port)) == true) { - return true; - } - } - } - // search right - if (((ip[i] >> u) & 1) > 0) { - currentNode = currentNode->right; - } else { // search left - currentNode = currentNode->left; - } + // search right + if (((ip[i] >> u) & 1) > 0) { + currentNode = currentNode->right; + } + else { // search left + currentNode = currentNode->left; + } - if (currentNode == NULL) { - return false; - } - } - } + if (currentNode == NULL) { + return false; + } + } + } - return false; + return false; } -void Whitelist::reloadWhitelist() -{ - if (wlFileName != NULL) { - ifstream ifs; - ifs.open(wlFileName, ifstream::in); - if (!ifs.is_open()) { - cerr << "Error Whitelist: Cannot open whitelist file!\n"; - return; - } - - delete ipv4Src; - delete ipv4Dst; - delete ipv6Src; - delete ipv6Dst; - - ipv4Src = new IPTrie(); - ipv4Dst = new IPTrie(); - ipv6Src = new IPTrie(); - ipv6Dst = new IPTrie(); - - parser.init(ipv4Src, ipv4Dst, ipv6Src, ipv6Dst); - parser.parse(&ifs, false); - - ifs.close(); - - cout << "Whitelist: Whitelist reloaded successfully.\n"; - } else { - cerr << "Error Whitelist: Whitelist path is not set!\n"; - } +void Whitelist::reloadWhitelist() { + if (wlFileName != NULL) { + ifstream ifs; + ifs.open(wlFileName, ifstream::in); + if (!ifs.is_open()) { + cerr << "Error Whitelist: Cannot open whitelist file!\n"; + return; + } + + delete ipv4Src; + delete ipv4Dst; + delete ipv6Src; + delete ipv6Dst; + + ipv4Src = new IPTrie(); + ipv4Dst = new IPTrie(); + ipv6Src = new IPTrie(); + ipv6Dst = new IPTrie(); + + parser.init(ipv4Src, ipv4Dst, ipv6Src, ipv6Dst); + parser.parse(&ifs, false); + + ifs.close(); + + cout << "Whitelist: Whitelist reloaded successfully.\n"; + } + else { + cerr << "Error Whitelist: Whitelist path is not set!\n"; + } } // ************************************************************/ // ********************* WHITELIST PARSER *********************/ // ************************************************************/ -void WhitelistParser::parse(ifstream *ifs, bool verboseMode) -{ - static bool verbose = verboseMode; - this->verbose = verbose; - string line; - uint8_t direction; - - if (verbose) { - cout << "Parsing whitelist file...\n"; - } - - while (std::getline((*ifs), line).good()) { - if (line.empty()) { - continue; - } - - if (line[0] == WHITELIST_PARSER_COMMENT_DELIM) { // skip comment line - continue; - } - - // substring before comment delim if exists - size_t pos = line.find_first_of(WHITELIST_PARSER_COMMENT_DELIM); - if (pos != string::npos) { - line = line.substr(0, pos); - } - - // now check for src or dst direction - if (line.size() < 4) { - if(verbose) { - cout << "Invalid line: " << line << endl; - } - - continue; - } - - string sDirection = line.substr(0, 3); - - if (sDirection == WHITELIST_PARSER_IP_DIRECTION_KEYWORD_SRC) { - direction = WHITELIST_PARSER_IP_DIRECTION_SRC; - line = line.substr(4); - } else if (sDirection == WHITELIST_PARSER_IP_DIRECTION_KEYWORD_DST) { - direction = WHITELIST_PARSER_IP_DIRECTION_DST; - line = line.substr(4); - } else { - direction = WHITELIST_PARSER_IP_DIRECTION_ALL; - } - - // now ip check parse - pos = line.find_first_of(WHITELIST_PARSER_PREFIX_DELIM); - if (pos != string::npos) { - string ipstring = line.substr(0, pos); - ip_addr_t ip; - if (ip_from_str(ipstring.c_str(), &ip)) { - // ip ok, now parse prefix and ports - string prefixAndPorts = line.substr(pos + 1); - if (!prefixAndPorts.empty()) { - if (verbose) { - cout << "IP: " << ipstring << endl; - } - - pos = prefixAndPorts.find_first_of(WHITELIST_PARSER_PORTS_DELIM); - string ports = string(); - if (pos != string::npos) { - string prefixStr = prefixAndPorts.substr(0, pos); - int prefix = atoi(prefixStr.c_str()); - // get ports now - ports = prefixAndPorts.substr(pos + 1); - if (ports.empty()) { - if (verbose) { - cout << "Invalid line: " << line << endl; - } - } else { - if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { - if (verbose) { - cout << "Invalid line: " << line << endl; +void WhitelistParser::parse(ifstream *ifs, bool verboseMode) { + static bool verbose = verboseMode; + this->verbose = verbose; + string line; + uint8_t direction; + + if (verbose) { + cout << "Parsing whitelist file...\n"; + } + + while (std::getline((*ifs), line).good()) { + if (line.empty()) { + continue; + } + + if (line[0] == WHITELIST_PARSER_COMMENT_DELIM) { // skip comment line + continue; + } + + // substring before comment delim if exists + size_t pos = line.find_first_of(WHITELIST_PARSER_COMMENT_DELIM); + if (pos != string::npos) { + line = line.substr(0, pos); + } + + // now check for src or dst direction + if (line.size() < 4) { + if (verbose) { + cout << "Invalid line: " << line << endl; + } + + continue; + } + + string sDirection = line.substr(0, 3); + + if (sDirection == WHITELIST_PARSER_IP_DIRECTION_KEYWORD_SRC) { + direction = WHITELIST_PARSER_IP_DIRECTION_SRC; + line = line.substr(4); + } + else if (sDirection == WHITELIST_PARSER_IP_DIRECTION_KEYWORD_DST) { + direction = WHITELIST_PARSER_IP_DIRECTION_DST; + line = line.substr(4); + } + else { + direction = WHITELIST_PARSER_IP_DIRECTION_ALL; + } + + // now ip check parse + pos = line.find_first_of(WHITELIST_PARSER_PREFIX_DELIM); + if (pos != string::npos) { + string ipstring = line.substr(0, pos); + ip_addr_t ip; + if (ip_from_str(ipstring.c_str(), &ip)) { + // ip ok, now parse prefix and ports + string prefixAndPorts = line.substr(pos + 1); + if (!prefixAndPorts.empty()) { + if (verbose) { + cout << "IP: " << ipstring << endl; + } + + pos = prefixAndPorts.find_first_of(WHITELIST_PARSER_PORTS_DELIM); + string ports = string(); + if (pos != string::npos) { + string prefixStr = prefixAndPorts.substr(0, pos); + int prefix = atoi(prefixStr.c_str()); + // get ports now + ports = prefixAndPorts.substr(pos + 1); + if (ports.empty()) { + if (verbose) { + cout << "Invalid line: " << line << endl; + } + } + else { + if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { + if (verbose) { + cout << "Invalid line: " << line << endl; + } + } } - } - } - } else { // ??? mtva vezev? - int prefix = atoi(prefixAndPorts.c_str()); - if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { - if (verbose) { - cout << "Invalid line: " << line << endl; - } - } - } - } else if (verbose) { - cout << "Invalid line: " << line << endl; + } + else { // ??? mtva vezev? + int prefix = atoi(prefixAndPorts.c_str()); + if (!checkPrefixAndPortsAndAdd(ip, direction, prefix, ports)) { + if (verbose) { + cout << "Invalid line: " << line << endl; + } + } + } + } + else if (verbose) { + cout << "Invalid line: " << line << endl; + } + } + else if (verbose) { // invalid ip + cout << "Invalid line: " << line << endl; } - } else if (verbose) { // invalid ip + } + else if (verbose) { cout << "Invalid line: " << line << endl; - } - } else if (verbose) { - cout << "Invalid line: " << line << endl; - } - } - - if (verbose) { - cout << "Total rules added: " << rulesCounter << endl; - cout << "Parsing whitelist file done" << endl; - } + } + } + + if (verbose) { + cout << "Total rules added: " << rulesCounter << endl; + cout << "Parsing whitelist file done" << endl; + } } -bool WhitelistParser::checkPrefixAndPortsAndAdd(ip_addr_t &addr, uint8_t direction, uint8_t prefix, string &ports) -{ - bool ipv4 = ip_is4(&addr); - if ((ipv4 && prefix > 32) || (!ipv4 && prefix > 128)) { - return false; - } +bool WhitelistParser::checkPrefixAndPortsAndAdd(ip_addr_t &addr, uint8_t direction, uint8_t prefix, string &ports) { + bool ipv4 = ip_is4(&addr); + if ((ipv4 && prefix > 32) || (!ipv4 && prefix > 128)) { + return false; + } - prepareAddIPAndPorts(addr, direction, prefix, ports); - return true; + prepareAddIPAndPorts(addr, direction, prefix, ports); + return true; } -void WhitelistParser::prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, uint8_t prefix, string &ports) -{ - if (ip_is4(&addr)) { - if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { - addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Src, ports); - addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Dst, ports); - } else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { - addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Src, ports); - } else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST - addIPAndSelectedPorts((uint8_t*) &addr + 8, prefix, ipv4Dst, ports); - } - } else { // ipv6 - if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { - addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Src, ports); - addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Dst, ports); - } else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { - addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Src, ports); - } else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST - addIPAndSelectedPorts((uint8_t*) &addr, prefix, ipv6Dst, ports); - } - } +void WhitelistParser::prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, uint8_t prefix, string &ports) { + if (ip_is4(&addr)) { + if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { + addIPAndSelectedPorts((uint8_t *) &addr + 8, prefix, ipv4Src, ports); + addIPAndSelectedPorts((uint8_t *) &addr + 8, prefix, ipv4Dst, ports); + } + else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { + addIPAndSelectedPorts((uint8_t *) &addr + 8, prefix, ipv4Src, ports); + } + else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST + addIPAndSelectedPorts((uint8_t *) &addr + 8, prefix, ipv4Dst, ports); + } + } + else { // ipv6 + if (direction == WHITELIST_PARSER_IP_DIRECTION_ALL) { + addIPAndSelectedPorts((uint8_t *) &addr, prefix, ipv6Src, ports); + addIPAndSelectedPorts((uint8_t *) &addr, prefix, ipv6Dst, ports); + } + else if (direction == WHITELIST_PARSER_IP_DIRECTION_SRC) { + addIPAndSelectedPorts((uint8_t *) &addr, prefix, ipv6Src, ports); + } + else { // direction == WHITELIST_PARSER_IP_DIRECTION_DST + addIPAndSelectedPorts((uint8_t *) &addr, prefix, ipv6Dst, ports); + } + } } -void WhitelistParser::addPorts(IPTrie *currentNode, string ports) -{ - WhitelistedPorts *whitelistedPorts = currentNode->whitelistedPorts; - - if(ports.empty()) { - return; - } - - size_t pos; - pos = ports.find_first_of(WHITELIST_PARSER_NEXT_PORT_DELIM); - if (pos != string::npos) { - string portString = ports.substr(0, pos); - ports = ports.substr(pos + 1); - - pos = portString.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); - if (pos != string::npos) { // range - string firstStringPort = portString.substr(0, pos); - string secondStringPort = portString.substr(pos + 1); - if (secondStringPort.empty()) { - if(verbose) { - cout << "Invalid ports range: " << portString << endl; +void WhitelistParser::addPorts(IPTrie *currentNode, string ports) { + WhitelistedPorts *whitelistedPorts = currentNode->whitelistedPorts; + + if (ports.empty()) { + return; + } + + size_t pos; + pos = ports.find_first_of(WHITELIST_PARSER_NEXT_PORT_DELIM); + if (pos != string::npos) { + string portString = ports.substr(0, pos); + ports = ports.substr(pos + 1); + + pos = portString.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); + if (pos != string::npos) { // range + string firstStringPort = portString.substr(0, pos); + string secondStringPort = portString.substr(pos + 1); + if (secondStringPort.empty()) { + if (verbose) { + cout << "Invalid ports range: " << portString << endl; + } + + return; } - return; - } - - uint16_t port = atoi(firstStringPort.c_str()); - uint16_t port2 = atoi(secondStringPort.c_str()); - - whitelistedPorts->addPortRange(port, port2); - rulesCounter++; - if (verbose) { - cout << "Adding port range " << portString << endl; - } - } else { // single port - uint16_t port = atoi(portString.c_str()); - whitelistedPorts->addSinglePort(port); - if(verbose) { - cout << "Adding single port " << port << endl; - } - } - - addPorts(currentNode, ports); - } else { - pos = ports.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); - if (pos != string::npos) { // range - string firstStringPort = ports.substr(0, pos); - string secondStringPort = ports.substr(pos + 1); - if (secondStringPort.empty()) { + uint16_t port = atoi(firstStringPort.c_str()); + uint16_t port2 = atoi(secondStringPort.c_str()); + + whitelistedPorts->addPortRange(port, port2); + rulesCounter++; if (verbose) { - cout << "Invalid ports range: " << ports << endl; + cout << "Adding port range " << portString << endl; + } + } + else { // single port + uint16_t port = atoi(portString.c_str()); + whitelistedPorts->addSinglePort(port); + if (verbose) { + cout << "Adding single port " << port << endl; + } + } + + addPorts(currentNode, ports); + } + else { + pos = ports.find_first_of(WHITELIST_PARSER_PORT_RANGE_DELIM); + if (pos != string::npos) { // range + string firstStringPort = ports.substr(0, pos); + string secondStringPort = ports.substr(pos + 1); + if (secondStringPort.empty()) { + if (verbose) { + cout << "Invalid ports range: " << ports << endl; + } + + addPorts(currentNode, ports); + return; } - addPorts(currentNode, ports); - return; - } - - uint16_t port = atoi(firstStringPort.c_str()); - uint16_t port2 = atoi(secondStringPort.c_str()); - - whitelistedPorts->addPortRange(port, port2); - rulesCounter++; - if (verbose) { - cout << "Adding port range " << ports << endl; - } - } else { // single port - uint16_t port = atoi(ports.c_str()); - whitelistedPorts->addSinglePort(port); - if (verbose) { - cout << "Adding single port " << port << endl; - } - } - } + uint16_t port = atoi(firstStringPort.c_str()); + uint16_t port2 = atoi(secondStringPort.c_str()); + + whitelistedPorts->addPortRange(port, port2); + rulesCounter++; + if (verbose) { + cout << "Adding port range " << ports << endl; + } + } + else { // single port + uint16_t port = atoi(ports.c_str()); + whitelistedPorts->addSinglePort(port); + if (verbose) { + cout << "Adding single port " << port << endl; + } + } + } } -void WhitelistParser::addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie *trie, string ports) -{ - IPTrie *currentNode = trie; - for (int i = 0; i < prefix; i++) { +void WhitelistParser::addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie *trie, string ports) { + IPTrie *currentNode = trie; + for (int i = 0; i < prefix; i++) { // bitset go right - if (((ip[i / 8] >> (7 - i % 8)) & 1) > 0) { - if (currentNode->right == NULL) { - currentNode->right = new IPTrie(); - } - // next - currentNode = currentNode->right; - } else { // go left - if (currentNode->left == NULL) { - currentNode->left = new IPTrie(); - } - // next - currentNode = currentNode->left; - } - - if ((i + 1) == prefix) { // last pos - if(currentNode->whitelistedPorts == NULL) { + if (((ip[i / 8] >> (7 - i % 8)) & 1) > 0) { + if (currentNode->right == NULL) { + currentNode->right = new IPTrie(); + } + // next + currentNode = currentNode->right; + } + else { // go left + if (currentNode->left == NULL) { + currentNode->left = new IPTrie(); + } + // next + currentNode = currentNode->left; + } + + if ((i + 1) == prefix) { // last pos + if (currentNode->whitelistedPorts == NULL) { + currentNode->whitelistedPorts = new WhitelistedPorts; + } + + if (ports.empty()) { + currentNode->allPorts = true; + } + else { + addPorts(currentNode, ports); + } + + currentNode->set = true; + rulesCounter++; + } + } + // prefix 0 + if (prefix == 0) { + if (currentNode->whitelistedPorts == NULL) { currentNode->whitelistedPorts = new WhitelistedPorts; - } + } - if (ports.empty()) { + if (ports.empty()) { currentNode->allPorts = true; - } else { + } + else { addPorts(currentNode, ports); - } - - currentNode->set = true; - rulesCounter++; - } - } - // prefix 0 - if (prefix == 0) { - if (currentNode->whitelistedPorts == NULL) { - currentNode->whitelistedPorts = new WhitelistedPorts; - } - - if (ports.empty()) { - currentNode->allPorts = true; - } else { - addPorts(currentNode, ports); - } - - currentNode->set = true; - rulesCounter++; - } + } + + currentNode->set = true; + rulesCounter++; + } } diff --git a/brute_force_detector/whitelist.h b/brute_force_detector/whitelist.h index f8483e21..ff201cd4 100644 --- a/brute_force_detector/whitelist.h +++ b/brute_force_detector/whitelist.h @@ -48,11 +48,11 @@ #include #include -#include +#include #include #include #include -#include +#include //WHITELIST PARSER VARIABLES @@ -63,10 +63,10 @@ const static uint8_t WHITELIST_PARSER_IP_DIRECTION_ALL = 0; const static uint8_t WHITELIST_PARSER_IP_DIRECTION_SRC = 1; const static uint8_t WHITELIST_PARSER_IP_DIRECTION_DST = 2; -const static uint8_t WHITELIST_PARSER_COMMENT_DELIM = '#'; -const static uint8_t WHITELIST_PARSER_PREFIX_DELIM = '/'; -const static uint8_t WHITELIST_PARSER_PORTS_DELIM = '/'; -const static uint8_t WHITELIST_PARSER_NEXT_PORT_DELIM = ','; +const static uint8_t WHITELIST_PARSER_COMMENT_DELIM = '#'; +const static uint8_t WHITELIST_PARSER_PREFIX_DELIM = '/'; +const static uint8_t WHITELIST_PARSER_PORTS_DELIM = '/'; +const static uint8_t WHITELIST_PARSER_NEXT_PORT_DELIM = ','; const static uint8_t WHITELIST_PARSER_PORT_RANGE_DELIM = '-'; @@ -77,42 +77,43 @@ const static uint8_t WHITELIST_PARSER_PORT_RANGE_DELIM = '-'; /** * @desc Class storage of white listed ports. Single port or portRange can be added */ -class WhitelistedPorts -{ +class WhitelistedPorts { public: - WhitelistedPorts(); - /** - * @desc Add port range to whitelisted ports - * @param from Port from (start of range) - * @param to Port to (end of range) - */ - void addPortRange(uint16_t from, uint16_t to); - /** - * @desc Add single port to whitelisted ports - * @param port Port to add - */ - void addSinglePort(uint16_t port); - /** - * @desc Find port if is whitelisted - * @param port Port to find - */ - bool findPort(uint16_t port); + WhitelistedPorts(); + + /** + * @desc Add port range to whitelisted ports + * @param from Port from (start of range) + * @param to Port to (end of range) + */ + void addPortRange(uint16_t from, uint16_t to); + + /** + * @desc Add single port to whitelisted ports + * @param port Port to add + */ + void addSinglePort(uint16_t port); + + /** + * @desc Find port if is whitelisted + * @param port Port to find + */ + bool findPort(uint16_t port); private: - typedef std::pair Range; - struct RangeCompare - { - bool operator()(const Range& r1, const Range& r2) const - { - return r1.second < r2.first; - } - }; - std::set portRangeList; - - bool inRange(const std::set& ranges, uint16_t port) - { - return ranges.find(Range(port, port)) != ranges.end(); - } + typedef std::pair Range; + + struct RangeCompare { + bool operator()(const Range &r1, const Range &r2) const { + return r1.second < r2.first; + } + }; + + std::set portRangeList; + + bool inRange(const std::set &ranges, uint16_t port) { + return ranges.find(Range(port, port)) != ranges.end(); + } }; // ************************************************************/ @@ -121,16 +122,17 @@ class WhitelistedPorts class IPTrie { public: - IPTrie(); - ~IPTrie(); + IPTrie(); - IPTrie *left; - IPTrie *right; + ~IPTrie(); - bool allPorts; - bool set; + IPTrie *left; + IPTrie *right; - WhitelistedPorts *whitelistedPorts; + bool allPorts; + bool set; + + WhitelistedPorts *whitelistedPorts; }; // ************************************************************/ @@ -141,58 +143,57 @@ class IPTrie { */ class WhitelistParser { public: - WhitelistParser() - { - rulesCounter = 0; - verbose = false; - } - - /** - * @desc Init parser with two IP tries, first for IPv4, second for IPv6 - */ - void init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IPTrie *ipv6Dst); - /** - * @desc Parse input filestream and add rules into IP Tries, detection mode must be set - */ - void parse(std::ifstream *ifs, bool verboseMode); - - /** - * \brief Only for unit testing! - * - * Only for unit testing! - */ - bool addSelectedPortRule(ip_addr_t ip, uint8_t direction, uint8_t prefix, std::string &ports) - { - return checkPrefixAndPortsAndAdd(ip, direction, prefix, ports); - } + WhitelistParser() { + rulesCounter = 0; + verbose = false; + } + + /** + * @desc Init parser with two IP tries, first for IPv4, second for IPv6 + */ + void init(IPTrie *ipv4Src, IPTrie *ipv4Dst, IPTrie *ipv6Src, IPTrie *ipv6Dst); + + /** + * @desc Parse input filestream and add rules into IP Tries, detection mode must be set + */ + void parse(std::ifstream *ifs, bool verboseMode); + + /** + * \brief Only for unit testing! + * + * Only for unit testing! + */ + bool addSelectedPortRule(ip_addr_t ip, uint8_t direction, uint8_t prefix, std::string &ports) { + return checkPrefixAndPortsAndAdd(ip, direction, prefix, ports); + } private: - IPTrie *ipv4Src; - IPTrie *ipv4Dst; - IPTrie *ipv6Src; - IPTrie *ipv6Dst; - bool verbose; - uint32_t rulesCounter; - - /** - * @desc Add ip and ports into whitelist - */ - void prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, uint8_t prefix, std::string &ports); - - /** - * @desc Add ip and selected ports into whitelist - */ - void addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie *trie, std::string ports); - - /** - * @desc Add ports into IP trie - */ - void addPorts(IPTrie *currentNode, std::string ports); - - /** - * @desc Check ip prefix, then add ip and ports into whitelist - */ - bool checkPrefixAndPortsAndAdd(ip_addr_t &addr, uint8_t direction, uint8_t prefix, std::string &ports); + IPTrie *ipv4Src; + IPTrie *ipv4Dst; + IPTrie *ipv6Src; + IPTrie *ipv6Dst; + bool verbose; + uint32_t rulesCounter; + + /** + * @desc Add ip and ports into whitelist + */ + void prepareAddIPAndPorts(ip_addr_t &addr, uint8_t direction, uint8_t prefix, std::string &ports); + + /** + * @desc Add ip and selected ports into whitelist + */ + void addIPAndSelectedPorts(uint8_t *ip, uint8_t prefix, IPTrie *trie, std::string ports); + + /** + * @desc Add ports into IP trie + */ + void addPorts(IPTrie *currentNode, std::string ports); + + /** + * @desc Check ip prefix, then add ip and ports into whitelist + */ + bool checkPrefixAndPortsAndAdd(ip_addr_t &addr, uint8_t direction, uint8_t prefix, std::string &ports); }; // ************************************************************/ @@ -204,63 +205,63 @@ class WhitelistParser { */ class Whitelist { public: - Whitelist(); - ~Whitelist(); - - /** - * @desc init whitelist - * @param fileName name of whitelist file - * @param detectionMode detection mode - */ - bool init(char *fileName, bool verbose); - - /** - * @desc check given record and host source ip if is whitelisted - * @param Record record - * @param srcip source ip address - */ - bool isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, uint16_t srcPort, uint16_t dstPort); - - /** - * @desc get status for configuration reload - */ - sig_atomic_t isLockedForConfigurationReload() - { - return locked; - } - - /** - * @desc reaload whitelist, all previous configuration will be erased - */ - void reloadWhitelist(); - - /** - * \brief Only for unit testing! - * - * Only for unit testing! - */ - WhitelistParser *getPointerToParser() - { - return &parser; - } + Whitelist(); + + ~Whitelist(); + + /** + * @desc init whitelist + * @param fileName name of whitelist file + * @param detectionMode detection mode + */ + bool init(char *fileName, bool verbose); + + /** + * @desc check given record and host source ip if is whitelisted + * @param Record record + * @param srcip source ip address + */ + bool isWhitelisted(const ip_addr_t *srcIp, const ip_addr_t *dstIp, uint16_t srcPort, uint16_t dstPort); + + /** + * @desc get status for configuration reload + */ + sig_atomic_t isLockedForConfigurationReload() { + return locked; + } + + /** + * @desc reaload whitelist, all previous configuration will be erased + */ + void reloadWhitelist(); + + /** + * \brief Only for unit testing! + * + * Only for unit testing! + */ + WhitelistParser *getPointerToParser() { + return &parser; + } + private: - /** - * @desc Find given ip address and port inside IP trie structure - * @param ipTrie IP trie - * @param ip IP address as array - * @param ipType Type of IP address 4 or 6 - * @param port Searched port - * @return true if port or ip is filtered, false otherwise - */ - bool trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t port); - - WhitelistParser parser; - IPTrie *ipv4Src; - IPTrie *ipv4Dst; - IPTrie *ipv6Src; - IPTrie *ipv6Dst; - sig_atomic_t locked; - char *wlFileName; + /** + * @desc Find given ip address and port inside IP trie structure + * @param ipTrie IP trie + * @param ip IP address as array + * @param ipType Type of IP address 4 or 6 + * @param port Searched port + * @return true if port or ip is filtered, false otherwise + */ + bool trieSearch(IPTrie *ipTrie, uint8_t *ip, uint8_t ipType, uint16_t port); + + WhitelistParser parser; + IPTrie *ipv4Src; + IPTrie *ipv4Dst; + IPTrie *ipv6Src; + IPTrie *ipv6Dst; + sig_atomic_t locked; + char *wlFileName; }; #endif // WHITELIST_H diff --git a/brute_force_detector/whitelist_unit_test.cpp b/brute_force_detector/whitelist_unit_test.cpp index dd85324b..adb6f932 100644 --- a/brute_force_detector/whitelist_unit_test.cpp +++ b/brute_force_detector/whitelist_unit_test.cpp @@ -48,38 +48,37 @@ using namespace std; //init and delete WL for new test instance -#define WL() { \ - if(wl!=nullptr) \ - { \ - delete wl; \ - wl = nullptr; \ - } \ - if(wl == nullptr) \ - { \ - wl = new Whitelist(); \ - } \ - parser = wl->getPointerToParser(); \ +#define WL() { \ + if(wl!=NULL) \ + { \ + delete wl; \ + wl = NULL; \ + } \ + if(wl == NULL) \ + { \ + wl = new Whitelist(); \ + } \ + parser = wl->getPointerToParser(); \ } //parser->setVerbose(); //print test number #define TEST(x) { WL(); } // cout << "Test " << x << ":" << endl; } -uint16_t getRandomPort(){return rand() % 65536;} +uint16_t getRandomPort() { return rand() % 65536; } int failCounter = 0; -void subTestRes(int testNum, const string& state) -{ +void subTestRes(int testNum, const string &state) { //cout <<"Subtest "<< testNum <<": "<< state << endl; - if (state == "fail") - failCounter++; + if (state == "fail") { + failCounter++; + } } -int main() -{ - Whitelist *wl = nullptr; +int main() { + Whitelist *wl = NULL; WhitelistParser *parser; srand(0); // TODO constant value as random seed @@ -106,38 +105,46 @@ int main() ip_from_str("255.255.255.255", &ip5); - /******************************************* - ***************** TEST 1 ****************** - ****** TEST FOR ALL PORTS, ALL DIR ******** - *******************************************/ + /******************************************* + ***************** TEST 1 ****************** + ****** TEST FOR ALL PORTS, ALL DIR ******** + *******************************************/ TEST(1); string ports = string(); //empty string behaves like all port rule parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_ALL, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&ip1, &zeroIp, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&ip1, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip2, &zeroIp, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&ip2, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should be whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), getRandomPort())) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), getRandomPort())) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } /******************************************* ***************** TEST 2 ****************** @@ -146,22 +153,28 @@ int main() TEST(2); parser->addSelectedPortRule(ip2, WHITELIST_PARSER_IP_DIRECTION_SRC, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&ip2, &zeroIp, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&ip2, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip1, &zeroIp, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&ip1, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip3, &zeroIp, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&ip3, &zeroIp, getRandomPort(), getRandomPort())) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 3 ****************** @@ -170,22 +183,28 @@ int main() TEST(3); parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_DST, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), getRandomPort())) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), getRandomPort())) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip3, getRandomPort(), getRandomPort())) + if (!wl->isWhitelisted(&zeroIp, &ip3, getRandomPort(), getRandomPort())) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 4 ****************** @@ -196,34 +215,44 @@ int main() parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_ALL, 32, ports); //ip port should be whitelisted - if(wl->isWhitelisted(&ip1, &zeroIp, 80, zeroPort)) + if (wl->isWhitelisted(&ip1, &zeroIp, 80, zeroPort)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip2, &zeroIp, 80, 80)) + if (!wl->isWhitelisted(&ip2, &zeroIp, 80, 80)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip port should be whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, zeroPort, 80)) + if (wl->isWhitelisted(&zeroIp, &ip1, zeroPort, 80)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, 80, 80)) + if (!wl->isWhitelisted(&zeroIp, &ip2, 80, 80)) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip1, 79, 79)) + if (!wl->isWhitelisted(&zeroIp, &ip1, 79, 79)) { subTestRes(5, "passed"); - else + } + else { subTestRes(5, "fail"); + } /******************************************* ***************** TEST 5 ****************** @@ -233,22 +262,28 @@ int main() ports = "80"; parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_SRC, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&ip1, &zeroIp, 80, getRandomPort())) + if (wl->isWhitelisted(&ip1, &zeroIp, 80, getRandomPort())) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip1, &zeroIp, 79, 80)) + if (!wl->isWhitelisted(&ip1, &zeroIp, 79, 80)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&ip3, &zeroIp, 80, 80)) + if (!wl->isWhitelisted(&ip3, &zeroIp, 80, 80)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 6 ****************** @@ -258,22 +293,28 @@ int main() ports = "80"; parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_DST, 32, ports); //ip should be whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 80)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 80)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 80)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 80)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 79)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 79)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 7 ****************** @@ -283,40 +324,52 @@ int main() ports = "80-100"; parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_DST, 32, ports); //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 95)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 95)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 80)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 80)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 100)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 100)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } //outside 80-100 range - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 79)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 79)) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } //outside 80-100 range - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 101)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 101)) { subTestRes(5, "passed"); - else + } + else { subTestRes(5, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 80)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 80)) { subTestRes(6, "passed"); - else + } + else { subTestRes(6, "fail"); + } /******************************************* ***************** TEST 8 ****************** @@ -327,34 +380,44 @@ int main() ports = "50,10-20,1000"; parser->addSelectedPortRule(ip1, WHITELIST_PARSER_IP_DIRECTION_DST, 32, ports); //1000 whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 1000)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 1000)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 10)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 10)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } //inside 80-100 range - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 18)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 18)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } //50 whitelisted - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 50)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 50)) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } //ip should not be whitelisted - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 50)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 50)) { subTestRes(5, "passed"); - else + } + else { subTestRes(5, "fail"); + } /******************************************* ***************** TEST 9 ****************** @@ -366,35 +429,47 @@ int main() ports = string(); parser->addSelectedPortRule(ip3, WHITELIST_PARSER_IP_DIRECTION_DST, 16, ports); - if(wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 15)) + if (wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 15)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } - if(wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 15)) + if (wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 15)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 21)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 21)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) { subTestRes(4, "passed"); - else + } + else { subTestRes(4, "fail"); + } - if(wl->isWhitelisted(&zeroIp, &ip3, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&zeroIp, &ip3, getRandomPort(), getRandomPort())) { subTestRes(5, "passed"); - else + } + else { subTestRes(5, "fail"); + } - if(wl->isWhitelisted(&zeroIp, &ip4, getRandomPort(), getRandomPort())) + if (wl->isWhitelisted(&zeroIp, &ip4, getRandomPort(), getRandomPort())) { subTestRes(6, "passed"); - else + } + else { subTestRes(6, "fail"); + } /******************************************* ***************** TEST 10 ****************** @@ -404,22 +479,28 @@ int main() ports = "10-20"; parser->addSelectedPortRule(ip5, WHITELIST_PARSER_IP_DIRECTION_DST, 0, ports); - if(wl->isWhitelisted(&zeroIp, &ip4, getRandomPort(), 10)) + if (wl->isWhitelisted(&zeroIp, &ip4, getRandomPort(), 10)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) + if (!wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } ports = string(); parser->addSelectedPortRule(ip3, WHITELIST_PARSER_IP_DIRECTION_DST, 0, ports); - if(wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) + if (wl->isWhitelisted(&zeroIp, &ip2, getRandomPort(), 9)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /******************************************* ***************** TEST 11 ***************** @@ -429,20 +510,26 @@ int main() ports = "25"; parser->addSelectedPortRule(ip5, WHITELIST_PARSER_IP_DIRECTION_DST, 8, ports); - if(wl->isWhitelisted(&zeroIp, &ip5, getRandomPort(), 25)) + if (wl->isWhitelisted(&zeroIp, &ip5, getRandomPort(), 25)) { subTestRes(1, "passed"); - else + } + else { subTestRes(1, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip5, 25, 0)) + if (!wl->isWhitelisted(&zeroIp, &ip5, 25, 0)) { subTestRes(2, "passed"); - else + } + else { subTestRes(2, "fail"); + } - if(!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 25)) + if (!wl->isWhitelisted(&zeroIp, &ip1, getRandomPort(), 25)) { subTestRes(3, "passed"); - else + } + else { subTestRes(3, "fail"); + } /* if(failCounter == 0) From 48aec36c8146868b30af9bc05e3b1b5202ea1b83 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Fri, 20 Sep 2019 16:42:48 +0200 Subject: [PATCH 36/40] travis build fix --- brute_force_detector/brute_force_detector.cpp | 30 +++++++------------ brute_force_detector/brute_force_detector.h | 6 ++-- brute_force_detector/sender.cpp | 18 ++++------- 3 files changed, 19 insertions(+), 35 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 525c1c5b..d46639ad 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -82,26 +82,16 @@ using namespace std; UR_FIELDS( // BASIC_FLOW - ipaddr - SRC_IP, // Source address of a flow - ipaddr - DST_IP, // Destination address of a flow - uint16 - SRC_PORT, // Source transport-layer port - uint16 - DST_PORT, // Destination transport-layer port - uint8 - PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) - uint32 - PACKETS, // Number of packets in a flow or in an interval - uint64 - BYTES, // Number of bytes in a flow or in an interval - time - TIME_FIRST, // Timestamp of the first packet of a flow - time - TIME_LAST, // Timestamp of the last packet of a flow - uint8 - TCP_FLAGS, // TCP flags of a flow (logical OR over TCP flags field of all packets) + ipaddr SRC_IP, // Source address of a flow + ipaddr DST_IP, // Destination address of a flow + uint16 SRC_PORT, // Source transport-layer port + uint16 DST_PORT, // Destination transport-layer port + uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint32 PACKETS, // Number of packets in a flow or in an interval + uint64 BYTES, // Number of bytes in a flow or in an interval + time TIME_FIRST, // Timestamp of the first packet of a flow + time TIME_LAST, // Timestamp of the last packet of a flow + uint8 TCP_FLAGS, // TCP flags of a flow (logical OR over TCP flags field of all packets) ) /* ************************************************************************* */ diff --git a/brute_force_detector/brute_force_detector.h b/brute_force_detector/brute_force_detector.h index 4165b9c9..55dff96c 100644 --- a/brute_force_detector/brute_force_detector.h +++ b/brute_force_detector/brute_force_detector.h @@ -71,17 +71,17 @@ struct cmpByIpAddr { struct thousandsSeparator : std::numpunct { // use dot as separator - char do_thousands_sep() const override { return '.'; } + char do_thousands_sep() const { return '.'; } // digits are grouped by 3 digits each - std::string do_grouping() const override { return "\3"; } + std::string do_grouping() const { return "\3"; } }; class logInfo { public: - explicit logInfo(std::string _protocolName) : protocolName(std::move(_protocolName)), + explicit logInfo(std::string _protocolName) : protocolName((_protocolName)), flows(0), incomingFlows(0), outgoingFlows(0), diff --git a/brute_force_detector/sender.cpp b/brute_force_detector/sender.cpp index 7c0f7582..eb5c8fd6 100644 --- a/brute_force_detector/sender.cpp +++ b/brute_force_detector/sender.cpp @@ -45,18 +45,12 @@ #include "sender.h" UR_FIELDS( - time - DETECTION_TIME, // Timestamp of the detection of some event - uint8 - WARDEN_TYPE, // Type of event (see Warden README for more information) - ipaddr - SRC_IP, // Source address of a flow - uint8 - PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) - uint16 - DST_PORT, // Destination transport-layer port - uint32 - EVENT_SCALE, // Attack intensity + time DETECTION_TIME, // Timestamp of the detection of some event + uint8 WARDEN_TYPE, // Type of event (see Warden README for more information) + ipaddr SRC_IP, // Source address of a flow + uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint16 DST_PORT, // Destination transport-layer port + uint32 EVENT_SCALE, // Attack intensity string NOTE, // Generic string note ) From a81800e80d832626a52f1f25039c0116a027a46d Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Fri, 20 Sep 2019 16:42:48 +0200 Subject: [PATCH 37/40] travis build fix --- brute_force_detector/brute_force_detector.cpp | 31 ++++++------------- brute_force_detector/brute_force_detector.h | 6 ++-- brute_force_detector/sender.cpp | 18 ++++------- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index 525c1c5b..f98762e7 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -82,26 +82,16 @@ using namespace std; UR_FIELDS( // BASIC_FLOW - ipaddr - SRC_IP, // Source address of a flow - ipaddr - DST_IP, // Destination address of a flow - uint16 - SRC_PORT, // Source transport-layer port - uint16 - DST_PORT, // Destination transport-layer port - uint8 - PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) - uint32 - PACKETS, // Number of packets in a flow or in an interval - uint64 - BYTES, // Number of bytes in a flow or in an interval - time - TIME_FIRST, // Timestamp of the first packet of a flow - time - TIME_LAST, // Timestamp of the last packet of a flow - uint8 - TCP_FLAGS, // TCP flags of a flow (logical OR over TCP flags field of all packets) + ipaddr SRC_IP, // Source address of a flow + ipaddr DST_IP, // Destination address of a flow + uint16 SRC_PORT, // Source transport-layer port + uint16 DST_PORT, // Destination transport-layer port + uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint32 PACKETS, // Number of packets in a flow or in an interval + uint64 BYTES, // Number of bytes in a flow or in an interval + time TIME_FIRST, // Timestamp of the first packet of a flow + time TIME_LAST, // Timestamp of the last packet of a flow + uint8 TCP_FLAGS, // TCP flags of a flow (logical OR over TCP flags field of all packets) ) /* ************************************************************************* */ @@ -172,7 +162,6 @@ printFlowPercent(uint64_t b, uint64_t p, const std::string &comment /* optional, int main(int argc, char **argv) { - getc(stdin); // ***** TRAP initialization ***** int ret; INIT_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS) diff --git a/brute_force_detector/brute_force_detector.h b/brute_force_detector/brute_force_detector.h index 4165b9c9..55dff96c 100644 --- a/brute_force_detector/brute_force_detector.h +++ b/brute_force_detector/brute_force_detector.h @@ -71,17 +71,17 @@ struct cmpByIpAddr { struct thousandsSeparator : std::numpunct { // use dot as separator - char do_thousands_sep() const override { return '.'; } + char do_thousands_sep() const { return '.'; } // digits are grouped by 3 digits each - std::string do_grouping() const override { return "\3"; } + std::string do_grouping() const { return "\3"; } }; class logInfo { public: - explicit logInfo(std::string _protocolName) : protocolName(std::move(_protocolName)), + explicit logInfo(std::string _protocolName) : protocolName((_protocolName)), flows(0), incomingFlows(0), outgoingFlows(0), diff --git a/brute_force_detector/sender.cpp b/brute_force_detector/sender.cpp index 7c0f7582..eb5c8fd6 100644 --- a/brute_force_detector/sender.cpp +++ b/brute_force_detector/sender.cpp @@ -45,18 +45,12 @@ #include "sender.h" UR_FIELDS( - time - DETECTION_TIME, // Timestamp of the detection of some event - uint8 - WARDEN_TYPE, // Type of event (see Warden README for more information) - ipaddr - SRC_IP, // Source address of a flow - uint8 - PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) - uint16 - DST_PORT, // Destination transport-layer port - uint32 - EVENT_SCALE, // Attack intensity + time DETECTION_TIME, // Timestamp of the detection of some event + uint8 WARDEN_TYPE, // Type of event (see Warden README for more information) + ipaddr SRC_IP, // Source address of a flow + uint8 PROTOCOL, // L4 protocol (TCP, UDP, ICMP, etc.) + uint16 DST_PORT, // Destination transport-layer port + uint32 EVENT_SCALE, // Attack intensity string NOTE, // Generic string note ) From 903676cbabf330e3728d71c7ee46758180e94c32 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Mon, 23 Sep 2019 17:16:31 +0200 Subject: [PATCH 38/40] Adhering to c++03 --- Makefile.am | 3 +- brute_force_detector/Makefile.am | 1 - brute_force_detector/brute_force_detector.cpp | 8 +- brute_force_detector/config.cpp | 93 ++++++++++--------- brute_force_detector/host.h | 72 +++++++------- brute_force_detector/record.h | 26 +++--- 6 files changed, 99 insertions(+), 104 deletions(-) diff --git a/Makefile.am b/Makefile.am index e8ca91f0..b18b74fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,4 @@ ACLOCAL_AMFLAGS = -I m4 - SUBDIRS=amplification_detection \ blacklistfilter \ blacklistfilter/adaptive_filter \ @@ -51,7 +50,7 @@ deb: make distdir && cd nemea-detectors-@VERSION@ && debuild -i -us -uc -b else endif - + deb-clean: rm -rf nemea-detectors_*.build* nemea-detectors_*.changes nemea-detectors*.deb nemea-detectors_*.orig.tar.gz nemea-detectors-*.tar.gz nemea-detectors-@VERSION@ diff --git a/brute_force_detector/Makefile.am b/brute_force_detector/Makefile.am index 0e76edd9..7592c9b5 100644 --- a/brute_force_detector/Makefile.am +++ b/brute_force_detector/Makefile.am @@ -1,4 +1,3 @@ - bin_PROGRAMS=brute_force_detector brute_force_detector_SOURCES=telnet_server_profile.cpp telnet_server_profile.h record.h record.cpp brute_force_detector.h brute_force_detector.cpp config.h config.cpp host.h host.cpp sender.h sender.cpp whitelist.cpp whitelist.h fields.c fields.h whitelist_unit_test_SOURCES=whitelist_unit_test.cpp whitelist.h whitelist.cpp diff --git a/brute_force_detector/brute_force_detector.cpp b/brute_force_detector/brute_force_detector.cpp index f98762e7..fc5264c6 100644 --- a/brute_force_detector/brute_force_detector.cpp +++ b/brute_force_detector/brute_force_detector.cpp @@ -50,14 +50,12 @@ #include #include #include -#include #include #include #include #include -#include #include #include "record.h" @@ -66,8 +64,6 @@ #include "sender.h" #include "brute_force_detector.h" #include "whitelist.h" -#include -#include #include #ifdef __cplusplus @@ -169,7 +165,7 @@ int main(int argc, char **argv) { // ***** Capturing signals ***** #ifdef HAVE_SIGACTION - struct sigaction sigAction{}; + struct sigaction sigAction = {}; sigAction.sa_handler = signalHandler; sigemptyset (&sigAction.sa_mask); @@ -340,7 +336,7 @@ int main(int argc, char **argv) { } // Process rest of new data - IRecord::MatchStructure flow{ + IRecord::MatchStructure flow = { .flags = ur_get(tmplt, data, F_TCP_FLAGS), .packets = ur_get(tmplt, data, F_PACKETS), .bytes = ur_get(tmplt, data, F_BYTES), diff --git a/brute_force_detector/config.cpp b/brute_force_detector/config.cpp index eb1ffa0f..7873fff2 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -43,6 +43,7 @@ */ #include "config.h" +#include using namespace std; @@ -232,169 +233,169 @@ bool Config::initFromFile(const string &path) { // ****** GENERAL ****** // ********************* if (keyword == kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) { - GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = std::stoul(value, NULL); + GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) { - GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = std::stod(value, NULL); + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = strtod(value.c_str(), NULL); } else if (keyword == kw_GENERAL_IGNORE_FIRST_SEND) { - GENERAL_IGNORE_FIRST_SEND = std::stoul(value, NULL); + GENERAL_IGNORE_FIRST_SEND = strtoul(value.c_str(), NULL, 0); } // ********************* // ******* SSH ********* // ********************* else if (keyword == kw_SSH_MAX_RECORDS) { - SSH_MAX_RECORDS = std::stoul(value, NULL); + SSH_MAX_RECORDS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_SSH_FLOW_THRESHOLD) { - SSH_FLOW_THRESHOLD = std::stoul(value, NULL); + SSH_FLOW_THRESHOLD = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_SSH_MATCHED_FLOW_RATIO) { - SSH_MATCHED_FLOW_RATIO = std::stod(value, NULL); + SSH_MATCHED_FLOW_RATIO = strtod(value.c_str(), NULL); } else if (keyword == kw_SSH_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_SSH_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); SSH_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) { - SSH_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); + SSH_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) { - SSH_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); + SSH_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_BYTES) { - SSH_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); + SSH_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_BYTES) { - SSH_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); + SSH_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) { - SSH_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, NULL); + SSH_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) { - SSH_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, NULL); + SSH_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) { - SSH_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, NULL); + SSH_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) { - SSH_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, NULL); + SSH_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } // ********************* // ******* RDP ********* // ********************* else if (keyword == kw_RDP_MAX_RECORDS) { - RDP_MAX_RECORDS = std::stoul(value, NULL); + RDP_MAX_RECORDS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_RDP_FLOW_THRESHOLD) { - RDP_FLOW_THRESHOLD = std::stoul(value, NULL); + RDP_FLOW_THRESHOLD = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_RDP_MATCHED_FLOW_RATIO) { - RDP_MATCHED_FLOW_RATIO = std::stod(value, NULL); + RDP_MATCHED_FLOW_RATIO = strtod(value.c_str(), NULL); } else if (keyword == kw_RDP_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_RDP_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); RDP_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) { - RDP_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); + RDP_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) { - RDP_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); + RDP_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_BYTES) { - RDP_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); + RDP_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_BYTES) { - RDP_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); + RDP_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) { - RDP_BRUTEFORCE_OUT_MIN_PACKETS = std::stoul(value, NULL); + RDP_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) { - RDP_BRUTEFORCE_OUT_MAX_PACKETS = std::stoul(value, NULL); + RDP_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) { - RDP_BRUTEFORCE_OUT_MIN_BYTES = std::stoul(value, NULL); + RDP_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) { - RDP_BRUTEFORCE_OUT_MAX_BYTES = std::stoul(value, NULL); + RDP_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } // ********************* // ****** TELNET ******* // ********************* else if (keyword == kw_TELNET_MAX_RECORDS) { - TELNET_MAX_RECORDS = std::stoul(value, NULL); + TELNET_MAX_RECORDS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_TELNET_FLOW_THRESHOLD) { - TELNET_FLOW_THRESHOLD = std::stoul(value, NULL); + TELNET_FLOW_THRESHOLD = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_TELNET_MATCHED_FLOW_RATIO) { - TELNET_MATCHED_FLOW_RATIO = std::stod(value, NULL); + TELNET_MATCHED_FLOW_RATIO = strtod(value.c_str(), NULL); } else if (keyword == kw_TELNET_ATTACK_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_RECORD_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_HOST_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_REPORT_TIMEOUT) { - uint32_t sec = std::stoul(value, NULL); + uint32_t sec = strtoul(value.c_str(), NULL, 0); TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) { - TELNET_BRUTEFORCE_INC_MIN_PACKETS = std::stoul(value, NULL); + TELNET_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) { - TELNET_BRUTEFORCE_INC_MAX_PACKETS = std::stoul(value, NULL); + TELNET_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) { - TELNET_BRUTEFORCE_INC_MIN_BYTES = std::stoul(value, NULL); + TELNET_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) { - TELNET_BRUTEFORCE_INC_MAX_BYTES = std::stoul(value, NULL); + TELNET_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } // ********************* // ******* UNKNOWN ***** diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 712abda9..8f5e2dfa 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -71,7 +71,7 @@ class IHost { scanned = false; } - virtual ~IHost() = default; + virtual ~IHost() {}; enum ATTACK_STATE { NO_ATTACK, @@ -181,15 +181,15 @@ class SSHHost : public IHost { public: SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} - bool addRecord(SSHRecord *record, void *structure, uint8_t direction) override; + bool addRecord(SSHRecord *record, void *structure, uint8_t direction); - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + ATTACK_STATE checkForAttack(ur_time_t actualTime); - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getSSHHostDeleteTimeout(); } + ur_time_t getHostDeleteTimeout() { return Config::getInstance().getSSHHostDeleteTimeout(); } - ur_time_t getHostReportTimeout() override { return Config::getInstance().getSSHReportTimeout(); } + ur_time_t getHostReportTimeout() { return Config::getInstance().getSSHReportTimeout(); } - ur_time_t getHostAttackTimeout() override { return Config::getInstance().getSSHAttackTimeout(); } + ur_time_t getHostAttackTimeout() { return Config::getInstance().getSSHAttackTimeout(); } }; @@ -198,15 +198,15 @@ class RDPHost : public IHost { public: RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} - bool addRecord(RDPRecord *record, void *structure, uint8_t direction) override; + bool addRecord(RDPRecord *record, void *structure, uint8_t direction); - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + ATTACK_STATE checkForAttack(ur_time_t actualTime); - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getRDPHostDeleteTimeout(); } + ur_time_t getHostDeleteTimeout() { return Config::getInstance().getRDPHostDeleteTimeout(); } - ur_time_t getHostReportTimeout() override { return Config::getInstance().getRDPReportTimeout(); } + ur_time_t getHostReportTimeout() { return Config::getInstance().getRDPReportTimeout(); } - ur_time_t getHostAttackTimeout() override { return Config::getInstance().getRDPAttackTimeout(); } + ur_time_t getHostAttackTimeout() { return Config::getInstance().getRDPAttackTimeout(); } }; class TELNETHost : public IHost { @@ -214,15 +214,15 @@ class TELNETHost : public IHost { public: TELNETHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} - bool addRecord(TELNETRecord *record, void *structure, uint8_t direction) override; + bool addRecord(TELNETRecord *record, void *structure, uint8_t direction); - ATTACK_STATE checkForAttack(ur_time_t actualTime) override; + ATTACK_STATE checkForAttack(ur_time_t actualTime); - ur_time_t getHostDeleteTimeout() override { return Config::getInstance().getTELNETHostDeleteTimeout(); } + ur_time_t getHostDeleteTimeout() { return Config::getInstance().getTELNETHostDeleteTimeout(); } - ur_time_t getHostReportTimeout() override { return Config::getInstance().getTELNETReportTimeout(); } + ur_time_t getHostReportTimeout() { return Config::getInstance().getTELNETReportTimeout(); } - ur_time_t getHostAttackTimeout() override { return Config::getInstance().getTELNETAttackTimeout(); } + ur_time_t getHostAttackTimeout() { return Config::getInstance().getTELNETAttackTimeout(); } }; ////////////////////////////////////////////////////////////////////////////////////// @@ -232,9 +232,9 @@ class TELNETHost : public IHost { class IHostMap { public: - IHostMap() = default; + IHostMap() {}; - ~IHostMap() = default; + ~IHostMap() {}; virtual void clear() = 0; @@ -288,23 +288,23 @@ class IHostMap { class SSHHostMap : public IHostMap { public: - SSHHostMap() = default; + SSHHostMap() {}; - ~SSHHostMap() = default; + ~SSHHostMap() {}; - void clear() override { + void clear() { IHostMap::clearMap(&hostMap); } - inline uint16_t size() override { + inline uint16_t size() { return hostMap.size(); } SSHHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void deleteOldRecordAndHosts(ur_time_t actualTime); - void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); private: map hostMap; @@ -313,23 +313,23 @@ class SSHHostMap : public IHostMap { class RDPHostMap : public IHostMap { public: - RDPHostMap() = default; + RDPHostMap() {}; - ~RDPHostMap() = default; + ~RDPHostMap() {}; - void clear() override { + void clear() { IHostMap::clearMap(&hostMap); } - inline uint16_t size() override { + inline uint16_t size() { return hostMap.size(); } RDPHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void deleteOldRecordAndHosts(ur_time_t actualTime); - void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); private: map hostMap; @@ -339,23 +339,23 @@ class RDPHostMap : public IHostMap { class TELNETHostMap : public IHostMap { public: - TELNETHostMap() = default; + TELNETHostMap() {}; - ~TELNETHostMap() = default; + ~TELNETHostMap() {}; - void clear() override { + void clear() { IHostMap::clearMap(&hostMap); } - inline uint16_t size() override { + inline uint16_t size() { return hostMap.size(); } TELNETHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); - void deleteOldRecordAndHosts(ur_time_t actualTime) override; + void deleteOldRecordAndHosts(ur_time_t actualTime); - void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) override; + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); private: map hostMap; diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 5d7e4a01..ddcadc9b 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -73,7 +73,7 @@ class IRecord { public: IRecord() : signatureMatched(false) {} - virtual ~IRecord() = default; + virtual ~IRecord() {}; virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl) = 0; @@ -96,8 +96,8 @@ class IRecord { }; // May seem unused, actually are passed to reporting functions - ip_addr_t dstIp{}; - ur_time_t flowLastSeen{}; + ip_addr_t dstIp; + ur_time_t flowLastSeen; protected: @@ -110,11 +110,11 @@ class SSHRecord : public IRecord { public: SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithIncomingSignature(void *structure, Whitelist *wl) ; - bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) ; - ur_time_t getRecordTimeout() override { return Config::getInstance().getSSHRecordTimeout(); } + ur_time_t getRecordTimeout() { return Config::getInstance().getSSHRecordTimeout(); } const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH }; @@ -125,11 +125,11 @@ class RDPRecord : public IRecord { public: RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithIncomingSignature(void *structure, Whitelist *wl); - bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl); - ur_time_t getRecordTimeout() override { return Config::getInstance().getRDPRecordTimeout(); } + ur_time_t getRecordTimeout() { return Config::getInstance().getRDPRecordTimeout(); } const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH const static uint8_t signatureFlagsWin8ManualCon = 0b00011110; // SYN + ACK + PSH + RST @@ -142,11 +142,11 @@ class TELNETRecord : public IRecord { public: TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - bool matchWithIncomingSignature(void *structure, Whitelist *wl) override; + bool matchWithIncomingSignature(void *structure, Whitelist *wl) ; - bool matchWithOutgoingSignature(void *structure, Whitelist *wl) override; + bool matchWithOutgoingSignature(void *structure, Whitelist *wl) ; - ur_time_t getRecordTimeout() override { return Config::getInstance().getTELNETRecordTimeout(); } + ur_time_t getRecordTimeout() { return Config::getInstance().getTELNETRecordTimeout(); } const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH const static uint8_t signatureFlagsFin = 0b00011011; // SYN + ACK + PSH + FIN @@ -214,7 +214,7 @@ class RecordList { std::set hashedDstIPSet; std::set hashedDstTotalIPSet; - char victimIP[46]{}; + char victimIP[46]; }; template From fc9b09cdc9675764d86bc26d1bbc68850efd212e Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Wed, 25 Sep 2019 11:42:01 +0200 Subject: [PATCH 39/40] Revert "Changes I did not make" This reverts commit 38c115f8 --- blacklistfilter/Makefile.am | 4 +- blacklistfilter/adaptive_filter/README.md | 122 +----------- .../blacklist_aggregator.py | 0 .../blacklist_downloader/README.md | 177 +----------------- blacklistfilter/dnsdetect/README.md | 109 ----------- .../dnsdetect/dnsdetect_config.xml | 10 +- blacklistfilter/hostrecvwarden.pl | 42 +++++ blacklistfilter/ipdetect/README.md | 70 +------ blacklistfilter/ipdetect/ipdetect_config.xml | 4 +- blacklistfilter/urldetect/README.md | 80 ++------ .../urldetect/urldetect_config.xml | 9 +- 11 files changed, 82 insertions(+), 545 deletions(-) rename blacklistfilter/{blacklist_aggregator => }/blacklist_aggregator.py (100%) create mode 100644 blacklistfilter/hostrecvwarden.pl diff --git a/blacklistfilter/Makefile.am b/blacklistfilter/Makefile.am index ad973e6d..908b9ca3 100644 --- a/blacklistfilter/Makefile.am +++ b/blacklistfilter/Makefile.am @@ -38,7 +38,7 @@ urlblacklistfilter_CXXFLAGS=-std=c++11 -Wall -pedantic urlblacklistfiltersysconfdir=${sysconfdir}/blacklistfilter dist_urlblacklistfiltersysconf_DATA=urldetect/urldetect_config.xml -EXTRA_DIST=blacklist_aggregator/blacklist_aggregator.py \ +EXTRA_DIST=blacklist_aggregator.py \ blacklist_downloader/bl_downloader.py.in \ blacklist_downloader/bl_downloader_config.xml \ urldetect/patternstrings.h \ @@ -51,7 +51,7 @@ EXTRA_DIST=blacklist_aggregator/blacklist_aggregator.py \ dnsdetect/README.md \ dnsdetect/dnsdetect_config.xml -bin_SCRIPTS=blacklist_downloader/bl_downloader.py blacklist_aggregator/blacklist_aggregator.py +bin_SCRIPTS=blacklist_downloader/bl_downloader.py blacklist_aggregator.py dist_blacklistfilter_DATA=blacklist_downloader/bl_downloader_config.xml diff --git a/blacklistfilter/adaptive_filter/README.md b/blacklistfilter/adaptive_filter/README.md index 2b7ec9ff..df6b066d 100644 --- a/blacklistfilter/adaptive_filter/README.md +++ b/blacklistfilter/adaptive_filter/README.md @@ -1,120 +1,2 @@ -# Adaptive filter - -Adaptive filter is the heart of the [blacklistfilter suite](../README.md). It receives all the detected events from -detectors (IP/URL/DNS) and decides whether the detection event will be reported to the Warden, or whether the event -needs further analysis of the suspicious client's traffic (who communicated with blacklisted entity). This is achieved with -so called `scenarios`, where these situations are defined. - - -![Big picture](../doc/big_picture.png) - - -## Usage: - -``` -Usage: adaptive_filter -i [-c ] [-e ] [-p ] - [-l ] [-a ] -``` - -- **blacklist_config**: Path to config file of the blacklist downloader (default: /etc/nemea/blacklistfilter/bl_downloader_config.xml) -- **evidence_timeout**: Timeout in seconds, meaning how long shall be the client monitored when the some matches (default: 600) -- **process_interval**: Timeout in seconds, meaning how often the adaptive filter processes new scenario events (default: 30) -- **log_level**: Standard logging level, 10=DEBUG, 20=INFO, etc. (default: 20) -- **adaptive_blacklist**: Path to the adaptive blacklist (default: /tmp/blacklistfilter/adaptive.blist) - - -## Interfaces -Inputs - - 0: FMT_JSON - "aggregated_blacklist" - aggregated IP/URL events - - 1: DNS flows - non-aggregated flows from DNS detector - -Outputs - - 0: FMT_JSON - "aggregated_blacklist" - sending events to Reporter - - 1: FMT_JSON - "blacklist_evidence" - sending events to Evidence - -## Scenarios -The scenarios define what cases trigger further monitoring of clients' traffic. -Every scenario has its defining key and a set of matching conditions. There are 2 scenarios so far. -For future reference, the class is called _scenario_, the instance is then called _scenario event_. -Also, beware the difference between _scenario event_ and _grouped event_. - -![Scenario model](../doc/scenario.png) - -### Attributes -- ID: UUID of the scenario event -- event_type: Scenario event type (BotnetDetection, DNSDetection, ..) -- grouped_events: A list of the events with the same key (in the same evidence timeout window). E.g. two distinct events - coming from the blacklist aggregator, where the source of trouble is the same C&C server (BotnetDetection scenario) -- grouped_events_cnt: Count of the grouped events -- first_detections_ts: Timestamp of the first grouped event -- last_detections_ts: Timestamp of the last grouped event -- processed_ts: Timestamp of the last scenario event processing -- adaptive_entities: Adaptive entities for the scenario event. E.g. a list of IPs who communicated with the C&C - - -### BotnetDetection -This scenario aims to analyze traffic of the clients who communicated with some C&C server. - -Key: - - IP address of the C&C server - -Matching conditions: - - The detection came from the IP/URL interface ("aggregated_blacklist") - - The detection type is "ip" - - The blacklist has a category Intrusion.Botnet - -### DNSDetection -This scenario aims to catch the DNS queries to blacklisted domains, translate them to IP addresses and then analyze -traffic with these addresses and try to identify the originator of the query. This is necessary because we cannot -report directly the SRC_IP of the DNS query to the blacklisted domain, since the SRC_IP is a recursive DNS resolver. -Key: - - Domain name -Matching conditions: - - The detection came from the DNS interface - - -## Operation -### Recieving events -- Adaptive filter listens for detection events from IP/URL detectors (aggregated) and from DNS detector (non-aggregated) -- Upon each received detection event, it is checked against defined scenarios, whether there is a match -- If not, the event is only passed to the Reporter and nothing is stored -- If yes, new `scenario_event` is created or an existing is updated. These scenario events are stored internally - -### Processing events -- Every `process_interval`, all the stored scenario events are checked -- Processing event means: - - Ensuring all the adaptive entities are up to date (when there is a new grouped event) - - Exporting the scenario event to Evidence when evidence timeout expired - - Creating new detector file (adaptive blacklist) when any of the above two actions happened (adding/removing entries - in the adaptive blacklist) - -### Adaptive IP detector -Adaptive IP detector is a normal IP detector except it uses a different format of the detector file (adaptive_blacklist). -There is also an event ID for each entry. When new detector file is created by the adaptive filter. Adaptive IP detector reloads the entries and starts detection -(like the normal IP detector). But these detections are then stored in Evidence (see the "Big picture" above). - - -## Evidence -The Evidence consists of two files: -- `evidence_detection`: All the scenario events stored by the Adaptive filter. Every time the evidence timeout expires for -the current event, this event is exported to this file. -- `evidence_adaptive`: All the adaptive events corresponding to the scenario events. I.e. the traffic of the suspicious clients - -The scenario events and adaptive events can be paired using the event ID. - -### Evaluation (experimental) -The offline evaluation can be done using the Evaluator script. This script loads the two files and tries to find some -patterns in the communication, these are: -- Flow count of the client and the C&C communication -- Flow count of the client and some other C&Cs communication -- Count of flows with IRC ports -- Information about the client from the [NERD](nerd.cesnet.cz) system - - -``` -Usage: evaluator.py -i [-c ] [-4 ] [-n ] -``` - -#### Example output of Evaluator - -![Evaluator](../doc/evaluator.png) +## Adaptive filter +# TODO \ No newline at end of file diff --git a/blacklistfilter/blacklist_aggregator/blacklist_aggregator.py b/blacklistfilter/blacklist_aggregator.py similarity index 100% rename from blacklistfilter/blacklist_aggregator/blacklist_aggregator.py rename to blacklistfilter/blacklist_aggregator.py diff --git a/blacklistfilter/blacklist_downloader/README.md b/blacklistfilter/blacklist_downloader/README.md index a2dafd10..6742d77e 100644 --- a/blacklistfilter/blacklist_downloader/README.md +++ b/blacklistfilter/blacklist_downloader/README.md @@ -9,7 +9,7 @@ along with the list of blacklists to download. ## How it works By default, the downloader fetches the blacklists every 10 minutes. If there is an update of some -blacklist, it creates a new file(s) for the detector(s). This file is preprocessed by the downloader, so that +blacklist, it creates a new file for the detector. This file is preprocessed by the downloader, so that the detector can just read it and start the detection. Preprocessing means: one entity per line, adding blacklist indexes to the entities, trimming whitespaces, sorting the entities,.. @@ -17,177 +17,4 @@ There are 3 types of blacklists: IP/URL/DNS. However, the URL detector also dete ## Usage: -``` -Usage: bl_downloader.py [-c ] [-r ] [-l ] -``` - -## Configuration -Is done via configuration file (command-line options override config file). -Below is an example config - -```xml - - - - - 10 - - 5 - - - - /tmp/blacklistfilter/ip4.blist - /tmp/blacklistfilter/ip6.blist - /tmp/blacklistfilter/url.blist - /tmp/blacklistfilter/dns.blist - - - - - - - - 1 - - Intrusion.Botnet - - web - - ZeuS Tracker - - https://zeustracker.abuse.ch/blocklist.php?download=ipblocklist - - 10 - - 4 - - - - - - - 1 - - web - - Malware Domains - - http://mirror1.malwaredomains.com/files/justdomains - - Malware - - 10 - - URL,DNS - - - - 2 - web - http://data.phishtank.com/data/online-valid.csv - - 2 - PhishTank - Fraud.Phishing - 10 - URL,DNS - - - - - -``` - -- `repo_path` - path to GIT repo. Provides local versioning of all the blacklists. Upon module startup, if no GIT repo in this path is present, it is created. If the path is present, it continues versoning. -- `log_level` - standard level of logging (to stderr). 20 = INFO, 10 = DEBUG, etc. - - -## Operation - -- Module performs a check of all blacklists every `download_interval` (global/general one) -- Every blacklist can be also fetched at individual `download_interval` (preventing ban) -- The entities are extracted using regexps -- When there is a change in IP or URL/DNS blacklist - - new detector file is created - - changes are commited to GIT repo (when -r given) - -Demonstrated also by UML diagram below: - -![URL preprocessing](../doc/downloader_final.png) - -## About detector files - -Detector files are special files created by blacklist downloader for the detectors (ip/url/dns). -Every row contains an entity, separator and blacklist index. All the entities are sorted (especially useful for ip blacklistfilter, which uses binary search). When there is a change in any blacklist of a given type, new detector file is created (rewrites the old one). The detector listens for the file change (inotify's IN_CLOSE_WRITE flag) and reloads the file when -there is a change. The detector doesn't have to process the data, it just loads them and detects. All the preprocessing (sorting, case-insensitivying, ..) is done by the downloader. - -The blacklist index is a bitmap, so a value 9 means the entity is present on the blacklists with ID 1 and 4. - - -### Examples -*/tmp/blacklistfilter/ip4.blist* -``` -1.10.16.0/20,8 -1.19.0.0/16,8 -1.22.124.243,256 -1.22.180.84,256 -1.22.241.193,256 -``` - -*/tmp/blacklistfilter/ip6.blist* -``` -2401:c580:0000:0000:0000:0000:0000:0000/32,256 -2402:6680:0000:0000:0000:0000:0000:0000/32,256 -2405:b180:0000:0000:0000:0000:0000:0000/32,256 -``` - -*/tmp/blacklistfilter/url.blist* -``` -0632qyw.com\1 -06642.ir/wp-includes/fonts/chaseonline2019/ch1.1/07b2f33e388cf03a82397b057fb9e03b\4 -06works-plus.com\1 -071899.com\1 -``` - -*/tmp/blacklistfilter/dns.blist* -``` -dorothyn.com\1 -dorpk2sa2i.dayzcy3xae.madpendesign.com.au\1 -dortxn.com\1 -``` - -## Example module run -``` -alois@some_kinda_linux:~$ bl_downloader.py --repo-path /tmp/repicko -[2019-03-27 14:35:22,043] - INFO - Initialized empty Git repository in /tmp/repicko/.git/ -[2019-03-27 14:35:22,304] - INFO - Updated IPv4Blacklist: ZeuS Tracker -[2019-03-27 14:35:22,549] - INFO - Updated IPv4Blacklist: Feodo Tracker -[2019-03-27 14:35:22,761] - INFO - Updated IPv4Blacklist: Ransomware Tracker -[2019-03-27 14:35:22,920] - INFO - Updated IPv4Blacklist: Spamhaus Drop -[2019-03-27 14:35:23,036] - INFO - Updated IPv4Blacklist: Andoniaf Miners -[2019-03-27 14:35:24,202] - INFO - Updated IPv4Blacklist: SANS Miners -[2019-03-27 14:35:25,110] - INFO - Updated IPv4Blacklist: Cryptoioc Miners -[2019-03-27 14:35:26,794] - INFO - Updated IPv4Blacklist: CI Army - BadGuys -[2019-03-27 14:35:26,802] - WARNING - IPv4Blacklist, CZ.NIC Honeypot Cowrie: No valid entities found -[2019-03-27 14:35:26,995] - INFO - Updated IPv4Blacklist: CZ.NIC Honeypot Dionaea -[2019-03-27 14:35:27,616] - INFO - Updated IPv4Blacklist: Malc0de -[2019-03-27 14:35:27,938] - INFO - Updated IPv4Blacklist: URLVir -[2019-03-27 14:35:27,984] - INFO - Committed changes to GIT -[2019-03-27 14:35:28,146] - INFO - New IPv4 detector file created: /tmp/blacklistfilter/ip4.blist -[2019-03-27 14:35:28,249] - INFO - Updated IPv6Blacklist: Spamhaus Drop -[2019-03-27 14:35:28,264] - INFO - Committed changes to GIT -[2019-03-27 14:35:28,266] - INFO - New IPv6 detector file created: /tmp/blacklistfilter/ip6.blist -[2019-03-27 14:35:30,231] - INFO - Updated URLandDNSBlacklist: Malware Domains -[2019-03-27 14:35:30,414] - WARNING - Could not fetch blacklist: http://data.phishtank.com/data/online-valid.csv -Status code: 509 -[2019-03-27 14:35:31,269] - INFO - Updated URLandDNSBlacklist: OpenPhish -[2019-03-27 14:35:31,854] - INFO - Updated URLandDNSBlacklist: DisconnectMe -[2019-03-27 14:35:32,017] - INFO - Updated URLandDNSBlacklist: Booters -[2019-03-27 14:35:32,321] - INFO - Updated URLandDNSBlacklist: Zeus Tracker -[2019-03-27 14:35:32,560] - INFO - Updated URLandDNSBlacklist: Ransomware Tracker -[2019-03-27 14:35:32,656] - INFO - Committed changes to GIT -[2019-03-27 14:35:32,939] - INFO - New URL detector file created: /tmp/blacklistfilter/url.blist -[2019-03-27 14:35:32,939] - INFO - New DNS detector file created: /tmp/blacklistfilter/dns.blist -``` \ No newline at end of file +Just run the script without arguments diff --git a/blacklistfilter/dnsdetect/README.md b/blacklistfilter/dnsdetect/README.md index c1e12759..e69de29b 100644 --- a/blacklistfilter/dnsdetect/README.md +++ b/blacklistfilter/dnsdetect/README.md @@ -1,109 +0,0 @@ -# DNS blacklistfilter - -This module is a part of the blacklistfilter suite. For information about other modules, see the main [README](../README.md) - -## Goal - -Module receives the UniRec record and checks if the domain name (FQDN) is present in any DNS/FQDN blacklists -that are available. If the FQDN is present in any blacklist the record is changed by adding an index of the blacklist. -UniRec with this flag is then sent to the output interface. Blacklists are downloaded by a separate module -Blacklist downloader which saves blacklists to a file (specified in configuration) and blacklistfilter uses -this file to reload blacklists. - -## Input/Output - -``` -Input Interface: UniRec format (,) -Output Interface: UniRec format (,,BLACKLIST) -``` - -## Usage - -``` -Usage: dnsblacklistfilter -i [-c ] [-b ] -``` - -## Configuration -Is done via configuration file (command-line options override config file) - -```xml - - - - - - /tmp/blacklistfilter/dns.blist - - - - true - - - -``` - -- `blacklist_file`: A DNS file created by Blacklist downloader, containing (sorted) entries (FQDNs) from all blacklists - -- `watch_blacklists`: A flag indicating whether the blacklist file is being reloaded everytime the file changes. When set to false, -the blacklists are loaded only once at the startup of the module - -## Operation - -- Module reports every single flow (request and reply) with DNS present on some blacklist, it is checking DNS_NAME field (request and reply) -- If `watch_blacklists` flag is true, the module listens for changes (IN_CLOSE_WRITE events) in the file(s) and reloads -them everytime there is a change -- Detection of the FQDN is case-insensitive and deals with little nuances in the FQDNs (such as redundant backslashes). Following -domain names (DNS_NAME field) are treated the same: - -![URL preprocessing](../doc/url_dns.png) - -## Required data - -This module is implemented on TRAP platform, so it receives data on -TRAP input interface in UniRec format. - -UniRec fields required: - -- `DST_IP` (ipaddr): destination IP address of the flow -- `SRC_IP` (ipaddr): source IP address of the flow -- `DST_PORT` (uint16): destination port of the flow -- `SRC_PORT` (uint16): source port of the flow -- `PROTOCOL` (uint8): protocol used (TCP, UDP...) -- `PACKETS` (uint32): packets in the flow -- `BYTES` (uint32): bytes in the flow -- `TIME_FIRST` (time): time of the first packet in the flow -- `TIME_LAST` (time): time of the last packet in the flow -- `DNS_NAME` (string): requested FQDN - - -## Output data - -Upon detection, the input data are sent to the output, enriched with this value: - -- `BLACKLIST` (uint64): indexes of the blacklists (bitmap) which blacklisted the URL - -For example, when the `BLACKLIST` field contains number 9, it means the URL is present on -blacklists with ID 1 and 4 (in binary: 1001) - -## Compilation and linking - -This module requires compilation with `-std=c++11`, because of the usage of *std::vector, streams, etc.*. - -For linking add `-ltrap -lunirec -lnemea-common` -(the module must be compiled as a part of [NEMEA](https://github.com/CESNET/Nemea) repository or using installed libtrap-devel and unirec packages). - - -## Example detection -Below is an example output of this detector. IP addresses are made-up. -There are both requests and replies (can be identified with DNS_ID). DNS_RDATA field is the raw reply. - -``` -ipaddr DST_IP,ipaddr SRC_IP,uint64 BLACKLIST,uint64 BYTES,time TIME_FIRST,time TIME_LAST,uint32 DNS_RR_TTL,uint32 PACKETS,uint16 DNS_ANSWERS,uint16 DNS_CLASS,uint16 DNS_ID,uint16 DNS_PSIZE,uint16 DNS_QTYPE,uint16 DNS_RLENGTH,uint16 DST_PORT,uint16 SRC_PORT,uint8 DNS_DO,uint8 DNS_RCODE,uint8 PROTOCOL,string DNS_NAME,bytes DNS_RDATA -192.168.1.1,192.168.1.107,32,59,2018-09-28T14:16:28.552,2018-09-28T14:16:28.552,0,1,0,1,63445,0,1,0,53,57649,0,0,17,"zstresser.com", -192.168.1.107,192.168.1.1,32,75,2018-09-28T14:16:28.594,2018-09-28T14:16:28.594,300,1,1,1,63445,0,1,14,57649,53,0,0,17,"zstresser.com",3138352e31312e3134352e323439 -192.168.1.107,192.168.1.1,1,132,2018-09-28T14:17:23.677,2018-09-28T14:17:23.677,0,1,0,1,238,0,28,0,57649,53,0,0,17,"zverinova-kucharka.cz", -192.168.1.107,192.168.1.1,1,83,2018-09-28T14:17:23.677,2018-09-28T14:17:23.677,1800,1,1,1,44066,0,1,14,57649,53,0,0,17,"zverinova-kucharka.cz",33372e3135372e3139372e313231 -``` diff --git a/blacklistfilter/dnsdetect/dnsdetect_config.xml b/blacklistfilter/dnsdetect/dnsdetect_config.xml index a11d1df3..df4cfe73 100644 --- a/blacklistfilter/dnsdetect/dnsdetect_config.xml +++ b/blacklistfilter/dnsdetect/dnsdetect_config.xml @@ -1,13 +1,15 @@ - + /tmp/blacklistfilter/dns.blist - true diff --git a/blacklistfilter/hostrecvwarden.pl b/blacklistfilter/hostrecvwarden.pl new file mode 100644 index 00000000..b11989a2 --- /dev/null +++ b/blacklistfilter/hostrecvwarden.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2011-2012 Cesnet z.s.p.o +# +# Use of this source is governed by a BSD-style license, see LICENSE file. + +use strict; + +#------------------------------------------------------------------------------ +# Warden 2.0 Client, Receiver, Example +# +# Simple use of warden-client receiver functionality to download new events +# from # Warden server. This code illustrates how to integrate warden-client +# receive functionality into local applications. +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# This code should developer add into his/her application. + +# Path to warden-client directory +my $warden_path = '/opt/warden-client'; + +# Inclusion of warden-client receiving functionality +require $warden_path . '/lib/WardenClientReceive.pm'; + +# Definition of requested event type. This attributes is also set on server +# and must not change. +my $requested_type = $ARGV[0]; + +# Download of new evetns from Warden server +my @new_events = WardenClientReceive::getNewEvents($warden_path, $requested_type); + +#------------------------------------------------------------------------------ +# Simple code that prints out new events obtained from Warden server. + +no warnings 'uninitialized'; + +foreach (@new_events) { + print join(',', @$_) . "\n"; +} + +exit 0; diff --git a/blacklistfilter/ipdetect/README.md b/blacklistfilter/ipdetect/README.md index 3f0f3517..ee116447 100644 --- a/blacklistfilter/ipdetect/README.md +++ b/blacklistfilter/ipdetect/README.md @@ -1,7 +1,5 @@ # IP blacklistfilter -This module is a part of the blacklistfilter suite. For information about other modules, see the main [README](../README.md) - ## Goal Module receives the UniRec basic flow and checks if the stored source @@ -10,65 +8,27 @@ blacklist that are available. If any of the addresses is blacklisted, the record is changed by adding a number/index of the blacklists that contain this address. UniRec with this flag is then sent to the output interface. Blacklists are downloaded by a separate module -Blacklist downloader which saves blacklists to a file (specified in configuration) and blacklistfilter uses +bl_downloader.py which saves blacklists to a file (specified in configuration) and blacklistfilter uses this file to reload blacklists. ## Input/Output -``` -Input Interface: UniRec format () +Input Interface: UniRec format () Output Interface: UniRec format (,SRC_BLACKLIST,DST_BLACKLIST) -``` ## Usage ``` -Usage: ipblacklistfilter -i [-c ] [-4 ] [-6 ] +Usage: ./ipblacklistfilter -u -i ``` -## Configuration -Is done via configuration file (command-line options override config file) - -```xml - - - - - - /tmp/blacklistfilter/ip4.blist - - - - /tmp/blacklistfilter/ip6.blist - - - - true - - - -``` - - -- `{ipv4/ipv6}_blacklist_file`: An IPv4/IPv6 file created by Blacklist downloader, containing (sorted) entries from all blacklists - -- `watch_blacklists`: A flag indicating whether the blacklist file is being reloaded everytime the file changes. When set to false, -the blacklists are loaded only once at the startup of the module +# Blacklist downloader +IP blacklistfilter uses blacklist file which is handled by Python downloader (bl_downloader.py). +The downloader periodically checks for new blacklist updates and feeds it to the blacklistfilter +using inotify mechanism. The data are preprocessed by the downloader (sorted, trimmed whitespaces etc.) -## Operation - -- Upon startup, if the module can not find/read `ipv4_blacklist_file`, it immediately exits with an error. -The `ipv6_blacklist_file` is optional and its absence only produces a warning. -- Module reports every single flow with src/dst address present on some blacklist, -the only exception is a flow with src/dst port 53 (DNS queries). -- If `watch_blacklists` flag is true, the module listens for changes (IN_CLOSE_WRITE events) in the files and reloads -them everytime there is a change +See "TODO: downloader README ref" ## Required data @@ -95,23 +55,9 @@ Upon detection, the input data are sent to the output, enriched with these value - `DST_BLACKLIST` (uint64): indexes of the blacklists (bitmap) which blacklisted `DST_IP`, zero if not blacklisted - `SRC_BLACKLIST` (uint64): indexes of the blacklists (bitmap) which blacklisted `SRC_IP`, zero if not blacklisted -For example, when the `DST_BLACKLIST` field contains number 9, it means the DST_IP is present on -blacklists with ID 1 and 4 (in binary: 1001) - -The very rare situation, when both addresses are present on some blacklist, is not handled. There is always just one -non-zero value for `{DST,SRC}_BLACKLIST` (either DST or SRC is blacklisted, not both). - ## Compilation and linking This module requires compilation with `-std=c++11`, because of the usage of *std::vector, streams, etc.*. For linking add `-ltrap -lunirec -lnemea-common` (the module must be compiled as a part of [NEMEA](https://github.com/CESNET/Nemea) repository or using installed libtrap-devel and unirec packages). - -## Example detection -``` -ipaddr DST_IP,ipaddr SRC_IP,uint64 BYTES,uint64 DST_BLACKLIST,uint64 SRC_BLACKLIST,time TIME_FIRST,time TIME_LAST,uint32 PACKETS,uint16 DST_PORT,uint8 PROTOCOL -192.168.1.1,192.168.1.2,123,0,8,2017-08-18T14:16:08.256,2017-08-18T14:16:13.177,3,1433,6 -192.168.1.1,192.168.1.2,41,0,8,2017-08-18T14:16:13.405,2017-08-18T14:16:13.405,1,1433,6 -192.168.1.1,192.168.1.2,404,8,0,2017-08-18T14:16:10.106,2017-08-18T14:16:25.100,8,25,6 -``` diff --git a/blacklistfilter/ipdetect/ipdetect_config.xml b/blacklistfilter/ipdetect/ipdetect_config.xml index 10929a94..f46261f4 100644 --- a/blacklistfilter/ipdetect/ipdetect_config.xml +++ b/blacklistfilter/ipdetect/ipdetect_config.xml @@ -12,8 +12,8 @@ /tmp/blacklistfilter/ip6.blist - true diff --git a/blacklistfilter/urldetect/README.md b/blacklistfilter/urldetect/README.md index e0346861..d2327e2f 100644 --- a/blacklistfilter/urldetect/README.md +++ b/blacklistfilter/urldetect/README.md @@ -1,7 +1,5 @@ # URL blacklistfilter -This module is a part of the blacklistfilter suite. For information about other modules, see the main [README](../README.md) - ## Goal Module receives the UniRec HTTP flow records and checks if the HTTP PATH (`HTTP_HOST` + `HTTP_URL`) is present in any @@ -9,59 +7,29 @@ blacklist that are available. If any of the addresses is blacklisted, the record is changed by adding a number/index of the blacklists that contain this URL. UniRec with this flag is then sent to the output interface. Blacklists are downloaded by a separate module -Blacklist downloader which saves blacklists to a file (specified in configuration) and blacklistfilter uses +`bl_downloader.py` which saves blacklists to a file (specified in configuration) and blacklistfilter uses this file to reload blacklists. ## Input/Output -``` -Input Interface: UniRec format (,) -Output Interface: UniRec format (,,BLACKLIST) -``` +Input Interface: UniRec format (``) + +Output Interface: UniRec format (``, `BLACKLIST`) ## Usage ``` -Usage: urlblacklistfilter -i [-c ] [-b ] +Usage: ./urlblacklistfilter -u -i ``` -## Configuration -Is done via configuration file (command-line options override config file) - -```xml - - - - - - /tmp/blacklistfilter/url.blist - - - - true - - - -``` - -- `blacklist_file`: An URL file created by Blacklist downloader, containing (sorted) entries (FQDNs and URLs) from all blacklists - -- `watch_blacklists`: A flag indicating whether the blacklist file is being reloaded everytime the file changes. When set to false, -the blacklists are loaded only once at the startup of the module +# Blacklist downloader -## Operation +URL blacklistfilter uses blacklist file which is handled by Python downloader (bl_downloader.py). +The downloader periodically checks for new blacklist updates and feeds it to the blacklistfilter +using inotify mechanism. The data are preprocessed by the downloader (sorted, trimmed whitespaces etc.) -- Module reports every single flow with URL present on some blacklist -- If `watch_blacklists` flag is true, the module listens for changes (IN_CLOSE_WRITE events) in the file(s) and reloads -them everytime there is a change -- Detection of the URL is case-insensitive and deals with little nuances in the URLs (such as redundant backslashes). Following -domain names (HTTP_HOST) are treated the same: +See "TODO: downloader README ref" -![URL preprocessing](../doc/url_dns.png) ## Required data @@ -74,14 +42,11 @@ UniRec fields required: - `SRC_IP` (ipaddr): source IP address of the flow - `DST_PORT` (uint16): destination port of the flow - `SRC_PORT` (uint16): source port of the flow -- `PROTOCOL` (uint8): protocol used (TCP, UDP...) -- `PACKETS` (uint32): packets in the flow -- `BYTES` (uint32): bytes in the flow - `TIME_FIRST` (time): time of the first packet in the flow - `TIME_LAST` (time): time of the last packet in the flow -- `HTTP_REQUEST_HOST` (string): HTTP Host header -- `HTTP_REQUEST_REFERER` (string): HTTP Referer header -- `HTTP_REQUEST_URL` (string): HTTP URL +- `HTTP_HOST` (string): HTTP Host header +- `HTTP_REFERER` (string): HTTP Referer header +- `HTTP_URL` (string): HTTP URL ## Output data @@ -90,28 +55,9 @@ Upon detection, the input data are sent to the output, enriched with this value: - `BLACKLIST` (uint64): indexes of the blacklists (bitmap) which blacklisted the URL -For example, when the `BLACKLIST` field contains number 9, it means the URL is present on -blacklists with ID 1 and 4 (in binary: 1001) - ## Compilation and linking This module requires compilation with `-std=c++11`, because of the usage of *std::vector, streams, etc.*. For linking add `-ltrap -lunirec -lnemea-common` (the module must be compiled as a part of [NEMEA](https://github.com/CESNET/Nemea) repository or using installed libtrap-devel and unirec packages). - - -## Example detection -Below is an example output of this detector. IP addresses are made-up. -When dealing with HTTPS, only domain name is visible to the module (through SNI header during TLS handshake), -so only domain names can be blacklisted when using HTTPS. With HTTP it can be either a domain or the entire URL. - -``` -ipaddr DST_IP,ipaddr SRC_IP,uint64 BLACKLIST,uint64 BYTES,time TIME_FIRST,time TIME_LAST,uint32 PACKETS,uint16 DST_PORT,uint16 SRC_PORT,uint8 PROTOCOL,string HTTP_REQUEST_HOST,string HTTP -_REQUEST_REFERER,string HTTP_REQUEST_URL - -192.168.1.1,192.168.1.2,8,3331,2018-09-11T10:16:54.549,2018-09-11T10:18:24.750,19,443,54174,6,"e.mail.ru","","" -192.168.1.1,192.168.1.2,4,450,2018-09-16T23:05:56.197,2018-09-16T23:05:57.481,6,80,48196,6,"112.e-democracy.bg","","/fre/verification/15d0e09cmbmm1b38nm5n/access.php" -192.168.1.1,192.168.1.2,17,446,2018-09-16T23:08:45.119,2018-09-16T23:08:45.837,7,80,48910,6,"029999.com","","/" -192.168.1.1,192.168.1.2,4,465,2018-09-16T23:09:37.086,2018-09-16T23:09:37.662,6,80,56802,6,"ang.angelflightmidatlantic.org","","/~mercymed/wp-content/uploads/2011/image/dhl/dhl/dhl" -``` diff --git a/blacklistfilter/urldetect/urldetect_config.xml b/blacklistfilter/urldetect/urldetect_config.xml index 305d39a2..4bcfc5b5 100644 --- a/blacklistfilter/urldetect/urldetect_config.xml +++ b/blacklistfilter/urldetect/urldetect_config.xml @@ -1,14 +1,15 @@ - + Blacklists must be preprocessed such that IP addresses and prefixes + are sorted (numerically) --> /tmp/blacklistfilter/url.blist - true From 21a04cf60cbe547ee44bffce80fba30da5896193 Mon Sep 17 00:00:00 2001 From: Petr Miculek Date: Thu, 26 Dec 2019 13:40:14 +0100 Subject: [PATCH 40/40] Revert "Changes I did not make" changing void pointers to MatchStructure objects --- brute_force_detector/host.cpp | 49 +++++++-------- brute_force_detector/host.h | 28 ++++----- brute_force_detector/record.cpp | 107 +++++++++++++++----------------- brute_force_detector/record.h | 38 ++++++------ 4 files changed, 108 insertions(+), 114 deletions(-) diff --git a/brute_force_detector/host.cpp b/brute_force_detector/host.cpp index e957fdd1..7e9a1abf 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -47,23 +47,22 @@ // ************************************************************/ // ************************* SSH HOST *************************/ // ************************************************************/ -bool SSHHost::addRecord(SSHRecord *record, void *structure, uint8_t direction) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool SSHHost::addRecord(SSHRecord *record, IRecord::MatchStructure *flow, uint8_t direction) { // ignore port-scans - if (isFlowScan(&st.packets, &st.flags)) { + if (isFlowScan(flow->packets, flow->flags)) { return false; } - else if (st.packets == 1 && st.flags == 0b00010000) // skip ack only packet + else if (flow->packets == 1 && flow->flags == 0b00010000) // skip ack only packet { return false; } - else if (st.packets == 4 && st.flags == 0b00000010) // 4 packet SYN request + else if (flow->packets == 4 && flow->flags == 0b00000010) // 4 packet SYN request { return false; } else { - timeOfLastReceivedRecord = st.lastSeen; + timeOfLastReceivedRecord = flow->lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); } @@ -152,15 +151,14 @@ SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { // ************************************************************/ // ************************* RDP HOST *************************/ // ************************************************************/ -bool RDPHost::addRecord(RDPRecord *record, void *structure, uint8_t direction) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool RDPHost::addRecord(RDPRecord *record, IRecord::MatchStructure *flow, uint8_t direction) { // ignore port-scans - if (isFlowScan(&st.packets, &st.flags)) { + if (isFlowScan(flow->packets, flow->flags)) { return false; } else { - timeOfLastReceivedRecord = st.lastSeen; + timeOfLastReceivedRecord = flow->lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); } @@ -247,15 +245,14 @@ RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { // ************************************************************/ // ************************ TELNET HOST ***********************/ // ************************************************************/ -bool TELNETHost::addRecord(TELNETRecord *record, void *structure, uint8_t direction) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool TELNETHost::addRecord(TELNETRecord *record, IRecord::MatchStructure *flow, uint8_t direction) { // ignore port-scans - if (isFlowScan(&st.packets, &st.flags)) { + if (isFlowScan(flow->packets, flow->flags)) { return false; } else { - timeOfLastReceivedRecord = st.lastSeen; + timeOfLastReceivedRecord = flow->lastSeen; if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); } @@ -340,13 +337,13 @@ TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { // *********************** SSH HOST MAP ***********************/ // ************************************************************/ -SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) { +SSHHost *SSHHostMap::findHost(const IRecord::MatchStructure *const flow, uint8_t direction) { ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { - ip = structure->srcIp; + ip = flow->srcIp; } else { - ip = structure->dstIp; + ip = flow->dstIp; } std::map::iterator it = hostMap.find(ip); @@ -355,7 +352,7 @@ SSHHost *SSHHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct if (it == hostMap.end()) { // not found, create new host - host = new SSHHost(ip, structure->firstSeen); + host = new SSHHost(ip, flow->firstSeen); hostMap.insert(std::pair(ip, host)); } else { @@ -388,13 +385,13 @@ void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { // *********************** RDP HOST MAP ***********************/ // ************************************************************/ -RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) { +RDPHost *RDPHostMap::findHost(const IRecord::MatchStructure *const flow, uint8_t direction) { ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { - ip = structure->srcIp; + ip = flow->srcIp; } else { - ip = structure->dstIp; // attacker is now destination address + ip = flow->dstIp; // attacker is now destination address } std::map::iterator it = hostMap.find(ip); @@ -403,7 +400,7 @@ RDPHost *RDPHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direct if (it == hostMap.end()) { // not found, create new host - host = new RDPHost(ip, structure->firstSeen); + host = new RDPHost(ip, flow->firstSeen); hostMap.insert(std::pair(ip, host)); } else { @@ -437,13 +434,13 @@ void RDPHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) { // ********************** TELNET HOST MAP *********************/ // ************************************************************/ -TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t direction) { +TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *flow, uint8_t direction) { ip_addr_t ip; if (direction == FLOW_INCOMING_DIRECTION) { - ip = structure->srcIp; + ip = flow->srcIp; } else { - ip = structure->dstIp; // attacker is now destination address + ip = flow->dstIp; // attacker is now destination address } std::map::iterator it = hostMap.find(ip); @@ -452,7 +449,7 @@ TELNETHost *TELNETHostMap::findHost(IRecord::MatchStructure *structure, uint8_t if (it == hostMap.end()) { // not found, create new host - host = new TELNETHost(ip, structure->firstSeen); + host = new TELNETHost(ip, flow->firstSeen); hostMap.insert(std::pair(ip, host)); } else { diff --git a/brute_force_detector/host.h b/brute_force_detector/host.h index 8f5e2dfa..a17ff247 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -99,7 +99,7 @@ class IHost { inline bool getHostScannedNetwork() { return scanned; } - virtual bool addRecord(T record, void *structure, uint8_t direction) { + virtual bool addRecord(T record, IRecord::MatchStructure* flow, uint8_t direction) { if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); } @@ -147,13 +147,13 @@ class IHost { recordListOutgoing.clearAllRecords(); } - bool isFlowScan(const uint32_t *packets, const uint8_t *flags) { - if ((*packets == 1 && *flags == 0b00000010) // SYN - || (*packets == 1 && *flags == 0b00010010) // SYN + ACK - || (*packets == 1 && *flags == 0b00010100) // RST + ACK - || (*packets == 2 && *flags == 0b00000010) // SYN - || (*packets == 2 && *flags == 0b00000110) // SYN + RST - || (*packets == 3 && *flags == 0b00000010)) // 3 SYN packets + bool isFlowScan(const uint32_t packets, const uint8_t flags) { + if ((packets == 1 && flags == 0b00000010) // SYN + || (packets == 1 && flags == 0b00010010) // SYN + ACK + || (packets == 1 && flags == 0b00010100) // RST + ACK + || (packets == 2 && flags == 0b00000010) // SYN + || (packets == 2 && flags == 0b00000110) // SYN + RST + || (packets == 3 && flags == 0b00000010)) // 3 SYN packets { scanned = true; return true; @@ -181,7 +181,7 @@ class SSHHost : public IHost { public: SSHHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} - bool addRecord(SSHRecord *record, void *structure, uint8_t direction); + bool addRecord(SSHRecord *record, IRecord::MatchStructure *flow, uint8_t direction); ATTACK_STATE checkForAttack(ur_time_t actualTime); @@ -198,7 +198,7 @@ class RDPHost : public IHost { public: RDPHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} - bool addRecord(RDPRecord *record, void *structure, uint8_t direction); + bool addRecord(RDPRecord *record, IRecord::MatchStructure *flow, uint8_t direction); ATTACK_STATE checkForAttack(ur_time_t actualTime); @@ -214,7 +214,7 @@ class TELNETHost : public IHost { public: TELNETHost(ip_addr_t hostIp, ur_time_t firstSeen) : IHost(hostIp, firstSeen) {} - bool addRecord(TELNETRecord *record, void *structure, uint8_t direction); + bool addRecord(TELNETRecord *record, IRecord::MatchStructure *flow, uint8_t direction); ATTACK_STATE checkForAttack(ur_time_t actualTime); @@ -300,7 +300,7 @@ class SSHHostMap : public IHostMap { return hostMap.size(); } - SSHHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + SSHHost *findHost(const IRecord::MatchStructure *const flow, uint8_t direction = FLOW_INCOMING_DIRECTION); void deleteOldRecordAndHosts(ur_time_t actualTime); @@ -325,7 +325,7 @@ class RDPHostMap : public IHostMap { return hostMap.size(); } - RDPHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + RDPHost *findHost(const IRecord::MatchStructure *const flow, uint8_t direction = FLOW_INCOMING_DIRECTION); void deleteOldRecordAndHosts(ur_time_t actualTime); @@ -351,7 +351,7 @@ class TELNETHostMap : public IHostMap { return hostMap.size(); } - TELNETHost *findHost(IRecord::MatchStructure *structure, uint8_t direction = FLOW_INCOMING_DIRECTION); + TELNETHost *findHost(IRecord::MatchStructure *flow, uint8_t direction = FLOW_INCOMING_DIRECTION); void deleteOldRecordAndHosts(ur_time_t actualTime); diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 8744b749..fdf09112 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -53,25 +53,24 @@ SSHRecord::SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->flowLastSeen = flowLastSeen; } -bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool SSHRecord::matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; - if ((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { + if ((flow->flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { return false; } - if (st.packets > Config::getInstance().getSSHIncMaxPackets() || - st.packets < Config::getInstance().getSSHIncMinPackets()) { + if (flow->packets > Config::getInstance().getSSHIncMaxPackets() || + flow->packets < Config::getInstance().getSSHIncMinPackets()) { return false; } - if (st.bytes > Config::getInstance().getSSHIncMaxBytes() || st.bytes < Config::getInstance().getSSHIncMinBytes()) { + if (flow->bytes > Config::getInstance().getSSHIncMaxBytes() || flow->bytes < Config::getInstance().getSSHIncMinBytes()) { return false; } - if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { + if (wl->isWhitelisted(&flow->srcIp, &flow->dstIp, flow->srcPort, flow->dstPort)) { std::cerr << "w\n"; return false; } @@ -81,23 +80,23 @@ bool SSHRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { return true; } -bool SSHRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool SSHRecord::matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) { - if ((st.flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { + if ((flow->flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { return false; } - if (st.packets > Config::getInstance().getSSHOutMaxPackets() || - st.packets < Config::getInstance().getSSHOutMinPackets()) { + if (flow->packets > Config::getInstance().getSSHOutMaxPackets() + || flow->packets < Config::getInstance().getSSHOutMinPackets()) { return false; } - if (st.bytes > Config::getInstance().getSSHOutMaxBytes() || st.bytes < Config::getInstance().getSSHOutMinBytes()) { + if (flow->bytes > Config::getInstance().getSSHOutMaxBytes() + || flow->bytes < Config::getInstance().getSSHOutMinBytes()) { return false; } - if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (wl->isWhitelisted(&flow->dstIp, &flow->srcIp, flow->dstPort, flow->srcPort)) // NOLINT: swapped src/dst ip and port { return false; } @@ -116,20 +115,19 @@ RDPRecord::RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->flowLastSeen = flowLastSeen; } -bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool RDPRecord::matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; // Win8 manual input - if ((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) { + if ((flow->flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) { // s port, d port, packets, bytes, flags // 42315, 3389, 8, 1691, 30 // 42345, 3389, 9, 1747, 30 - if (st.packets >= 7 && st.packets <= 11 && st.bytes >= 1500 && st.bytes <= 2000) { - if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { + if (flow->packets >= 7 && flow->packets <= 11 && flow->bytes >= 1500 && flow->bytes <= 2000) { + if (wl->isWhitelisted(&flow->srcIp, &flow->dstIp, flow->srcPort, flow->dstPort)) { return false; } signatureMatched = true; @@ -139,12 +137,12 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { // Ncrack/thc hydra to win8 unsuccessful connection - if ((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { + if ((flow->flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { // s port, d port, packets, bytes, flags // 37501, 3389, 3, 165, 26 - if (st.packets == 3 && (st.bytes >= 100 && st.bytes <= 200)) { - if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { + if (flow->packets == 3 && (flow->bytes >= 100 && flow->bytes <= 200)) { + if (wl->isWhitelisted(&flow->srcIp, &flow->dstIp, flow->srcPort, flow->dstPort)) { return false; } signatureMatched = true; @@ -153,19 +151,19 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { } - if ((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { + if ((flow->flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { return false; } - if (st.packets > Config::getInstance().getRDPIncMaxPackets() || - st.packets < Config::getInstance().getRDPIncMinPackets()) { + if (flow->packets > Config::getInstance().getRDPIncMaxPackets() || + flow->packets < Config::getInstance().getRDPIncMinPackets()) { return false; } - if (st.bytes > Config::getInstance().getRDPIncMaxBytes() || st.bytes < Config::getInstance().getRDPIncMinBytes()) { + if (flow->bytes > Config::getInstance().getRDPIncMaxBytes() || flow->bytes < Config::getInstance().getRDPIncMinBytes()) { return false; } - if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { + if (wl->isWhitelisted(&flow->srcIp, &flow->dstIp, flow->srcPort, flow->dstPort)) { return false; } @@ -173,20 +171,19 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { return true; } -bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool RDPRecord::matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; // Win8 manual input - if ((st.flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) { + if ((flow->flags & RDPRecord::signatureFlagsWin8ManualCon) == RDPRecord::signatureFlagsWin8ManualCon) { // s port, d port, packets, bytes, flags // 3389, 42320, 7, 1882, 26 // 3389, 42303, 7, 1951, 26 - if (st.packets == 7 && st.bytes >= 1700 && st.bytes <= 2200) { - if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (flow->packets == 7 && flow->bytes >= 1700 && flow->bytes <= 2200) { + if (wl->isWhitelisted(&flow->dstIp, &flow->srcIp, flow->dstPort, flow->srcPort)) // NOLINT: swapped src/dst ip and port { return false; } @@ -197,12 +194,12 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { // Ncrack/thc hydra to win8 unsuccessful connection - if ((st.flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { + if ((flow->flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { // s port, d port, packets, bytes, flags // 3389, 37639, 2, 92, 22 - if (st.packets == 2 && (st.bytes > 80 && st.bytes < 120)) { - if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (flow->packets == 2 && (flow->bytes > 80 && flow->bytes < 120)) { + if (wl->isWhitelisted(&flow->dstIp, &flow->srcIp, flow->dstPort, flow->srcPort)) // NOLINT: swapped src/dst ip and port { return false; } @@ -211,20 +208,20 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { } } - if ((st.flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { + if ((flow->flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { return false; } - if (st.packets > Config::getInstance().getRDPOutMaxPackets() || - st.packets < Config::getInstance().getRDPOutMinPackets()) { + if (flow->packets > Config::getInstance().getRDPOutMaxPackets() || + flow->packets < Config::getInstance().getRDPOutMinPackets()) { return false; } - if (st.bytes > Config::getInstance().getRDPOutMaxBytes() || st.bytes < Config::getInstance().getRDPOutMinBytes()) { + if (flow->bytes > Config::getInstance().getRDPOutMaxBytes() || flow->bytes < Config::getInstance().getRDPOutMinBytes()) { return false; } - if (wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swapped src/dst ip and port + if (wl->isWhitelisted(&flow->dstIp, &flow->srcIp, flow->dstPort, flow->srcPort)) // NOLINT: swapped src/dst ip and port { return false; } @@ -243,25 +240,24 @@ TELNETRecord::TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen) { this->flowLastSeen = flowLastSeen; } -bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool TELNETRecord::matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; - if ((st.flags & TELNETRecord::signatureFlags) != TELNETRecord::signatureFlags) { + if ((flow->flags & TELNETRecord::signatureFlags) != TELNETRecord::signatureFlags) { return false; } - if (st.packets > Config::getInstance().getTELNETIncMaxPackets() || - st.packets < Config::getInstance().getTELNETIncMinPackets()) { + if (flow->packets > Config::getInstance().getTELNETIncMaxPackets() || + flow->packets < Config::getInstance().getTELNETIncMinPackets()) { return false; } - if (st.bytes > Config::getInstance().getTELNETIncMaxBytes() || - st.bytes < Config::getInstance().getTELNETIncMinBytes()) { + if (flow->bytes > Config::getInstance().getTELNETIncMaxBytes() || + flow->bytes < Config::getInstance().getTELNETIncMinBytes()) { return false; } - if (wl->isWhitelisted(&st.srcIp, &st.dstIp, st.srcPort, st.dstPort)) { + if (wl->isWhitelisted(&flow->srcIp, &flow->dstIp, flow->srcPort, flow->dstPort)) { return false; } @@ -270,29 +266,28 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) { } -bool TELNETRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) { - IRecord::MatchStructure st = *(IRecord::MatchStructure *) (structure); +bool TELNETRecord::matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; - if ((st.flags & TELNETRecord::signatureFlagsFin) != TELNETRecord::signatureFlagsFin) { + if ((flow->flags & TELNETRecord::signatureFlagsFin) != TELNETRecord::signatureFlagsFin) { return false; } - TelnetServerProfile *TSPProfile = TSPMap.findProfile(st.srcIp); + TelnetServerProfile *TSPProfile = TSPMap.findProfile(flow->srcIp); if (TSPProfile == NULL) { - TSPProfile = TSPMap.createProfile(st.srcIp, st.firstSeen); + TSPProfile = TSPMap.createProfile(flow->srcIp, flow->firstSeen); } - TSPProfile->profileWithNewData(st.packets, st.bytes); + TSPProfile->profileWithNewData(flow->packets, flow->bytes); - if (st.packets < TELNET_OUTGOING_MIN_PACKETS) { + if (flow->packets < TELNET_OUTGOING_MIN_PACKETS) { return false; } //for max range only if (TSPProfile->isProfiled()) { - if (st.packets > TSPProfile->getMaxPackets() || st.bytes > TSPProfile->getMaxBytes()) { + if (flow->packets > TSPProfile->getMaxPackets() || flow->bytes > TSPProfile->getMaxBytes()) { return false; } } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index ddcadc9b..c30dc9d8 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -71,18 +71,6 @@ inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTim class IRecord { public: - IRecord() : signatureMatched(false) {} - - virtual ~IRecord() {}; - - virtual bool matchWithIncomingSignature(void *structure, Whitelist *wl) = 0; - - virtual bool matchWithOutgoingSignature(void *structure, Whitelist *wl) = 0; - - inline bool isMatched() { return signatureMatched; } - - virtual ur_time_t getRecordTimeout() = 0; - struct MatchStructure { uint8_t flags; uint32_t packets; @@ -95,6 +83,20 @@ class IRecord { ur_time_t lastSeen; }; + IRecord() : signatureMatched(false) {} + + virtual ~IRecord() {}; + + + virtual bool matchWithIncomingSignature(IRecord::MatchStructure *flow, Whitelist *wl) = 0; + + virtual bool matchWithOutgoingSignature(IRecord::MatchStructure *flow, Whitelist *wl) = 0; + + inline bool isMatched() { return signatureMatched; } + + virtual ur_time_t getRecordTimeout() = 0; + + // May seem unused, actually are passed to reporting functions ip_addr_t dstIp; ur_time_t flowLastSeen; @@ -110,9 +112,9 @@ class SSHRecord : public IRecord { public: SSHRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - bool matchWithIncomingSignature(void *structure, Whitelist *wl) ; + bool matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) ; - bool matchWithOutgoingSignature(void *structure, Whitelist *wl) ; + bool matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) ; ur_time_t getRecordTimeout() { return Config::getInstance().getSSHRecordTimeout(); } @@ -125,9 +127,9 @@ class RDPRecord : public IRecord { public: RDPRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - bool matchWithIncomingSignature(void *structure, Whitelist *wl); + bool matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl); - bool matchWithOutgoingSignature(void *structure, Whitelist *wl); + bool matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl); ur_time_t getRecordTimeout() { return Config::getInstance().getRDPRecordTimeout(); } @@ -142,9 +144,9 @@ class TELNETRecord : public IRecord { public: TELNETRecord(ip_addr_t dstIp, ur_time_t flowLastSeen); - bool matchWithIncomingSignature(void *structure, Whitelist *wl) ; + bool matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) ; - bool matchWithOutgoingSignature(void *structure, Whitelist *wl) ; + bool matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) ; ur_time_t getRecordTimeout() { return Config::getInstance().getTELNETRecordTimeout(); }