Skip to content

Commit e7c62c7

Browse files
committed
Add alert definitions for S7Comm
1 parent 279b0f2 commit e7c62c7

16 files changed

+520
-2
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
*
3+
* (C) 2013-24 - ntop.org
4+
*
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19+
*
20+
*/
21+
22+
#ifndef _S7COMM_INVALID_TRANSITION_ALERT_H_
23+
#define _S7COMM_INVALID_TRANSITION_ALERT_H_
24+
25+
#include "ntop_includes.h"
26+
27+
class S7CommInvalidTransitionAlert : public FlowAlert {
28+
private:
29+
u_int32_t packet_epoch;
30+
u_int16_t type_i;
31+
u_int8_t type_id;
32+
33+
ndpi_serializer *getAlertJSON(ndpi_serializer *serializer);
34+
35+
public:
36+
static FlowAlertType getClassType() {
37+
return {NDPI_NO_RISK, flow_alert_s7comm_invalid_transition, alert_category_security};
38+
}
39+
static u_int8_t getDefaultScore() { return SCORE_LEVEL_NOTICE; };
40+
41+
inline u_int32_t get_packet_epoch() { return packet_epoch; };
42+
inline u_int16_t get_type_i() { return type_i; };
43+
inline u_int8_t get_type_id() { return type_id; };
44+
45+
S7CommInvalidTransitionAlert(FlowCheck *c, Flow *f, struct timeval *_time,
46+
u_int16_t _type_i, u_int8_t _type_id) : FlowAlert(c, f) {
47+
type_i = _type_i;
48+
type_id = _type_id;
49+
packet_epoch = _time->tv_sec;
50+
setAlertScore(getDefaultScore());
51+
};
52+
~S7CommInvalidTransitionAlert(){};
53+
54+
bool autoAck() const { return false; };
55+
56+
FlowAlertType getAlertType() const { return getClassType(); }
57+
};
58+
59+
#endif /* _S7COMM_INVALID_TRANSITION_ALERT_H_ */
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
*
3+
* (C) 2013-24 - ntop.org
4+
*
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19+
*
20+
*/
21+
22+
#ifndef _S7COMM_TOO_MANY_ERRORS_ALERT_H_
23+
#define _S7COMM_TOO_MANY_ERRORS_ALERT_H_
24+
25+
#include "ntop_includes.h"
26+
27+
class S7CommTooManyErrorsAlert : public FlowAlert {
28+
private:
29+
u_int32_t num_errors;
30+
31+
ndpi_serializer* getAlertJSON(ndpi_serializer* serializer);
32+
33+
public:
34+
static FlowAlertType getClassType() {
35+
return {NDPI_NO_RISK, flow_alert_s7comm_too_many_errors, alert_category_security};
36+
}
37+
static u_int8_t getDefaultScore() { return SCORE_LEVEL_ERROR; };
38+
39+
S7CommTooManyErrorsAlert(FlowCheck* c, Flow* f, u_int32_t _num_errors) : FlowAlert(c, f) {
40+
num_errors = _num_errors;
41+
setAlertScore(getDefaultScore());
42+
};
43+
~S7CommTooManyErrorsAlert(){};
44+
45+
bool autoAck() const { return false; };
46+
47+
FlowAlertType getAlertType() const { return getClassType(); }
48+
};
49+
50+
#endif /* _S7COMM_TOO_MANY_ERRORS_ALERT_H_ */
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
*
3+
* (C) 2013-24 - ntop.org
4+
*
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19+
*
20+
*/
21+
22+
#ifndef _S7COMM_UNEXPECTED_FUNCTION_CODE_ALERT_H_
23+
#define _S7COMM_UNEXPECTED_FUNCTION_CODE_ALERT_H_
24+
25+
#include "ntop_includes.h"
26+
27+
class S7CommUnexpectedFunctionCodeAlert : public FlowAlert {
28+
private:
29+
u_int8_t function_code;
30+
31+
ndpi_serializer* getAlertJSON(ndpi_serializer* serializer);
32+
33+
public:
34+
static FlowAlertType getClassType() {
35+
return {NDPI_NO_RISK, flow_alert_s7comm_unexpected_function_code, alert_category_security};
36+
}
37+
static u_int8_t getDefaultScore() { return SCORE_LEVEL_ERROR; };
38+
39+
inline u_int8_t get_function_code() { return function_code; };
40+
41+
S7CommUnexpectedFunctionCodeAlert(FlowCheck* c, Flow* f, u_int8_t _function_code) : FlowAlert(c, f) {
42+
function_code = _function_code;
43+
setAlertScore(getDefaultScore());
44+
};
45+
~S7CommUnexpectedFunctionCodeAlert(){};
46+
47+
bool autoAck() const { return false; };
48+
49+
FlowAlertType getAlertType() const { return getClassType(); }
50+
};
51+
52+
#endif /* _S7COMM_UNEXPECTED_FUNCTION_CODE_ALERT_H_ */

include/flow_alerts_includes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@
9898
#include "flow_alerts/ModbusUnexpectedFunctionCodeAlert.h"
9999
#include "flow_alerts/ModbusTooManyExceptionsAlert.h"
100100
#include "flow_alerts/ModbusInvalidTransitionAlert.h"
101+
#include "flow_alerts/S7CommUnexpectedFunctionCodeAlert.h"
102+
#include "flow_alerts/S7CommTooManyErrorsAlert.h"
103+
#include "flow_alerts/S7CommInvalidTransitionAlert.h"
101104
#include "flow_alerts/DataExfiltrationAlert.h"
102105
#include "flow_alerts/ElephantFlowAlert.h"
103106
#include "flow_alerts/LateralMovementAlert.h"

include/flow_checks_includes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
#include "flow_checks/ModbusUnexpectedFunctionCode.h"
101101
#include "flow_checks/ModbusTooManyExceptions.h"
102102
#include "flow_checks/ModbusInvalidTransition.h"
103+
#include "flow_checks/S7CommUnexpectedFunctionCode.h"
104+
#include "flow_checks/S7CommTooManyErrors.h"
105+
#include "flow_checks/S7CommInvalidTransition.h"
103106
#include "flow_checks/TCPConnectionFailed.h"
104107
#include "flow_checks/FlowRiskTLSCertValidityTooLong.h"
105108
#include "flow_checks/FlowRiskTLSCertificateExpired.h"

include/ntop_defines.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,12 @@ extern NtopngLuaContext* getUserdata(struct lua_State *vm);
16081608
"ntopng.checks.modbus_too_many_exceptions"
16091609
#define CHECKS_MODBUS_UNEXPECTED_FUNCTION_CODE \
16101610
"ntopng.checks.modbus_unexpected_function_code_enabled"
1611+
#define CHECKS_S7COMM_INVALID_TRANSITION \
1612+
"ntopng.checks.s7comm_invalid_transition_enabled"
1613+
#define CHECKS_S7COMM_TOO_MANY_ERRORS \
1614+
"ntopng.checks.s7comm_too_many_errors_enabled"
1615+
#define CHECKS_S7COMM_UNEXPECTED_FUNCTION_CODE \
1616+
"ntopng.checks.s7comm_unexpected_function_code_enabled"
16111617

16121618
#define CUSTOM_FLOW_NDPI_SCRIPT \
16131619
"scripts/callbacks/checks/flows/custom_flow_protocol_detected_script.lua"

include/ntop_typedefs.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,10 @@ typedef enum {
540540
flow_alert_ndpi_obfuscated_traffic = 105,
541541
flow_alert_nedge_policy_violation = 106,
542542
flow_alert_ndpi_mismatching_protocol_with_ip = 107,
543-
543+
flow_alert_s7comm_unexpected_function_code = 108,
544+
flow_alert_s7comm_too_many_errors = 109,
545+
flow_alert_s7comm_invalid_transition = 110,
546+
544547
MAX_DEFINED_FLOW_ALERT_TYPE, /* Leave it as last member */
545548

546549
MAX_FLOW_ALERT_TYPE =

scripts/locales/en.lua

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3307,6 +3307,17 @@ local lang = {
33073307
["modbus_unexpected_function_code_ids_description"] = "Comma separated values of ModbusTCP Function Codes. Example: 1,2,3,4",
33083308
["modbus_unexpected_function_code_ids_title"] = "Allowed Function Codes",
33093309
["modbus_unexpected_function_code_title"] = "ModbusTCP Unexpected Function Code",
3310+
["s7comm_description"] = "Trigger an alert when an invalid S7Comm transition is detected",
3311+
["s7comm_invalid_function_code"] = "S7Comm Invalid Function Code",
3312+
["s7comm_invalid_transition"] = "S7Comm Invalid Transition",
3313+
["s7comm_title"] = "S7Comm Invalid Transition",
3314+
["s7comm_too_many_errors"] = "S7Comm Too Many Errors",
3315+
["s7comm_too_many_errors_description"] = "Trigger an alert when a flow reports a number of errors exceeding the specified threshold",
3316+
["s7comm_too_many_errors_title"] = "S7Comm Too Many Errors",
3317+
["s7comm_unexpected_function_code_description"] = "Trigger an alert when an unexpected S7Comm Function code is detected",
3318+
["s7comm_unexpected_function_code_ids_description"] = "Comma separated values of S7Comm Function Codes. Example: 0x04,0x05,0xf0",
3319+
["s7comm_unexpected_function_code_ids_title"] = "Allowed Function Codes",
3320+
["s7comm_unexpected_function_code_title"] = "S7Comm Unexpected Function Code",
33103321
["network_behavior_check_list"] = "Networks to analyze",
33113322
["network_behavior_check_list_example"] = "A list of Networks to analyze, separated by commas",
33123323
["no_callbacks_available"] = "No callbacks available.",
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
--
2+
-- (C) 2019-24 - ntop.org
3+
--
4+
5+
-- ##############################################
6+
7+
local flow_alert_keys = require "flow_alert_keys"
8+
local json = require "dkjson"
9+
local format_utils = require "format_utils"
10+
-- Import the classes library.
11+
local classes = require "classes"
12+
-- Make sure to import the Superclass!
13+
local alert = require "alert"
14+
-- Import Mitre Att&ck utils
15+
local mitre = require "mitre_utils"
16+
17+
-- ##############################################
18+
19+
local alert_s7comm_invalid_transition = classes.class(alert)
20+
21+
-- ##############################################
22+
23+
alert_s7comm_invalid_transition.meta = {
24+
alert_key = flow_alert_keys.flow_alert_s7comm_invalid_transition,
25+
i18n_title = "flow_checks.s7comm_invalid_transition",
26+
icon = "fas fa-fw fa-industry",
27+
28+
-- Mitre Att&ck Matrix values
29+
mitre_values = {
30+
mitre_tactic = mitre.tactic.impact,
31+
mitre_technique = mitre.technique.data_manipulation,
32+
mitre_id = "T1565"
33+
},
34+
}
35+
36+
-- ##############################################
37+
38+
-- @brief Prepare an alert table used to generate the alert
39+
-- @param last_error A string with the lastest influxdb error
40+
-- @return A table with the alert built
41+
function alert_s7comm_invalid_transition:init()
42+
-- Call the parent constructor
43+
self.super:init()
44+
end
45+
46+
-- ##############################################
47+
48+
local function function_code_to_string(function_id)
49+
-- S7Comm function codes
50+
if(function_id == 0x04) then return("Read Var (" .. function_id .. ")") end
51+
if(function_id == 0x05) then return("Write Var (" .. function_id .. ")") end
52+
if(function_id == 0xf0) then return("Setup Communication (" .. function_id .. ")") end
53+
if(function_id == 0x00) then return("CPU Services (" .. function_id .. ")") end
54+
if(function_id == 0x29) then return("PLC Control (" .. function_id .. ")") end
55+
if(function_id == 0x28) then return("PLC Stop (" .. function_id .. ")") end
56+
57+
return(function_id)
58+
end
59+
60+
-- #######################################################
61+
62+
-- @brief Format an alert into a human-readable string
63+
-- @param ifid The integer interface id of the generated alert
64+
-- @param alert The alert description table, including alert data such as the generating entity, timestamp, granularity, type
65+
-- @param alert_type_params Table `alert_type_params` as built in the `:init` method
66+
-- @return A human-readable string
67+
function alert_s7comm_invalid_transition.format(ifid, alert, alert_type_params)
68+
local from = function_code_to_string(alert_type_params.from) or alert_type_params.from or i18n('unknown')
69+
local to = function_code_to_string(alert_type_params.to) or alert_type_params.to or i18n('unknown')
70+
71+
local rsp = from .. " -> ".. to
72+
73+
-- tprint(alert_type_params)
74+
75+
return(rsp)
76+
end
77+
78+
-- #######################################################
79+
80+
return alert_s7comm_invalid_transition
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
--
2+
-- (C) 2019-24 - ntop.org
3+
--
4+
5+
-- ##############################################
6+
7+
local flow_alert_keys = require "flow_alert_keys"
8+
local json = require "dkjson"
9+
local format_utils = require "format_utils"
10+
-- Import the classes library.
11+
local classes = require "classes"
12+
-- Make sure to import the Superclass!
13+
local alert = require "alert"
14+
-- Import Mitre Att&ck utils
15+
local mitre = require "mitre_utils"
16+
17+
-- ##############################################
18+
19+
local alert_s7comm_too_many_errors = classes.class(alert)
20+
21+
-- ##############################################
22+
23+
alert_s7comm_too_many_errors.meta = {
24+
alert_key = flow_alert_keys.flow_alert_s7comm_too_many_errors,
25+
i18n_title = "flow_checks.s7comm_too_many_errors",
26+
icon = "fas fa-fw fa-industry",
27+
28+
-- Mitre Att&ck Matrix values
29+
mitre_values = {
30+
mitre_tactic = mitre.tactic.impact,
31+
mitre_technique = mitre.technique.data_manipulation,
32+
mitre_id = "T1565"
33+
},
34+
}
35+
36+
-- ##############################################
37+
38+
-- @brief Prepare an alert table used to generate the alert
39+
-- @param last_error A string with the lastest influxdb error
40+
-- @return A table with the alert built
41+
function alert_s7comm_too_many_errors:init()
42+
-- Call the parent constructor
43+
self.super:init()
44+
end
45+
46+
-- #######################################################
47+
48+
-- @brief Format an alert into a human-readable string
49+
-- @param ifid The integer interface id of the generated alert
50+
-- @param alert The alert description table, including alert data such as the generating entity, timestamp, granularity, type
51+
-- @param alert_type_params Table `alert_type_params` as built in the `:init` method
52+
-- @return A human-readable string
53+
function alert_s7comm_too_many_errors.format(ifid, alert, alert_type_params)
54+
local rsp = alert_type_params.num_errors .. " Errors"
55+
56+
-- tprint(alert_type_params)
57+
58+
return(rsp)
59+
end
60+
61+
-- #######################################################
62+
63+
return alert_s7comm_too_many_errors

0 commit comments

Comments
 (0)