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/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/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/README.md b/brute_force_detector/README.md index efc1a1bf..367654b3 100644 --- a/brute_force_detector/README.md +++ b/brute_force_detector/README.md @@ -46,13 +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 5d02022d..fc5264c6 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 @@ -50,14 +50,12 @@ #include #include #include -#include #include #include #include #include -#include #include #include "record.h" @@ -66,9 +64,8 @@ #include "sender.h" #include "brute_force_detector.h" #include "whitelist.h" -#include -#include #include + #ifdef __cplusplus extern "C" { #endif @@ -80,27 +77,26 @@ 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; -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) + 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") \ @@ -111,60 +107,57 @@ 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) -{ - 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()) + else if (signal == SIGUSR2) { + if (!whitelist.isLockedForConfigurationReload()) { whitelist.reloadWhitelist(); - else - alarm(1); //cannot reload now.. wait + } + else { + alarm(1); // cannot reload now.. wait + } } - else if(signal == SIGALRM) - { - if(!whitelist.isLockedForConfigurationReload()) + else if (signal == SIGALRM) { + if (!whitelist.isLockedForConfigurationReload()) { whitelist.reloadWhitelist(); - else - alarm(1); //wait another second + } + else { + alarm(1); // wait another second + } } } -bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t actualTime) -{ - if(oldTime + timer <= actualTime) - return true; - else - return false; -} - -void printFlowPercent(uint64_t b, uint64_t p) -{ - if (b && p && 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; +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()); + + 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) @@ -172,20 +165,20 @@ 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); 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 + // register signal handler sigaction (SIGTERM, &sigAction, NULL); sigaction (SIGINT , &sigAction, NULL); sigaction (SIGUSR1, &sigAction, NULL); @@ -193,7 +186,7 @@ int main(int argc, char **argv) sigaction (SIGALRM, &sigAction, NULL); #else signal(SIGTERM, signalHandler); - signal(SIGINT, signalHandler); + signal(SIGINT, signalHandler); signal(SIGUSR1, signalHandler); signal(SIGUSR2, signalHandler); signal(SIGALRM, signalHandler); @@ -205,59 +198,53 @@ int main(int argc, char **argv) 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) - { - 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; } // ***** Config init ***** - if(configFilePath != NULL) - { + if (configFilePath != NULL) { 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 != NULL) - { + // ***** Whitelist init ***** + if (whitelistFilePath != NULL) { 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; @@ -270,22 +257,21 @@ int main(int argc, char **argv) char *errstr = NULL; ur_template_t *tmplt = ur_create_input_template(0, unirecSpecifier.c_str(), &errstr); if (tmplt == NULL) { - cerr << "Error: Invalid UniRec specifier." << endl; - if(errstr != NULL){ - fprintf(stderr, "%s\n", errstr); - free(errstr); - } - trap_finalize(); - FREE_MODULE_INFO_STRUCT(MODULE_BASIC_INFO, MODULE_PARAMS); - return 4; + cerr << "Error: Invalid UniRec specifier." << endl; + if (errstr != NULL) { + 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; Sender *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); @@ -294,55 +280,33 @@ int main(int argc, char **argv) return 4; } - // ***** Main processing loop ***** - SSHHostMap sshHostMap; - RDPHostMap rdpHostMap; + 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; 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; - 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 - 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"; @@ -350,312 +314,300 @@ 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) { 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; + 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) + 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; + } - // 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; - 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; + // 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, + .firstSeen = ur_get(tmplt, data, F_TIME_FIRST), + .lastSeen = ur_get(tmplt, data, F_TIME_LAST), + }; ret = 0; // *** SSH *** - if(SSH && (dstPort == TCP_SSH_PORT || srcPort == TCP_SSH_PORT)) - { - bool state; + 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(dstIp, flowLastSeen); - state = record->matchWithIncomingSignature(&structure, &whitelist); - if(state) - SSHTotalMatchedIncomingFlows++; - SSHTotalIncomingFlows++; + if (direction == FLOW_INCOMING_DIRECTION) { + record = new SSHRecord(flow.dstIp, flow.lastSeen); + is_matched = record->matchWithIncomingSignature(&flow, &whitelist); + if (is_matched) { + ssh.matchedIncomingFlows++; + } + ssh.incomingFlows++; + } + else { + // FLOW_OUTGOING_DIRECTION + record = new SSHRecord(flow.srcIp, flow.lastSeen); + is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); + if (is_matched) { + ssh.matchedOutgoingFlows++; + } + ssh.outgoingFlows++; } - else - { // FLOW_OUTGOING_DIRECTION - record = new SSHRecord(srcIp, flowLastSeen); - state = record->matchWithOutgoingSignature(&structure, &whitelist); - if(state) - SSHTotalMatchedOutgoingFlows++; - SSHTotalOutgoingFlows++; + + if (is_matched) { + ssh.matchedFlows++; } + ssh.flows++; - if(state) - SSHTotalMatchedFlows++; - SSHTotalFlows++; + // host is the source of current flow/connection + SSHHost *host = sshHostMap.findHost(&flow, direction); - SSHHost *host = sshHostMap.findHost(&structure, direction); + is_portscan = !host->addRecord(record, &flow, direction); - state = host->addRecord(record, &structure, direction); - if(!state) + if (is_portscan) { delete record; - else - { //check for attack - SSHHost::ATTACK_STATE 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 + } + else { + // check for attack + 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.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) - { - //clear list + else if (attackState == SSHHost::END_OF_ATTACK) { + // clear list host->clearAllRecords(); host->setNotReported(); } - else if(attackState == SSHHost::REPORT_END_OF_ATTACK) - { - //report and clear list - ret = sender->continuingReport(host, TCP_SSH_PORT, flowLastSeen, true); + else if (attackState == SSHHost::REPORT_END_OF_ATTACK) { + // report and clear list + ret = sender->continuingReport(host, TCP_SSH_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); } - else if(attackState == SSHHost::ATTACK) - { - ret = sender->continuingReport(host, TCP_SSH_PORT, flowLastSeen); + else if (attackState == SSHHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_SSH_PORT, flow.lastSeen); } } } } // *** RDP *** - if(RDP && (dstPort == TCP_RDP_PORT || srcPort == TCP_RDP_PORT)) - { - bool state; + 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(dstIp, flowLastSeen); - state = record->matchWithIncomingSignature(&structure, &whitelist); - if(state) - RDPTotalMatchedIncomingFlows++; - RDPTotalIncomingFlows++; + if (direction == FLOW_INCOMING_DIRECTION) { + record = new RDPRecord(flow.dstIp, flow.lastSeen); + is_matched = record->matchWithIncomingSignature(&flow, &whitelist); + if (is_matched) { + rdp.matchedIncomingFlows++; + } + rdp.incomingFlows++; } - else - { // FLOW_OUTGOING_DIRECTION - record = new RDPRecord(srcIp, flowLastSeen); - state = record->matchWithOutgoingSignature(&structure, &whitelist); - if(state) - RDPTotalMatchedOutgoingFlows++; - RDPTotalOutgoingFlows++; + else { + // FLOW_OUTGOING_DIRECTION + record = new RDPRecord(flow.srcIp, flow.lastSeen); + is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); + if (is_matched) { + rdp.matchedOutgoingFlows++; + } + rdp.outgoingFlows++; } - if(state) - RDPTotalMatchedFlows++; - RDPTotalFlows++; + if (is_matched) { + rdp.matchedFlows++; + } + rdp.flows++; - RDPHost *host = rdpHostMap.findHost(&structure, direction); + RDPHost *host = rdpHostMap.findHost(&flow, direction); - state = host->addRecord(record, &structure, direction); - if(!state) + is_portscan = !host->addRecord(record, &flow, direction); + if (is_portscan) { delete record; - else - { //check for attack - RDPHost::ATTACK_STATE attackState = host->checkForAttack(flowLastSeen); - if(attackState != RDPHost::NO_ATTACK) - { - if(attackState == RDPHost::NEW_ATTACK) - 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 + } + else { + // check for attack + 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.lastSeen, + Config::getInstance().getRDPFlowThreshold()); } - else if(attackState == RDPHost::END_OF_ATTACK) - { + 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) { host->clearAllRecords(); host->setNotReported(); } - else if(attackState == RDPHost::REPORT_END_OF_ATTACK) - { - //report and clear list - ret = sender->continuingReport(host, TCP_RDP_PORT, flowLastSeen, true); + else if (attackState == RDPHost::REPORT_END_OF_ATTACK) { + // report and clear list + ret = sender->continuingReport(host, TCP_RDP_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); } - else if(attackState == RDPHost::ATTACK) - { - ret = sender->continuingReport(host, TCP_RDP_PORT, flowLastSeen); + else if (attackState == RDPHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_RDP_PORT, flow.lastSeen); } } } } // *** TELNET *** - if(TELNET && (dstPort == TCP_TELNET_PORT || srcPort == TCP_TELNET_PORT)) - { - bool state; + 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(dstIp, flowLastSeen); - state = record->matchWithIncomingSignature(&structure, &whitelist); - if(state) - TELNETTotalMatchedIncomingFlows++; - TELNETTotalIncomingFlows++; + if (direction == FLOW_INCOMING_DIRECTION) { + record = new TELNETRecord(flow.dstIp, flow.lastSeen); + is_matched = record->matchWithIncomingSignature(&flow, &whitelist); + if (is_matched) { + telnet.matchedIncomingFlows++; + } + telnet.incomingFlows++; } - else - { // FLOW_OUTGOING_DIRECTION - record = new TELNETRecord(srcIp, flowLastSeen); - state = record->matchWithOutgoingSignature(&structure, &whitelist); - if(state) - TELNETTotalMatchedOutgoingFlows++; - TELNETTotalOutgoingFlows++; + else { + // FLOW_OUTGOING_DIRECTION + record = new TELNETRecord(flow.srcIp, flow.lastSeen); + is_matched = record->matchWithOutgoingSignature(&flow, &whitelist); + if (is_matched) { + telnet.matchedOutgoingFlows++; + } + telnet.outgoingFlows++; } - if(state) - TELNETTotalMatchedFlows++; - TELNETTotalFlows++; + if (is_matched) { + telnet.matchedFlows++; + } + telnet.flows++; - TELNETHost *host = telnetHostMap.findHost(&structure, direction); + TELNETHost *host = telnetHostMap.findHost(&flow, direction); - state = host->addRecord(record, &structure, direction); - if(!state) + is_portscan = !host->addRecord(record, &flow, direction); + if (is_portscan) { delete record; - else - { //check for attack - TELNETHost::ATTACK_STATE attackState = host->checkForAttack(flowLastSeen); - if(attackState != TELNETHost::NO_ATTACK) - { - if(attackState == TELNETHost::NEW_ATTACK) - 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 + } + else { + // check for attack + 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.lastSeen, + Config::getInstance().getTELNETFlowThreshold()); } - else if(attackState == TELNETHost::END_OF_ATTACK) - { + 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) { host->clearAllRecords(); host->setNotReported(); } - else if(attackState == TELNETHost::REPORT_END_OF_ATTACK) - { - //report and clear list - ret = sender->continuingReport(host, TCP_TELNET_PORT, flowLastSeen, true); + else if (attackState == TELNETHost::REPORT_END_OF_ATTACK) { + // report and clear list + ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.lastSeen, true); host->clearAllRecords(); host->setNotReported(); } - else if(attackState == TELNETHost::ATTACK) - { - ret = sender->continuingReport(host, TCP_TELNET_PORT, flowLastSeen); + else if (attackState == TELNETHost::REPORT_ATTACK) { + ret = sender->continuingReport(host, TCP_TELNET_PORT, flow.lastSeen); } } } } - //check for timeout - if(checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flowLastSeen)) - { - timeOfLastReportCheck = flowLastSeen; - - if(SSH) - sshHostMap.checkForAttackTimeout(flowLastSeen, sender); - if(RDP) - rdpHostMap.checkForAttackTimeout(flowLastSeen, sender); - if(TELNET) - telnetHostMap.checkForAttackTimeout(flowLastSeen, sender); + if (checkForTimeout(timeOfLastReportCheck, timerForReportCheck, flow.lastSeen)) { + timeOfLastReportCheck = flow.lastSeen; + + if (SSH) { + sshHostMap.checkForAttackTimeout(flow.lastSeen, sender); + } + if (RDP) { + rdpHostMap.checkForAttackTimeout(flow.lastSeen, sender); + } + if (TELNET) { + telnetHostMap.checkForAttackTimeout(flow.lastSeen, sender); + } } - if(checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, flowLastSeen)) - { - timeOfLastDeleteCheck = flowLastSeen; - - if(SSH) - sshHostMap.deleteOldRecordAndHosts(flowLastSeen); - if(RDP) - rdpHostMap.deleteOldRecordAndHosts(flowLastSeen); - if(TELNET) - telnetHostMap.deleteOldRecordAndHosts(flowLastSeen); + + if (checkForTimeout(timeOfLastDeleteCheck, timerForDeleteCheck, flow.lastSeen)) { + timeOfLastDeleteCheck = flow.lastSeen; + + if (SSH) { + sshHostMap.deleteOldRecordAndHosts(flow.lastSeen); + } + if (RDP) { + rdpHostMap.deleteOldRecordAndHosts(flow.lastSeen); + } + if (TELNET) { + telnetHostMap.deleteOldRecordAndHosts(flow.lastSeen); + } } - //kontrola po odeslani - TRAP_DEFAULT_SEND_DATA_ERROR_HANDLING(ret, continue, break); + // post-send state check + TRAP_DEFAULT_SEND_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 @@ -47,28 +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; +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 { return '.'; } + // use dot as separator + char do_thousands_sep() const { return '.'; } + + // digits are grouped by 3 digits each + std::string do_grouping() const { return "\3"; } +}; + + +class logInfo { +public: + + explicit logInfo(std::string _protocolName) : protocolName((_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; + } - // digits are grouped by 3 digits each - std::string do_grouping() const { return "\3"; } + 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 e3e43716..7873fff2 100644 --- a/brute_force_detector/config.cpp +++ b/brute_force_detector/config.cpp @@ -43,30 +43,32 @@ */ #include "config.h" +#include 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_ATTACK_MIN_EVENTS_TO_REPORT = 10; GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = 10.0; - GENERAL_IGNORE_FIRST_SEND = 0; + GENERAL_IGNORE_FIRST_SEND = 0; //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_THRESHOLD = 30; - SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(1800, 0); - SSH_HOST_TIMEOUT = ur_time_from_sec_msec(4200, 0); + SSH_MAX_RECORDS = 500; + SSH_FLOW_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_BRUTEFORCE_INC_MIN_PACKETS = 11; 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; @@ -76,17 +78,18 @@ Config::Config() SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(600, 0); //RDP - RDP_LIST_SIZE = 1000; - RDP_LIST_SIZE_BOTTOM_TRESHOLD = 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); + RDP_MAX_RECORDS = 500; + RDP_FLOW_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_BRUTEFORCE_INC_MIN_PACKETS = 20; 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; @@ -97,11 +100,12 @@ Config::Config() RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(600, 0); //TELNET - TELNET_LIST_SIZE = 1000; - TELNET_LIST_SIZE_BOTTOM_TRESHOLD = 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); + TELNET_MAX_RECORDS = 500; + TELNET_FLOW_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_BRUTEFORCE_INC_MIN_PACKETS = 9; TELNET_BRUTEFORCE_INC_MAX_PACKETS = 50; @@ -111,8 +115,7 @@ 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"; @@ -120,100 +123,100 @@ Config::Config() kw_GENERAL_IGNORE_FIRST_SEND = "GENERAL_IGNORE_FIRST_SEND"; //SSH - kw_SSH_LIST_SIZE = "SSH_LIST_SIZE"; - kw_SSH_LIST_THRESHOLD = "SSH_LIST_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"; + 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_THRESHOLD = "RDP_LIST_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"; + 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_THRESHOLD = "TELNET_LIST_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"; + 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(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()) + if (line.empty()) { continue; //skip empty line + } - if(line[0] == '#') + if (line[0] == '#') { continue; //skip comment line + } - size_t pos = line.find("="); // = delimiter - if(pos == std::string::npos) - { + size_t pos = line.find('='); // = delimiter + if (pos == std::string::npos) { cerr << "Error Config: Invalid line \"" << line << "\"" << endl; cerr.flush(); continue; //skip invalid line @@ -226,211 +229,178 @@ 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 - if(keyword.compare(kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + // ********************* + // ****** GENERAL ****** + // ********************* + if (keyword == kw_GENERAL_CHECK_FOR_REPORT_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); GENERAL_CHECK_FOR_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_GENERAL_CHECK_FOR_DELETE_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); GENERAL_CHECK_FOR_DELETE_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) == 0) - { - GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_GENERAL_ATTACK_MIN_EVENTS_TO_REPORT) { + GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) == 0) - { - GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = atof(value.c_str()); + else if (keyword == kw_GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST) { + GENERAL_ATTACK_MIN_RATIO_TO_KEEP_TRACKING_HOST = strtod(value.c_str(), NULL); } - else if(keyword.compare(kw_GENERAL_IGNORE_FIRST_SEND) == 0) - { - GENERAL_IGNORE_FIRST_SEND = strtoul(value.c_str(), NULL, 10); - } - // ********************* - // ******* SSH ********* - // ********************* - else if(keyword.compare(kw_SSH_LIST_SIZE) == 0) - { - SSH_LIST_SIZE = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_GENERAL_IGNORE_FIRST_SEND) { + GENERAL_IGNORE_FIRST_SEND = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_SSH_LIST_THRESHOLD) == 0) - { - SSH_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); + // ********************* + // ******* SSH ********* + // ********************* + else if (keyword == kw_SSH_MAX_RECORDS) { + SSH_MAX_RECORDS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_SSH_ATTACK_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_FLOW_THRESHOLD) { + SSH_FLOW_THRESHOLD = strtoul(value.c_str(), NULL, 0); + } + else if (keyword == kw_SSH_MATCHED_FLOW_RATIO) { + SSH_MATCHED_FLOW_RATIO = strtod(value.c_str(), NULL); + } + else if (keyword == kw_SSH_ATTACK_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); SSH_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_SSH_RECORD_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_RECORD_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); SSH_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_SSH_HOST_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_HOST_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); SSH_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_SSH_REPORT_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_REPORT_TIMEOUT) { + 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.compare(kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) == 0) - { - SSH_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + // SSH INCOMING DIRECTION (ATTACKER -> VICTIM) + else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_PACKETS) { + SSH_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) == 0) - { - SSH_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_PACKETS) { + SSH_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_INC_MIN_BYTES) == 0) - { - SSH_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_BRUTEFORCE_INC_MIN_BYTES) { + SSH_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_INC_MAX_BYTES) == 0) - { - SSH_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_BRUTEFORCE_INC_MAX_BYTES) { + SSH_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } - // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) - else if(keyword.compare(kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) == 0) - { - SSH_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + // SSH OUTGOING DIRECTION (VICTIM -> ATTACKER) + else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_PACKETS) { + SSH_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) == 0) - { - SSH_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_PACKETS) { + SSH_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) == 0) - { - SSH_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_BRUTEFORCE_OUT_MIN_BYTES) { + SSH_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) == 0) - { - SSH_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 10); - } - // ********************* - // ******* RDP ********* - // ********************* - else if(keyword.compare(kw_RDP_LIST_SIZE) == 0) - { - RDP_LIST_SIZE = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_SSH_BRUTEFORCE_OUT_MAX_BYTES) { + SSH_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_RDP_LIST_THRESHOLD) == 0) - { - RDP_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); + // ********************* + // ******* RDP ********* + // ********************* + else if (keyword == kw_RDP_MAX_RECORDS) { + RDP_MAX_RECORDS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_RDP_ATTACK_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_FLOW_THRESHOLD) { + RDP_FLOW_THRESHOLD = strtoul(value.c_str(), NULL, 0); + } + else if (keyword == kw_RDP_MATCHED_FLOW_RATIO) { + RDP_MATCHED_FLOW_RATIO = strtod(value.c_str(), NULL); + } + else if (keyword == kw_RDP_ATTACK_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); RDP_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_RDP_RECORD_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_RECORD_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); RDP_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_RDP_HOST_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_HOST_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); RDP_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_RDP_REPORT_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_REPORT_TIMEOUT) { + 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.compare(kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) == 0) - { - RDP_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + // RDP INCOMING DIRECTION (ATTACKER -> VICTIM) + else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_PACKETS) { + RDP_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) == 0) - { - RDP_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_PACKETS) { + RDP_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_INC_MIN_BYTES) == 0) - { - RDP_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_BRUTEFORCE_INC_MIN_BYTES) { + RDP_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_INC_MAX_BYTES) == 0) - { - RDP_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_BRUTEFORCE_INC_MAX_BYTES) { + RDP_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } - // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) - else if(keyword.compare(kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) == 0) - { - RDP_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + // RDP OUTGOING DIRECTION (VICTIM -> ATTACKER) + else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_PACKETS) { + RDP_BRUTEFORCE_OUT_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) == 0) - { - RDP_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_PACKETS) { + RDP_BRUTEFORCE_OUT_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) == 0) - { - RDP_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_BRUTEFORCE_OUT_MIN_BYTES) { + RDP_BRUTEFORCE_OUT_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) == 0) - { - RDP_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 10); - } - // ********************* - // ****** TELNET ******* - // ********************* - else if(keyword.compare(kw_TELNET_LIST_SIZE) == 0) - { - TELNET_LIST_SIZE = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_RDP_BRUTEFORCE_OUT_MAX_BYTES) { + RDP_BRUTEFORCE_OUT_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_TELNET_LIST_THRESHOLD) == 0) - { - TELNET_LIST_THRESHOLD = strtoul(value.c_str(), NULL, 10); + // ********************* + // ****** TELNET ******* + // ********************* + else if (keyword == kw_TELNET_MAX_RECORDS) { + TELNET_MAX_RECORDS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_TELNET_ATTACK_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_TELNET_FLOW_THRESHOLD) { + TELNET_FLOW_THRESHOLD = strtoul(value.c_str(), NULL, 0); + } + else if (keyword == kw_TELNET_MATCHED_FLOW_RATIO) { + TELNET_MATCHED_FLOW_RATIO = strtod(value.c_str(), NULL); + } + else if (keyword == kw_TELNET_ATTACK_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); TELNET_ATTACK_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_TELNET_RECORD_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_TELNET_RECORD_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); TELNET_RECORD_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_TELNET_HOST_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_TELNET_HOST_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); TELNET_HOST_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_TELNET_REPORT_TIMEOUT) == 0) - { - uint32_t sec = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_TELNET_REPORT_TIMEOUT) { + uint32_t sec = strtoul(value.c_str(), NULL, 0); TELNET_REPORT_TIMEOUT = ur_time_from_sec_msec(sec, 0); } - else if(keyword.compare(kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) == 0) - { - TELNET_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_PACKETS) { + TELNET_BRUTEFORCE_INC_MIN_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) == 0) - { - TELNET_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_PACKETS) { + TELNET_BRUTEFORCE_INC_MAX_PACKETS = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) == 0) - { - TELNET_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_TELNET_BRUTEFORCE_INC_MIN_BYTES) { + TELNET_BRUTEFORCE_INC_MIN_BYTES = strtoul(value.c_str(), NULL, 0); } - else if(keyword.compare(kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) == 0) - { - TELNET_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 10); + else if (keyword == kw_TELNET_BRUTEFORCE_INC_MAX_BYTES) { + TELNET_BRUTEFORCE_INC_MAX_BYTES = strtoul(value.c_str(), NULL, 0); } - // ********************* - // ******* 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 29fff9c5..d3d47ff8 100644 --- a/brute_force_detector/config.h +++ b/brute_force_detector/config.h @@ -56,74 +56,109 @@ 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;} - 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 ur_time_t getGlobalTimerForReportCheck() const { return GENERAL_CHECK_FOR_REPORT_TIMEOUT; } - inline int getGlobalIgnoreFirstSend() const {return GENERAL_IGNORE_FIRST_SEND;} - - //SSH - inline uint16_t getSSHMaxListSize() const {return SSH_LIST_SIZE;} - inline uint16_t getSSHListBottomSize() const {return SSH_LIST_SIZE_BOTTOM_TRESHOLD;} + inline ur_time_t getGlobalTimerForDeleteCheck() const { return GENERAL_CHECK_FOR_DELETE_TIMEOUT; } - 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 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 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;} - - //RDP - inline uint16_t getRDPListBottomSize() const {return RDP_LIST_SIZE_BOTTOM_TRESHOLD;} - 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 getRDPReportTimeout() const {return RDP_REPORT_TIMEOUT;} - inline ur_time_t getRDPAttackTimeout() const {return RDP_ATTACK_TIMEOUT;} + 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; } + + inline ur_time_t getRDPReportTimeout() const { return RDP_REPORT_TIMEOUT; } + + 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;} - - // 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;} - - //TELNET - inline uint16_t getTELNETListBottomSize() const {return TELNET_LIST_SIZE_BOTTOM_TRESHOLD;} - 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 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;} - - 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; } @@ -132,25 +167,28 @@ 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; - + 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; + //SSH - uint16_t SSH_LIST_SIZE; - uint16_t SSH_LIST_THRESHOLD; - uint16_t SSH_LIST_SIZE_BOTTOM_TRESHOLD; + 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_HOST_TIMEOUT; @@ -161,15 +199,16 @@ 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; - std::string kw_SSH_LIST_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; std::string kw_SSH_BRUTEFORCE_INC_MIN_PACKETS; @@ -184,36 +223,11 @@ 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_THRESHOLD; + 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_HOST_TIMEOUT; ur_time_t RDP_REPORT_TIMEOUT; @@ -223,15 +237,16 @@ 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; 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_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; std::string kw_RDP_BRUTEFORCE_INC_MIN_PACKETS; @@ -244,6 +259,37 @@ 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_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; + }; -#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..de871a35 100644 --- a/brute_force_detector/config/config.conf +++ b/brute_force_detector/config/config.conf @@ -8,40 +8,50 @@ ######################## ####### 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 -## Minimum number of suspicious flows to report (continuous detection [not first detection]) +## 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 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 +# GENERAL_ATTACK_MIN_EVENTS_TO_REPORT = 10 +## +## 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 -## Suppress reporting of first detection -## If set, attack scale will have to pass threshold +# 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 +## false positive detections. 0/1 = false/true +# GENERAL_IGNORE_FIRST_SEND = 0 ####################################### -## PROTOCOL X KEYWORDS INFORMATION ## +## PROTOCOL (X) KEYWORDS INFORMATION ## +## X -> SSH/RDP/TELNET +## ## -## X_ATTACK_TIMEOUT - After x seconds from last report set attack by given host +## 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 ## X_LIST_THRESHOLD - Set threshold for number of suspicious flows -## X_REPORT_TIMEOUT - Attacker can be reported again after x seconds. -## During this entire period attack information is agregated. -## X_ATTACK_TIMEOUT > X_REPORT_TIMEOUT +## 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 -## 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) @@ -55,11 +65,13 @@ ######################## ######### SSH ########## ######################## +#SSH_MAX_RECORDS = 500 +#SSH_FLOW_THRESHOLD = 90 +#SSH_MATCHED_FLOW_RATIO = 0.9 #SSH_ATTACK_TIMEOUT = 600 -#SSH_LIST_SIZE = 50 -#SSH_LIST_THRESHOLD = 30 -#SSH_RECORD_TIMEOUT = 1800 -#SSH_HOST_TIMEOUT = 4200 +#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 @@ -68,15 +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_MAX_RECORDS = 500 +#RDP_FLOW_THRESHOLD = 90 +#RDP_MATCHED_FLOW_RATIO = 0.9 #RDP_ATTACK_TIMEOUT = 600 -#RDP_LIST_SIZE = 50 -#RDP_LIST_THRESHOLD = 30 -#RDP_RECORD_TIMEOUT = 1800 -#RDP_HOST_TIMEOUT = 4200 +#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 @@ -85,18 +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_MAX_RECORDS = 500 +#TELNET_FLOW_THRESHOLD = 90 +#TELNET_MATCHED_FLOW_RATIO = 0.9 #TELNET_ATTACK_TIMEOUT = 600 -#TELNET_LIST_SIZE = 50 -#TELNET_LIST_THRESHOLD = 30 -#TELNET_RECORD_TIMEOUT = 1800 -#TELNET_HOST_TIMEOUT = 4200 +#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 version is not supported -#TELNET_REPORT_TIMEOUT = 300 \ No newline at end of file +## Outgoing direction is not supported diff --git a/brute_force_detector/config/whitelist.wl b/brute_force_detector/config/whitelist.wl index b18c5099..75d85a7a 100644 --- a/brute_force_detector/config/whitelist.wl +++ b/brute_force_detector/config/whitelist.wl @@ -13,12 +13,13 @@ # 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 +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 b6981dd8..7e9a1abf 100644 --- a/brute_force_detector/host.cpp +++ b/brute_force_detector/host.cpp @@ -47,133 +47,103 @@ // ************************************************************/ // ************************* 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) { - //scan => SKIP!!! - if(isFlowScan(&st.packets, &st.flags)) + // ignore port-scans + if (isFlowScan(flow->packets, flow->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 + } + else if (flow->packets == 1 && flow->flags == 0b00010000) // skip ack only packet + { return false; - else + } + else if (flow->packets == 4 && flow->flags == 0b00000010) // 4 packet SYN request { - timeOfLastReceivedRecord = st.flowLastSeen; - if(direction == FLOW_INCOMING_DIRECTION) + return false; + } + else { + timeOfLastReceivedRecord = flow->lastSeen; + if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - else + } + else { recordListOutgoing.addRecord(record, isReported()); + } + return true; } } -SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) -{ - uint16_t numOfCurrentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t numOfCurrentOutgoingMF = 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 - if ( actualListSizeInc <= Config::getInstance().getSSHListBottomSize() || - actualListSizeOut <= Config::getInstance().getSSHListBottomSize()) { - - if( numOfCurrentIncomingMF >= Config::getInstance().getSSHListThreshold() || - numOfCurrentOutgoingMF >= Config::getInstance().getSSHListThreshold()) { - - //crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - - return SSHHost::NEW_ATTACK; - } else { - return SSHHost::NO_ATTACK; - } - //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) { - //crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - - return SSHHost::NEW_ATTACK; - } else { - return SSHHost::NO_ATTACK; - } - } +SSHHost::ATTACK_STATE SSHHost::checkForAttack(ur_time_t actualTime) { + uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); + uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); + + if (!isReported()) { + // no attack yet + uint16_t incomingListSize = recordListIncoming.getActualListSize(); + uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); + + 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().getSSHFlowThreshold() && + (topMatchedRatio >= Config::getInstance().getSSHMatchedFlowRatio())) { + // crossed threshold, new attack detected + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); + return SSHHost::REPORT_NEW_ATTACK; + } + else { + return SSHHost::NO_ATTACK; + } } - else - { //host is attacking, check for report timeout - if(!canReportAgain(actualTime)) - //timeout nevyprsel, report pripadne pozdeji - return SSHHost::ATTACK_REPORT_WAIT; - else - { - uint32_t incomingAttackScale = recordListIncoming.getNumOfMatchedFlowsSinceLastReport(); - uint32_t incomingTotalFlows = recordListIncoming.getNumOfTotalFlowsSinceLastReport(); - - uint32_t outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); - - if(numOfCurrentIncomingMF == 0 && incomingAttackScale == 0 && - numOfCurrentOutgoingMF == 0 && outgoingAttackScale == 0) + else // isReported + { + // 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; + } - double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - - double incomingPer = 0.0; - if(incomingTotalFlows > 0.0) - incomingPer = (100.0 / incomingTotalFlows) * incomingAttackScale; - - double outgoingPer = 0.0; - if(outgoingTotalFlows > 0.0) - outgoingPer = (100.0 / outgoingTotalFlows) * outgoingAttackScale; - - if (incomingPer < configRatio && outgoingPer < configRatio) - { - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + 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 + } + else { return SSHHost::END_OF_ATTACK; + } } - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) - return SSHHost::ATTACK; - else + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return SSHHost::REPORT_ATTACK; + } + else { return SSHHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -181,118 +151,93 @@ 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) { - //scan => SKIP!!! - if(isFlowScan(&st.packets, &st.flags)) + // ignore port-scans + if (isFlowScan(flow->packets, flow->flags)) { return false; - else - { - timeOfLastReceivedRecord = st.flowLastSeen; - if(direction == FLOW_INCOMING_DIRECTION) + } + else { + timeOfLastReceivedRecord = flow->lastSeen; + if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - else + } + else { recordListOutgoing.addRecord(record, isReported()); + } return true; } } -RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) -{ - uint16_t numOfCurrentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t numOfCurrentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); - - if(!isReported()) - { //no attack yet - uint16_t actualListSizeInc = recordListIncoming.getActualNumOfListSize(); - uint16_t actualListSizeOut = recordListOutgoing.getActualNumOfListSize(); - - if (actualListSizeInc <= Config::getInstance().getRDPListBottomSize() || - actualListSizeOut <= Config::getInstance().getRDPListBottomSize()) { - - if(numOfCurrentIncomingMF >= Config::getInstance().getRDPListThreshold() || - numOfCurrentOutgoingMF >= 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 { - 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; - } - } +RDPHost::ATTACK_STATE RDPHost::checkForAttack(ur_time_t actualTime) { + uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); + uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); + + if (!isReported()) { + // no attack yet + uint16_t incomingListSize = recordListIncoming.getActualListSize(); + uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); + + 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().getRDPFlowThreshold() && + (topMatchedRatio >= Config::getInstance().getRDPMatchedFlowRatio())) { + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); + + return RDPHost::REPORT_NEW_ATTACK; + } + else { + return RDPHost::NO_ATTACK; + } - if (numOfCurrentIncomingMF >= RDP_LIST_TOP_TRESHOLD || numOfCurrentOutgoingMF >= RDP_LIST_TOP_TRESHOLD) { - //crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return RDPHost::NEW_ATTACK; - } else { - return RDPHost::NO_ATTACK; - } - } } - else - { //host is attacking, check for report timeout - if(!canReportAgain(actualTime)) - //timeout nevyprsel, report pripadne pozdeji + else // isReported + { + // 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 outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); - - if(numOfCurrentIncomingMF == 0 && incomingAttackScale == 0 && - numOfCurrentOutgoingMF == 0 && outgoingAttackScale == 0) + } + 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 RDPHost::END_OF_ATTACK; + } + + double keepTrackingHostRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - - double incomingPer = 0.0; - if(incomingTotalFlows > 0.0) - incomingPer = (100.0 / incomingTotalFlows) * incomingAttackScale; - - double outgoingPer = 0.0; - if(outgoingTotalFlows > 0.0) - outgoingPer = (100.0 / outgoingTotalFlows) * outgoingAttackScale; - - if (incomingPer < configRatio && outgoingPer < configRatio) - { - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + // 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 RDPHost::REPORT_END_OF_ATTACK; - else + } + else { return RDPHost::END_OF_ATTACK; + } } - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) - return RDPHost::ATTACK; - else + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return RDPHost::REPORT_ATTACK; + } + else { return RDPHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -300,117 +245,90 @@ 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) { - //scan => SKIP!!! - if(isFlowScan(&st.packets, &st.flags)) + // ignore port-scans + if (isFlowScan(flow->packets, flow->flags)) { return false; - else - { - timeOfLastReceivedRecord = st.flowLastSeen; - if(direction == FLOW_INCOMING_DIRECTION) + } + else { + timeOfLastReceivedRecord = flow->lastSeen; + if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - else + } + else { recordListOutgoing.addRecord(record, isReported()); + } return true; } } -TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) -{ - uint16_t numOfCurrentIncomingMF = recordListIncoming.getActualNumOfMatchedFlows(); - uint16_t numOfCurrentOutgoingMF = recordListOutgoing.getActualNumOfMatchedFlows(); - - if(!isReported()) - { //no attack yet - uint16_t actualListSizeInc = recordListIncoming.getActualNumOfListSize(); - uint16_t actualListSizeOut = recordListOutgoing.getActualNumOfListSize(); - - if (actualListSizeInc <= Config::getInstance().getTELNETListBottomSize() || - actualListSizeOut <= Config::getInstance().getTELNETListBottomSize()) { - - if(numOfCurrentIncomingMF >= Config::getInstance().getTELNETListThreshold() || - numOfCurrentOutgoingMF >= Config::getInstance().getTELNETListThreshold()) { - //crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return TELNETHost::NEW_ATTACK; - } else { - return TELNETHost::NO_ATTACK; - } - //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; - } - } +TELNETHost::ATTACK_STATE TELNETHost::checkForAttack(ur_time_t actualTime) { + uint16_t incomingMatched = recordListIncoming.getActualMatchedFlows(); + uint16_t outgoingMatched = recordListOutgoing.getActualMatchedFlows(); - if(numOfCurrentIncomingMF >= TELNET_LIST_TOP_TRESHOLD || numOfCurrentOutgoingMF >= TELNET_LIST_TOP_TRESHOLD) { - //crossed threshold, new attack detected - recordListIncoming.initTotalTargetsSet(); - recordListOutgoing.initTotalTargetsSet(); - return TELNETHost::NEW_ATTACK; - } else { - return TELNETHost::NO_ATTACK; - } - } + if (!isReported()) { + uint16_t incomingListSize = recordListIncoming.getActualListSize(); + uint16_t outgoingListSize = recordListOutgoing.getActualListSize(); + + 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().getTELNETFlowThreshold() && + (topMatchedRatio >= Config::getInstance().getTELNETMatchedFlowRatio())) { + recordListIncoming.initTotalTargetsSet(); + recordListOutgoing.initTotalTargetsSet(); + + return TELNETHost::REPORT_NEW_ATTACK; + } + else { + return TELNETHost::NO_ATTACK; + } } - else - { //host is attacking, check for report timeout - if(!canReportAgain(actualTime)) - //timeout nevyprsel, report pripadne pozdeji + else // isReported + { + // host is attacking, wait for timeout to report again + if (!canReportAgain(actualTime)) { return TELNETHost::ATTACK_REPORT_WAIT; - else - { - uint32_t incomingAttackScale = recordListIncoming.getNumOfMatchedFlowsSinceLastReport(); - uint32_t incomingTotalFlows = recordListIncoming.getNumOfTotalFlowsSinceLastReport(); - - uint32_t outgoingAttackScale = recordListOutgoing.getNumOfMatchedFlowsSinceLastReport(); - uint32_t outgoingTotalFlows = recordListOutgoing.getNumOfTotalFlowsSinceLastReport(); - - if(numOfCurrentIncomingMF == 0 && incomingAttackScale == 0 && - numOfCurrentOutgoingMF == 0 && outgoingAttackScale == 0) + } + 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 TELNETHost::END_OF_ATTACK; + } - double configRatio = Config::getInstance().getGlobalAttackMinRatioToKeepTrackingHost(); - - double incomingPer = 0.0; - if(incomingTotalFlows > 0.0) - incomingPer = (100.0 / incomingTotalFlows) * incomingAttackScale; - - double outgoingPer = 0.0; - if(outgoingTotalFlows > 0.0) - outgoingPer = (100.0 / outgoingTotalFlows) * outgoingAttackScale; - - if (incomingPer < configRatio && outgoingPer < configRatio) - { - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) + 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 + } + else { return TELNETHost::END_OF_ATTACK; + } } - if(incomingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport() || - outgoingAttackScale >= Config::getInstance().getGlobalAttackMinEvToReport()) - return TELNETHost::ATTACK; - else + if (std::max(incomingMatchedNew, outgoingMatchedNew) >= + Config::getInstance().getGlobalAttackMinEvToReport()) { + return TELNETHost::REPORT_ATTACK; + } + else { return TELNETHost::ATTACK_MIN_EVENTS_WAIT; + } } } } @@ -419,39 +337,38 @@ 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; - else - ip = structure->dstIp; //attacker is now destination address + if (direction == FLOW_INCOMING_DIRECTION) { + ip = flow->srcIp; + } + else { + ip = flow->dstIp; + } std::map::iterator it = hostMap.find(ip); SSHHost *host; - if(it == hostMap.end()) - { //not found, create new host - host = new SSHHost(ip, structure->flowFirstSeen); - hostMap.insert(std::pair(ip, host)); + if (it == hostMap.end()) { + // not found, create new host + host = new SSHHost(ip, flow->firstSeen); + hostMap.insert(std::pair(ip, host)); } - else + else { host = it->second; + } return host; } -void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) -{ - for (std::map::iterator it = hostMap.begin(); it != hostMap.end(); it++) - { +void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { + 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()->getNumOfMatchedFlowsSinceLastReport(); - if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) - { + 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); } host->setNotReported(); @@ -460,48 +377,47 @@ void SSHHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) } } -void SSHHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) -{ - IHostMap::clearOldRecAHost(&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(const IRecord::MatchStructure *const flow, 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 = flow->srcIp; + } + else { + ip = flow->dstIp; // attacker is now destination address + } + std::map::iterator it = hostMap.find(ip); RDPHost *host; - if (it == hostMap.end()) - { //not found, create new host - host = new RDPHost(ip, structure->flowFirstSeen); - hostMap.insert(std::pair(ip, host)); + if (it == hostMap.end()) { + // not found, create new host + host = new RDPHost(ip, flow->firstSeen); + hostMap.insert(std::pair(ip, host)); } - else + else { host = it->second; + } return host; } -void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) -{ +void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { 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()->getNumOfMatchedFlowsSinceLastReport(); - if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) - { + 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); } host->setNotReported(); @@ -510,57 +426,56 @@ void RDPHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) } } -void RDPHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) -{ - IHostMap::clearOldRecAHost(&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 *flow, 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 = flow->srcIp; + } + else { + ip = flow->dstIp; // attacker is now destination address + } std::map::iterator it = hostMap.find(ip); TELNETHost *host; - if(it == hostMap.end()) - { //not found, create new host - host = new TELNETHost(ip, structure->flowFirstSeen); - hostMap.insert(std::pair(ip, host)); + if (it == hostMap.end()) { + // not found, create new host + host = new TELNETHost(ip, flow->firstSeen); + hostMap.insert(std::pair(ip, host)); } - else + else { host = it->second; + } return host; } -void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) -{ +void TELNETHostMap::checkForAttackTimeout(ur_time_t actualTime, Sender *sender) { 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()->getNumOfMatchedFlowsSinceLastReport(); - if(numOfEvents >= Config::getInstance().getGlobalAttackMinEvToReport()) - { + 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(); } } } -void TELNETHostMap::deleteOldRecordAndHosts(ur_time_t actualTime) -{ - IHostMap::clearOldRecAHost(&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 00148ac6..a17ff247 100644 --- a/brute_force_detector/host.h +++ b/brute_force_detector/host.h @@ -55,15 +55,15 @@ #include #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; @@ -71,152 +71,159 @@ class IHost { scanned = false; } - virtual ~IHost() {} + virtual ~IHost() {}; - 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, + 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() { 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() - { + + inline void setNotReported() { + recordListIncoming.clearTotalTargetsSinceAttack(); + recordListOutgoing.clearTotalTargetsSinceAttack(); timeOfLastReport = 0; - recordListIncoming.clearNumOfTotalTargetsSinceAttack(); - recordListOutgoing.clearNumOfTotalTargetsSinceAttack(); } - + inline bool getHostScannedNetwork() { return scanned; } - virtual bool addRecord(T record, void *structure, uint8_t direction = FLOW_INCOMING_DIRECTION) - { - if(direction == FLOW_INCOMING_DIRECTION) + virtual bool addRecord(T record, IRecord::MatchStructure* flow, uint8_t direction) { + if (direction == FLOW_INCOMING_DIRECTION) { recordListIncoming.addRecord(record, isReported()); - else + } + else { 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 bool canDeleteHost(ur_time_t actualTime) - { - /* - 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; - */ + 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) { ur_time_t timer = getHostDeleteTimeout(); - //return checkForTimeout(timeOfLastRecord, timer, actualTime); return checkForTimeout(timeOfLastReceivedRecord, timer, actualTime); - } 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(uint32_t *packets, 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 + 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 + else { return false; + } } protected: - bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) - { - if(flowTime + timer <= actualTime) - return true; - else - return false; - } bool scanned; ip_addr_t hostIp; - ur_time_t firstSeen; + ur_time_t firstSeen; // TODO unused 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; }; -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, IRecord::MatchStructure *flow, uint8_t direction); + + ATTACK_STATE checkForAttack(ur_time_t actualTime); + + ur_time_t getHostDeleteTimeout() { return Config::getInstance().getSSHHostDeleteTimeout(); } - 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(); } + ur_time_t getHostReportTimeout() { return Config::getInstance().getSSHReportTimeout(); } + + ur_time_t getHostAttackTimeout() { 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, IRecord::MatchStructure *flow, uint8_t direction); + + ATTACK_STATE checkForAttack(ur_time_t actualTime); - 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(); } + ur_time_t getHostDeleteTimeout() { return Config::getInstance().getRDPHostDeleteTimeout(); } + + ur_time_t getHostReportTimeout() { return Config::getInstance().getRDPReportTimeout(); } + + ur_time_t getHostAttackTimeout() { 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) {} - 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, IRecord::MatchStructure *flow, uint8_t direction); + ATTACK_STATE checkForAttack(ur_time_t actualTime); + + ur_time_t getHostDeleteTimeout() { return Config::getInstance().getTELNETHostDeleteTimeout(); } + + ur_time_t getHostReportTimeout() { return Config::getInstance().getTELNETReportTimeout(); } + + ur_time_t getHostAttackTimeout() { return Config::getInstance().getTELNETAttackTimeout(); } +}; ////////////////////////////////////////////////////////////////////////////////////// /************************************************************************************/ @@ -225,47 +232,55 @@ class TELNETHost : public IHost { class IHostMap { public: - IHostMap() {} - ~IHostMap() {} + IHostMap() {}; + + ~IHostMap() {}; + + virtual void clear() = 0; + + virtual inline uint16_t size() = 0; - virtual void clear() = 0; - virtual inline uint16_t size() = 0; + virtual void deleteOldRecordAndHosts(ur_time_t actualTime) = 0; - virtual void deleteOldRecordAndHosts(ur_time_t actualTime) = 0; - virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) = 0; + virtual void checkForAttackTimeout(ur_time_t actualTime, Sender *sender) = 0; protected: template - void clearMap(Container *c) - { + void clearMap(Container *c) { typename Container::iterator it = c->begin(); - while(it != c->end()) - { - if(it->second) - delete it->second; - it++; + while (it != c->end()) { + delete it->second; + it++; } c->clear(); } + /** + * @brief clear old hostMap records and old hosts + * + * @tparam Container + * @param c + * @param actualTime + */ 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()) - { + // iterating over map (or RDPHost* or TELNETHost*) + + 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 + else { it++; + } } } }; @@ -273,73 +288,77 @@ class IHostMap { class SSHHostMap : public IHostMap { public: - SSHHostMap() {} - ~SSHHostMap() {} + SSHHostMap() {}; + + ~SSHHostMap() {}; - virtual void clear() - { + void clear() { IHostMap::clearMap(&hostMap); } - virtual inline uint16_t size() - { + + inline uint16_t size() { 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); + SSHHost *findHost(const IRecord::MatchStructure *const flow, uint8_t direction = FLOW_INCOMING_DIRECTION); + + void deleteOldRecordAndHosts(ur_time_t actualTime); + + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); private: - map hostMap; + map hostMap; }; -class RDPHostMap: public IHostMap { +class RDPHostMap : public IHostMap { public: - RDPHostMap() {} - ~RDPHostMap() {} + RDPHostMap() {}; + + ~RDPHostMap() {}; - virtual void clear() - { + void clear() { IHostMap::clearMap(&hostMap); } - - virtual inline uint16_t size() - { + + inline uint16_t size() { 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); + RDPHost *findHost(const IRecord::MatchStructure *const flow, uint8_t direction = FLOW_INCOMING_DIRECTION); + + void deleteOldRecordAndHosts(ur_time_t actualTime); + + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); private: - map hostMap; + map hostMap; }; -class TELNETHostMap: public IHostMap { +class TELNETHostMap : public IHostMap { public: - TELNETHostMap() {} - ~TELNETHostMap() {} + TELNETHostMap() {}; + + ~TELNETHostMap() {}; - virtual void clear() - { + void clear() { IHostMap::clearMap(&hostMap); } - - virtual inline uint16_t size() - { + + inline uint16_t size() { 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); + TELNETHost *findHost(IRecord::MatchStructure *flow, uint8_t direction = FLOW_INCOMING_DIRECTION); + + void deleteOldRecordAndHosts(ur_time_t actualTime); + + void checkForAttackTimeout(ur_time_t actualTime, Sender *sender); private: - map hostMap; + map hostMap; }; -#endif +#endif // HOST_H diff --git a/brute_force_detector/record.cpp b/brute_force_detector/record.cpp index 2388327a..fdf09112 100644 --- a/brute_force_detector/record.cpp +++ b/brute_force_detector/record.cpp @@ -48,58 +48,55 @@ // ************************ 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); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; - - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set +bool SSHRecord::matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; - if((flags & signatureFlags) != signatureFlags) + if ((flow->flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { return false; + } - if(packets > Config::getInstance().getSSHBFIncMaxPackets() || packets < Config::getInstance().getSSHBFIncMinPackets()) + if (flow->packets > Config::getInstance().getSSHIncMaxPackets() || + flow->packets < Config::getInstance().getSSHIncMinPackets()) { return false; - if(bytes > Config::getInstance().getSSHBFIncMaxBytes() || bytes < Config::getInstance().getSSHBFIncMinBytes()) + } + + 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; } + signatureMatched = true; return true; } -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; +bool SSHRecord::matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) { - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set - - if((flags & signatureFlags) != signatureFlags) + if ((flow->flags & SSHRecord::signatureFlags) != SSHRecord::signatureFlags) { return false; - - if(packets > Config::getInstance().getSSHBFOutMaxPackets() || packets < Config::getInstance().getSSHBFOutMinPackets()) + } + + if (flow->packets > Config::getInstance().getSSHOutMaxPackets() + || flow->packets < Config::getInstance().getSSHOutMinPackets()) { return false; - if(bytes > Config::getInstance().getSSHBFOutMaxBytes() || bytes < Config::getInstance().getSSHBFOutMinBytes()) + } + + if (flow->bytes > Config::getInstance().getSSHOutMaxBytes() + || flow->bytes < Config::getInstance().getSSHOutMinBytes()) { return false; + } - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swap src/dst ip/port + if (wl->isWhitelisted(&flow->dstIp, &flow->srcIp, flow->dstPort, flow->srcPort)) // NOLINT: swapped src/dst ip and port { return false; } @@ -113,47 +110,39 @@ 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); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; +bool RDPRecord::matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; - - //win8 manual input - uint8_t signatureFlagsWin8ManualCon = 0b00011110; //SYN + ACK + PSH + RST - if((flags & signatureFlagsWin8ManualCon) == signatureFlagsWin8ManualCon) - { // s port, d port, packets, bytes, flags + + // Win8 manual input + + 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(packets >= 7 && packets <= 11 && bytes >= 1500 && 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; - return true; + return true; } - } - - //Ncrack/thc hydra to win8 unsuccessful connection - uint8_t signatureFlagsWin8FailedCon = 0b00011010; //SYN + ACK + PSH - if((flags & signatureFlagsWin8FailedCon) == signatureFlagsWin8FailedCon) - { // s port, d port, packets, bytes, flags + } + + // Ncrack/thc hydra to win8 unsuccessful connection + + if ((flow->flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { + // s port, d port, packets, bytes, flags // 37501, 3389, 3, 165, 26 - if(packets == 3 && ( bytes >= 100 && 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; @@ -161,18 +150,20 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) } } - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH - if((flags & signatureFlags) != signatureFlags) + if ((flow->flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { return false; + } - if(packets > Config::getInstance().getRDPBFIncMaxPackets() || packets < Config::getInstance().getRDPBFIncMinPackets()) + if (flow->packets > Config::getInstance().getRDPIncMaxPackets() || + flow->packets < Config::getInstance().getRDPIncMinPackets()) { return false; - if(bytes > Config::getInstance().getRDPBFIncMaxBytes() || bytes < Config::getInstance().getRDPBFIncMinBytes()) + } + 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; } @@ -180,40 +171,35 @@ bool RDPRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return true; } -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; - +bool RDPRecord::matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) { + signatureMatched = false; - - //win8 manual input - uint8_t signatureFlagsWin8ManualCon = 0b00011010; //SYN + ACK + PSH - if((flags & signatureFlagsWin8ManualCon) == signatureFlagsWin8ManualCon) - { // s port, d port, packets, bytes, flags + + // Win8 manual input + + 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(packets == 7 && bytes >= 1700 && bytes <= 2200) - { - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swap src/dst ip/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; } signatureMatched = true; return true; } - } - - //Ncrack/thc hydra to win8 unsuccessful connection - uint8_t signatureFlagsWin8FailedCon = 0b00011010; //SYN + ACK + RST - if((flags & signatureFlagsWin8FailedCon) == signatureFlagsWin8FailedCon) - { // s port, d port, packets, bytes, flags + } + + // Ncrack/thc hydra to win8 unsuccessful connection + + if ((flow->flags & RDPRecord::signatureFlagsWin8FailedCon) == RDPRecord::signatureFlagsWin8FailedCon) { + // s port, d port, packets, bytes, flags // 3389, 37639, 2, 92, 22 - if(packets == 2 && ( bytes > 80 && bytes < 120)) - { - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swap src/dst ip/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; } @@ -221,24 +207,27 @@ bool RDPRecord::matchWithOutgoingSignature(void *structure, Whitelist *wl) return true; } } - - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH + RST - if((flags & signatureFlags) != signatureFlags) + + if ((flow->flags & RDPRecord::signatureFlags) != RDPRecord::signatureFlags) { return false; - - if(packets > Config::getInstance().getRDPBFOutMaxPackets() || packets < Config::getInstance().getRDPBFOutMinPackets()) + } + + if (flow->packets > Config::getInstance().getRDPOutMaxPackets() || + flow->packets < Config::getInstance().getRDPOutMinPackets()) { return false; - if(bytes > Config::getInstance().getRDPBFOutMaxBytes() || bytes < Config::getInstance().getRDPBFOutMinBytes()) + } + if (flow->bytes > Config::getInstance().getRDPOutMaxBytes() || flow->bytes < Config::getInstance().getRDPOutMinBytes()) { return false; - - - if(wl->isWhitelisted(&st.dstIp, &st.srcIp, st.dstPort, st.srcPort)) //swap src/dst ip/port + } + + + if (wl->isWhitelisted(&flow->dstIp, &flow->srcIp, flow->dstPort, flow->srcPort)) // NOLINT: swapped src/dst ip and port { return false; } signatureMatched = true; - return true; + return true; } @@ -246,33 +235,29 @@ 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); - uint32_t packets = st.packets; - uint64_t bytes = st.bytes; - uint8_t flags = st.flags; - - uint8_t signatureFlags = 0b00011010; //SYN + ACK + PSH set +bool TELNETRecord::matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; - if((flags & signatureFlags) != signatureFlags) + if ((flow->flags & TELNETRecord::signatureFlags) != TELNETRecord::signatureFlags) { return false; + } - if(packets > Config::getInstance().getTELNETBFIncMaxPackets() || packets < Config::getInstance().getTELNETBFIncMinPackets()) + if (flow->packets > Config::getInstance().getTELNETIncMaxPackets() || + flow->packets < Config::getInstance().getTELNETIncMinPackets()) { + return false; + } + if (flow->bytes > Config::getInstance().getTELNETIncMaxBytes() || + flow->bytes < Config::getInstance().getTELNETIncMinBytes()) { return false; - if(bytes > Config::getInstance().getTELNETBFIncMaxBytes() || bytes < Config::getInstance().getTELNETBFIncMinBytes()) - 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; } @@ -280,40 +265,38 @@ bool TELNETRecord::matchWithIncomingSignature(void *structure, Whitelist *wl) return true; } -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 + +bool TELNETRecord::matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) { signatureMatched = false; - if((flags & signatureFlags) != signatureFlags) + if ((flow->flags & TELNETRecord::signatureFlagsFin) != TELNETRecord::signatureFlagsFin) { return false; - - TelnetServerProfile * TSPProfile = TSPMap.findProfile(st.srcIp); - if(TSPProfile == NULL) - TSPProfile = TSPMap.createProfile(st.srcIp, st.flowFirstSeen); - - TSPProfile->profileWithNewData(packets, bytes); - - if(packets < 6) + } + + TelnetServerProfile *TSPProfile = TSPMap.findProfile(flow->srcIp); + if (TSPProfile == NULL) { + TSPProfile = TSPMap.createProfile(flow->srcIp, flow->firstSeen); + } + + TSPProfile->profileWithNewData(flow->packets, flow->bytes); + + if (flow->packets < TELNET_OUTGOING_MIN_PACKETS) { return false; - + } + //for max range only - if(TSPProfile->isProfiled()) - { - if(packets > TSPProfile->getMaxPackets() || bytes > TSPProfile->getMaxBytes()) + if (TSPProfile->isProfiled()) { + if (flow->packets > TSPProfile->getMaxPackets() || flow->bytes > TSPProfile->getMaxBytes()) { return false; + } } - else + else { return false; - + } + signatureMatched = true; - return true; + return true; } diff --git a/brute_force_detector/record.h b/brute_force_detector/record.h index 6cce7376..c30dc9d8 100644 --- a/brute_force_detector/record.h +++ b/brute_force_detector/record.h @@ -46,39 +46,32 @@ #define RECORD_H #include -//class TelnetServerProfileMap; -#include "telnet_server_profile.h" - -#include //ip_addr_t -#include //ur_time_t #include #include +#include +#include + +#include +#include // ip_addr_t +#include // ur_time_t #include "brute_force_detector.h" #include "whitelist.h" -#include -#include -#include #include "config.h" -//If we don't have a lot of memory use hash -//#define USE_HASH +// class TelnetServerProfileMap +#include "telnet_server_profile.h" + +inline bool checkForTimeout(ur_time_t oldTime, ur_time_t timer, ur_time_t newTime) { + return oldTime + timer <= newTime; +} /** * Interface for record */ 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 - { +public: + struct MatchStructure { uint8_t flags; uint32_t packets; uint64_t bytes; @@ -86,48 +79,79 @@ 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; }; + 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; + + protected: bool signatureMatched; }; + 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(); } - - ip_addr_t dstIp; - ur_time_t flowLastSeen; + + bool matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) ; + + bool matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) ; + + ur_time_t getRecordTimeout() { return Config::getInstance().getSSHRecordTimeout(); } + + const static uint8_t signatureFlags = 0b00011010; // SYN + ACK + PSH }; + 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(); } - ip_addr_t dstIp; - ur_time_t flowLastSeen; + bool matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl); + + bool matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl); + + 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 + const static uint8_t signatureFlagsWin8FailedCon = 0b00011010; // SYN + ACK + PSH }; + 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(); } - ip_addr_t dstIp; - ur_time_t flowLastSeen; + bool matchWithIncomingSignature(MatchStructure *flow, Whitelist *wl) ; + + bool matchWithOutgoingSignature(MatchStructure *flow, Whitelist *wl) ; + + 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 private: static TelnetServerProfileMap TSPMap; @@ -138,165 +162,165 @@ 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 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 getNumOfTargetsSinceLastReport() { return hashedDstIPSet.size(); } - inline void clearNumOfTargetsSinceLastReport() { hashedDstIPSet.clear(); } + 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 uint16_t getNumOfCurrentTargets(); + 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 unused + + inline uint32_t getTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } + + inline void clearTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } - inline uint32_t getNumOfTotalTargetsSinceAttack() { return hashedDstTotalIPSet.size(); } - inline void clearNumOfTotalTargetsSinceAttack() { hashedDstTotalIPSet.clear(); } inline void initTotalTargetsSet(); + std::vector getIpsOfVictims(); private: - std::list list; + std::list list; // In derived classes implemented like list, stores flow records uint16_t maxListSize; uint16_t actualListSize; - uint16_t actualListMatchedFlows; + uint16_t actualMatchedFlows; uint32_t matchedFlowsSinceLastReport; uint32_t totalFlowsSinceLastReport; - + 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; - char str[46]; - - bool checkForTimeout(ur_time_t flowTime, ur_time_t timer, ur_time_t actualTime) - { - if(flowTime + timer <= actualTime) - return true; - else - return false; - } + char victimIP[46]; }; -template -RecordList::RecordList() -{ +template +RecordList::RecordList() { actualListSize = 0; - actualListMatchedFlows = 0; - flowCounter = 0; - flowMatchedCounter = 0; + actualMatchedFlows = 0; matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 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 - { - std::cerr<<"Error record.h: Max list size for class "< -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; } actualListSize = 0; - actualListMatchedFlows = 0; + actualMatchedFlows = 0; + flowCounter = 0; flowMatchedCounter = 0; matchedFlowsSinceLastReport = 0; totalFlowsSinceLastReport = 0; - - clearNumOfTargetsSinceLastReport(); } - -template -void RecordList::addRecord(T record, bool isHostReported) -{ - flowCounter++; +template +void RecordList::addRecord(T record, bool isHostReported) { actualListSize++; - if(actualListSize > maxListSize) - { //list is full - //delete first record - if((*list.begin())->isMatched()) - actualListMatchedFlows--; + flowCounter++; + + if (actualListSize > maxListSize) { + // list is full + // delete first record + + if ((*list.begin())->isMatched()) { + actualMatchedFlows--; + } T recToDelete = list.front(); delete recToDelete; + list.pop_front(); actualListSize--; } - - if(record->isMatched()) - { + + if (record->isMatched()) { + actualMatchedFlows++; flowMatchedCounter++; - actualListMatchedFlows++; } - - if(isHostReported) - { + + if (isHostReported) { totalFlowsSinceLastReport++; - if(record->isMatched()) - { + if (record->isMatched()) { matchedFlowsSinceLastReport++; - - hashedDstIPSet.insert(record->dstIp); + + hashedDstIPSet.insert(record->dstIp); hashedDstTotalIPSet.insert(record->dstIp); } } - - list.push_back(record); //finally push record to a list + 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) - { - //delete first record + if (currentMaxSize > newMaxListSize) { + while (actualListSize > newMaxListSize) { + // delete first record T recToDelete = list.front(); - if (recToDelete->isMatched()) - actualListMatchedFlows--; + if (recToDelete->isMatched()) { + actualMatchedFlows--; + } delete recToDelete; list.pop_front(); @@ -306,25 +330,29 @@ void RecordList::setNewMaxListSize(uint16_t newMaxListSize) maxListSize = newMaxListSize; } -template -void RecordList::clearOldRecords(ur_time_t actualTime) -{ - if(list.empty()) +/** + * @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; + } 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()) - { - actualListMatchedFlows--; + + if (checkForTimeout(flowTime, timer, actualTime)) { + if ((*it)->isMatched()) { + actualMatchedFlows--; } actualListSize--; @@ -332,62 +360,54 @@ void RecordList::clearOldRecords(ur_time_t actualTime) delete *it; list.erase(it++); } - else + else { break; + } } } -template -ur_time_t RecordList::getTimeOfLastRecord() -{ - if(!list.empty()) +template +ur_time_t RecordList::getTimeOfLastRecord() { + if (!list.empty()) { return list.back()->flowLastSeen; - else + } + else { return 0; + } } template -uint16_t RecordList::getNumOfCurrentTargets() -{ +uint16_t RecordList::getCurrentTargets() { std::set dstIpSet; for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) { - if((*it)->isMatched()) - { - ip_addr_t dstIp = (*it)->dstIp; - dstIpSet.insert(dstIp); + if ((*it).isMatched()) { + dstIpSet.insert((*it)->dstIp); } } return dstIpSet.size(); } template -void RecordList::initTotalTargetsSet() -{ +void RecordList::initTotalTargetsSet() { for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) - { - if((*it)->isMatched()) - { - ip_addr_t dstIp = (*it)->dstIp; - - hashedDstTotalIPSet.insert(dstIp); + if ((*it)->isMatched()) { + hashedDstTotalIPSet.insert((*it)->dstIp); } } -} + + template -std::vector RecordList::getIpsOfVictims() -{ +std::vector RecordList::getIpsOfVictims() { std::vector tmpIpsOfVictims; for(typename std::list::iterator it = list.begin(); it != list.end(); ++it) { - if((*it)->isMatched()) - { - ip_addr_t dstIp = (*it)->dstIp; - ip_to_str(&dstIp, str); + if ((*it)->isMatched()) { + 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.cpp b/brute_force_detector/sender.cpp index e06e5401..eb5c8fd6 100644 --- a/brute_force_detector/sender.cpp +++ b/brute_force_detector/sender.cpp @@ -45,33 +45,31 @@ #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(), NULL); - if(outTemplate == NULL) - { + if (outTemplate == NULL) { *success = false; return; } *success = true; } -Sender::~Sender() -{ - if(outTemplate != NULL) - 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 97b0689a..963c2134 100644 --- a/brute_force_detector/sender.h +++ b/brute_force_detector/sender.h @@ -45,76 +45,80 @@ #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; -//WARDEN_TYPE +// WARDEN_TYPE #define WT_BRUTEFORCE 2 /** * @desc Class for handling output messages */ -class Sender -{ +class Sender { public: - Sender(bool *success); + 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; } + 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 - 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(); + 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()->clearNumOfTargetsSinceLastReport(); - host->getPointerToIncomingRecordList()->clearNumOfMatchedFlowsSinceLastReport(); - host->getPointerToIncomingRecordList()->clearNumOTotalFlowsSinceLastReport(); - - host->getPointerToOutgoingRecordList()->clearNumOfTargetsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearNumOfMatchedFlowsSinceLastReport(); - host->getPointerToOutgoingRecordList()->clearNumOTotalFlowsSinceLastReport(); - + host->getPointerToIncomingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToIncomingRecordList()->clearTotalFlowsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearTargetsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearMatchedFlowsSinceLastReport(); + host->getPointerToOutgoingRecordList()->clearTotalFlowsSinceLastReport(); - return send(host, dstPort, actualTime, incomingAttackScale > outgoingAttackScale ? incomingAttackScale : outgoingAttackScale, endOfAttack, sNote); + return send(host, dstPort, actualTime, std::max(incomingMatched, outgoingMatched), endOfAttack, sNote); } private: 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()) - { + 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; @@ -125,29 +129,29 @@ class Sender sort(outIpsVictims.begin(), outIpsVictims.end()); outIpsVictims.erase(unique(outIpsVictims.begin(), outIpsVictims.end()), outIpsVictims.end()); - //Incoming + // Incoming note.append("I:"); - for (unsigned int i = 0; i < incIpsVictims.size(); i++) { + for (unsigned long i = 0; i < incIpsVictims.size(); i++) { note.append(incIpsVictims.at(i)); note.append(","); } //Outgoing note.append("O:"); - for (unsigned int i = 0; i < outIpsVictims.size(); i++) { + 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 - 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 +159,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); @@ -168,4 +172,4 @@ class Sender } }; -#endif +#endif // SENDER_H diff --git a/brute_force_detector/telnet_server_profile.cpp b/brute_force_detector/telnet_server_profile.cpp index b9de4a98..bee78182 100644 --- a/brute_force_detector/telnet_server_profile.cpp +++ b/brute_force_detector/telnet_server_profile.cpp @@ -43,86 +43,79 @@ */ #include "telnet_server_profile.h" + using namespace std; + #include -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) +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 < TELNET_OUTGOING_MIN_PACKETS) { return; - + } + static uint16_t profileCounter = 0; profileCounter++; - - if(listSize >= TSPArraySize) - { + + if (listSize >= TSPArraySize) { byteList.pop_front(); packetList.pop_front(); listSize--; } - + byteList.push_back(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; - + vector byteVector; + copy(packetList.begin(), packetList.end(), back_inserter(packetVector)); - copy(byteList.begin(), byteList.end(), back_inserter(byteVector)); - - //median - nth_element(byteVector.begin(), byteVector.begin() + n, byteVector.end()); + copy(byteList.begin(), byteList.end(), back_inserter(byteVector)); + + // 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)); - + TSPMap.insert(std::pair(ip, TSP)); + return TSP; } -TelnetServerProfile * TelnetServerProfileMap::findProfile(ip_addr_t & hostIp) const -{ +TelnetServerProfile *TelnetServerProfileMap::findProfile(ip_addr_t &hostIp) const { std::map::const_iterator it = TSPMap.find(hostIp); - if(it == TSPMap.end()) + 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 abb28098..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; - } - } - } - } 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; +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 if (verbose) { //invalid ip + else if (verbose) { // invalid ip + cout << "Invalid line: " << line << endl; + } + } + 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 << "Adding port range " << portString << endl; + } + } + else { // single port + uint16_t port = atoi(portString.c_str()); + whitelistedPorts->addSinglePort(port); if (verbose) { - cout << "Invalid ports range: " << ports << endl; + 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++) { - //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) { +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) { + 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 { - 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++; - } + } + else { + addPorts(currentNode, ports); + } + + currentNode->set = true; + rulesCounter++; + } } diff --git a/brute_force_detector/whitelist.h b/brute_force_detector/whitelist.h index ad96f861..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 \ 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 15334feb..adb6f932 100644 --- a/brute_force_detector/whitelist_unit_test.cpp +++ b/brute_force_detector/whitelist_unit_test.cpp @@ -48,38 +48,40 @@ using namespace std; //init and delete WL for new test instance -#define WL() { \ - if(wl!=NULL) \ - { \ - delete wl; \ - wl = NULL; \ - } \ - if(wl == NULL) \ - 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, string state) -{ +void subTestRes(int testNum, const string &state) { //cout <<"Subtest "<< testNum <<": "<< state << endl; - if (state == "fail") failCounter++; + if (state == "fail") { + failCounter++; + } } -int main() -{ +int main() { Whitelist *wl = NULL; WhitelistParser *parser; - srand(0); + srand(0); // TODO constant value as random seed //add rules using: //parser->addSelectedPortRule(ip_addr_t, direction, prefix, string ports); @@ -103,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 ****************** @@ -143,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 ****************** @@ -167,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 ****************** @@ -193,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 ****************** @@ -230,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 ****************** @@ -255,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 ****************** @@ -280,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 ****************** @@ -324,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 ****************** @@ -363,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 ****************** @@ -401,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 ***************** @@ -426,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) 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@ 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: