def test_05_advanced(self): """ Test parsing of advanced filtering expressions. """ self.maxDiff = None p = MentatFilterParser() p.build() self.assertEqual( repr(p.parse('Category in ["Abusive.Spam" , "Attempt.Exploit"]')), "COMPBINOP(VARIABLE('Category') OP_IN LIST(CONSTANT('Abusive.Spam'), CONSTANT('Attempt.Exploit')))" ) self.assertEqual( repr(p.parse('Category is ["Abusive.Spam" , "Attempt.Exploit"]')), "COMPBINOP(VARIABLE('Category') OP_IS LIST(CONSTANT('Abusive.Spam'), CONSTANT('Attempt.Exploit')))" ) self.assertEqual( repr(p.parse('Node.Name in ["cz.cesnet.labrea"]')), "COMPBINOP(VARIABLE('Node.Name') OP_IN LIST(CONSTANT('cz.cesnet.labrea')))" ) self.assertEqual( repr(p.parse('Source.IP4 in [127.0.0.1 , 127.0.0.2]')), "COMPBINOP(VARIABLE('Source.IP4') OP_IN LIST(IPV4('127.0.0.1'), IPV4('127.0.0.2')))" ) self.assertEqual( repr( p.parse( '(Source.IP4 eq 127.0.0.1) or (Node[#].Name is "cz.cesnet.labrea")' )), "LOGBINOP(COMPBINOP(VARIABLE('Source.IP4') OP_EQ IPV4('127.0.0.1')) OP_OR COMPBINOP(VARIABLE('Node[#].Name') OP_IS CONSTANT('cz.cesnet.labrea')))" )
def __init__(self, rule, actions, addrGroups, parser=None, compiler=None): # Check is we got parser instance if parser is None: self.parser = MentatFilterParser() self.parser.build() else: self.parser = parser # Check is we got compiler instance if compiler is None: self.compiler = IDEAFilterCompiler() else: self.compiler = compiler # Instantiate filter self.__filter = DataObjectFilter() # Store rule condition in raw form self.__conditionRaw = rule["condition"] if not self.__matchvar(rule["condition"], addrGroups): self.__condition = self.__conditionRaw # Set inner rule ID self.id = rule["id"] if (self.__condition != None): self.parseRule() self.__actions = list() self.__elseactions = list() # Associate actions if "actions" in rule: for actionId in rule["actions"]: try: logger.debug("Rule %s inserting %s", self.id, actionId) self.__actions.append(actions[actionId]) except KeyError as e: raise Exception("Missing action with ID " + str(e)) # Associate elseactions if "elseactions" in rule: for actionId in rule["elseactions"]: try: self.__elseactions.append(actions[actionId]) except KeyError as e: raise Exception("Missing elseaction with ID " + str(e))
def test_05_non_existent_nodes(self): """ Perform advanced filtering tests. """ self.maxDiff = None flt = DataObjectFilter() psr = MentatFilterParser() psr.build() rule = psr.parse('(ConnCounts + 10) > 11') self.assertEqual(flt.filter(rule, self.test_msg1), None) rule = psr.parse('ConnCount > ConnCounts') self.assertEqual(flt.filter(rule, self.test_msg1), None) rule = psr.parse('DetectTime < InspectionTime') self.assertEqual(flt.filter(rule, self.test_msg1), None)
def test_04_advanced_filters(self): """ Perform advanced filtering tests. """ self.maxDiff = None flt = DataObjectFilter() psr = MentatFilterParser() psr.build() rule = psr.parse('(ConnCount + 10) > 11') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('((ConnCount + 3) < 5) or ((ConnCount + 10) > 11)') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('1') self.assertEqual(flt.filter(rule, self.test_msg1), True)
def test_03_basic_math(self): """ Perform basic math tests. """ self.maxDiff = None flt = DataObjectFilter() psr = MentatFilterParser() psr.build() rule = MathBinOpRule('OP_PLUS', VariableRule("ConnCount"), IntegerRule(1)) self.assertEqual(flt.filter(rule, self.test_msg1), 3) rule = MathBinOpRule('OP_MINUS', VariableRule("ConnCount"), IntegerRule(1)) self.assertEqual(flt.filter(rule, self.test_msg1), 1) rule = MathBinOpRule('OP_TIMES', VariableRule("ConnCount"), IntegerRule(5)) self.assertEqual(flt.filter(rule, self.test_msg1), 10) rule = MathBinOpRule('OP_DIVIDE', VariableRule("ConnCount"), IntegerRule(2)) self.assertEqual(flt.filter(rule, self.test_msg1), 1) rule = MathBinOpRule('OP_MODULO', VariableRule("ConnCount"), IntegerRule(2)) self.assertEqual(flt.filter(rule, self.test_msg1), 0) rule = psr.parse('ConnCount + 1') self.assertEqual(flt.filter(rule, self.test_msg1), 3) rule = psr.parse('ConnCount - 1') self.assertEqual(flt.filter(rule, self.test_msg1), 1) rule = psr.parse('ConnCount * 5') self.assertEqual(flt.filter(rule, self.test_msg1), 10) rule = psr.parse('ConnCount / 2') self.assertEqual(flt.filter(rule, self.test_msg1), 1) rule = psr.parse('ConnCount % 2') self.assertEqual(flt.filter(rule, self.test_msg1), 0)
def __init__(self, path, trap = None, warden = None): """ :param path Path to YAML configuration file :param trap Instance of TRAP client used in TrapAction :param warden Instance of Warden Client used in WardenAction """ # Parse given config file with open(path, 'r') as f: self.conf = Parser(f) if not self.conf: raise Exception("Loading YAML file ({0}) failed. Isn't it empty?".format(path)) # Build parser self.parser = MentatFilterParser() self.parser.build() self.compiler = IDEAFilterCompiler() self.addrGroups = dict() # Create all address groups if there are any if "addressgroups" in self.conf: for i in self.conf["addressgroups"]: self.addrGroups[i["id"]] = AddressGroup(i) self.actions = dict() # Parse and instantiate all custom actions if "custom_actions" in self.conf: for i in self.conf["custom_actions"]: if "mark" in i: from .actions.Mark import MarkAction self.actions[i["id"]] = MarkAction(i) elif "mongo" in i: from .actions.Mongo import MongoAction self.actions[i["id"]] = MongoAction(i) elif "email" in i: from .actions.Email import EmailAction self.actions[i["id"]] = EmailAction(i) elif "file" in i: from .actions.File import FileAction self.actions[i["id"]] = FileAction(i) elif "warden" in i: """ Pass Warden Client instance to the Warden action """ from .actions.Warden import WardenAction self.actions[i["id"]] = WardenAction(i, warden) elif "trap" in i: """ Pass TRAP context instance to the TRAP action """ from .actions.Trap import TrapAction self.actions[i["id"]] = TrapAction(i, trap) elif "drop" in i: logger.warning("Drop action mustn't be specified in custom_actions!") continue else: raise Exception("Undefined action: " + str(i)) self.actions["drop"] = DropAction() self.rules = list() # Parse all rules and match them with actions and address groups # There must be at least one rule (mandatory field) if "rules" in self.conf: if self.conf["rules"]: for i in self.conf["rules"]: self.rules.append(Rule(i , self.actions , self.addrGroups , parser = self.parser , compiler = self.compiler )) if not self.rules: raise Exception("YAML file should contain at least one `rule` in `rules`.") else: raise Exception("YAML file must contain `rules`.")
class Config(): addrGroups = dict() actions = dict() rules = list() parser = None compiler = None def __init__(self, path, trap = None, warden = None): """ :param path Path to YAML configuration file :param trap Instance of TRAP client used in TrapAction :param warden Instance of Warden Client used in WardenAction """ # Parse given config file with open(path, 'r') as f: self.conf = Parser(f) if not self.conf: raise Exception("Loading YAML file ({0}) failed. Isn't it empty?".format(path)) # Build parser self.parser = MentatFilterParser() self.parser.build() self.compiler = IDEAFilterCompiler() self.addrGroups = dict() # Create all address groups if there are any if "addressgroups" in self.conf: for i in self.conf["addressgroups"]: self.addrGroups[i["id"]] = AddressGroup(i) self.actions = dict() # Parse and instantiate all custom actions if "custom_actions" in self.conf: for i in self.conf["custom_actions"]: if "mark" in i: from .actions.Mark import MarkAction self.actions[i["id"]] = MarkAction(i) elif "mongo" in i: from .actions.Mongo import MongoAction self.actions[i["id"]] = MongoAction(i) elif "email" in i: from .actions.Email import EmailAction self.actions[i["id"]] = EmailAction(i) elif "file" in i: from .actions.File import FileAction self.actions[i["id"]] = FileAction(i) elif "warden" in i: """ Pass Warden Client instance to the Warden action """ from .actions.Warden import WardenAction self.actions[i["id"]] = WardenAction(i, warden) elif "trap" in i: """ Pass TRAP context instance to the TRAP action """ from .actions.Trap import TrapAction self.actions[i["id"]] = TrapAction(i, trap) elif "drop" in i: logger.warning("Drop action mustn't be specified in custom_actions!") continue else: raise Exception("Undefined action: " + str(i)) self.actions["drop"] = DropAction() self.rules = list() # Parse all rules and match them with actions and address groups # There must be at least one rule (mandatory field) if "rules" in self.conf: if self.conf["rules"]: for i in self.conf["rules"]: self.rules.append(Rule(i , self.actions , self.addrGroups , parser = self.parser , compiler = self.compiler )) if not self.rules: raise Exception("YAML file should contain at least one `rule` in `rules`.") else: raise Exception("YAML file must contain `rules`.") def match(self, msg): """ Check if msg matches rules from config file. Return a list of bool values representing results of all tested rules. """ results = [] actionsDone = [] try: for rule in self.rules: self.clearActionLog() res = rule.filter(msg) #logger.debug("Filter by rule: %s \n message: %s\n\nresult: %s", rule, msg, res) #print("Filter by rule: %s \n message: %s\n\nresult: %s" % (rule.rule(), msg, res)) results.append(res) tmp_msg = copy.deepcopy(msg) if res: # condition is True rule.actions(tmp_msg) logger.info("action running") else: # condition is False rule.elseactions(tmp_msg) logger.info("else action running") actionsDone.append(self.getActionLog()) except DropMsg: # This exception breaks the processing of rule list. pass return (results, actionsDone) def getActionLog(self): return Action.actionLog def clearActionLog(self): Action.actionLog = [] def loglevel(self): """Get logging level CRITICAL 50 ERROR 40 WARNING 30 INFO 20 DEBUG 10 NOTSET 0 """ try: return (self.conf["reporter"]["loglevel"]) * 10 except: return 30 def __str__(self): ag = "\n".join([str(self.addrGroups[key]) for key in self.addrGroups]) a = "\n".join([key + ":\n\t" + str(self.actions[key]) for key in self.actions]) r = "\n".join([str(val) for val in self.rules]) string = "Address Groups:\n{0}\n----------------\nCustom Actions:\n{1}\n----------------\nRules:\n{2}\n".format(ag, a, r) return string
def test_04_basic_factors(self): """ Test parsing of all available factors. """ self.maxDiff = None p = MentatFilterParser() p.build() self.assertEqual(repr(p.parse("127.0.0.1")), "IPV4('127.0.0.1')") self.assertEqual(repr(p.parse("::1")), "IPV6('::1')") self.assertEqual(repr(p.parse("1")), "INTEGER(1)") self.assertEqual(repr(p.parse("1.1")), "FLOAT(1.1)") self.assertEqual(repr(p.parse("Test")), "VARIABLE('Test')") self.assertEqual(repr(p.parse('"constant1"')), "CONSTANT('constant1')") self.assertEqual(repr(p.parse("(127.0.0.1)")), "IPV4('127.0.0.1')") self.assertEqual(repr(p.parse("(::1)")), "IPV6('::1')") self.assertEqual(repr(p.parse("(1)")), "INTEGER(1)") self.assertEqual(repr(p.parse("(1.1)")), "FLOAT(1.1)") self.assertEqual(repr(p.parse("(Test)")), "VARIABLE('Test')") self.assertEqual(repr(p.parse('("constant1")')), "CONSTANT('constant1')") self.assertEqual(repr(p.parse("((127.0.0.1))")), "IPV4('127.0.0.1')") self.assertEqual(repr(p.parse("((::1))")), "IPV6('::1')") self.assertEqual(repr(p.parse("((1))")), "INTEGER(1)") self.assertEqual(repr(p.parse("((1.1))")), "FLOAT(1.1)") self.assertEqual(repr(p.parse("((Test))")), "VARIABLE('Test')") self.assertEqual(repr(p.parse('(("constant1"))')), "CONSTANT('constant1')") self.assertEqual(repr(p.parse("[127.0.0.1]")), "LIST(IPV4('127.0.0.1'))") self.assertEqual(repr(p.parse("[::1]")), "LIST(IPV6('::1'))") self.assertEqual(repr(p.parse("[1]")), "LIST(INTEGER(1))") self.assertEqual(repr(p.parse("[1.1]")), "LIST(FLOAT(1.1))") self.assertEqual(repr(p.parse("[Test]")), "LIST(VARIABLE('Test'))") self.assertEqual(repr(p.parse('["constant1"]')), "LIST(CONSTANT('constant1'))") self.assertEqual(repr(p.parse("[127.0.0.1 , 127.0.0.2]")), "LIST(IPV4('127.0.0.1'), IPV4('127.0.0.2'))") self.assertEqual(repr(p.parse("[::1 , ::2]")), "LIST(IPV6('::1'), IPV6('::2'))") self.assertEqual( repr(p.parse("[1,2, 3,4 , 5]")), "LIST(INTEGER(1), INTEGER(2), INTEGER(3), INTEGER(4), INTEGER(5))") self.assertEqual( repr(p.parse("[1.1,2.2, 3.3,4.4 , 5.5]")), "LIST(FLOAT(1.1), FLOAT(2.2), FLOAT(3.3), FLOAT(4.4), FLOAT(5.5))") self.assertEqual( repr(p.parse("[Var1,Var2, Var3,Var4 , Var5 ]")), "LIST(VARIABLE('Var1'), VARIABLE('Var2'), VARIABLE('Var3'), VARIABLE('Var4'), VARIABLE('Var5'))" ) self.assertEqual( repr(p.parse('["c1","c2", "c3","c4" , "c5" ]')), "LIST(CONSTANT('c1'), CONSTANT('c2'), CONSTANT('c3'), CONSTANT('c4'), CONSTANT('c5'))" )
def test_03_basic_math(self): """ Test the parsing of basic mathematical operations. """ self.maxDiff = None p = MentatFilterParser() p.build() self.assertEqual(repr(p.parse('3 + 3')), 'MATHBINOP(INTEGER(3) OP_PLUS INTEGER(3))') self.assertEqual(repr(p.parse('3 - 3')), 'MATHBINOP(INTEGER(3) OP_MINUS INTEGER(3))') self.assertEqual(repr(p.parse('3 * 3')), 'MATHBINOP(INTEGER(3) OP_TIMES INTEGER(3))') self.assertEqual(repr(p.parse('3 / 3')), 'MATHBINOP(INTEGER(3) OP_DIVIDE INTEGER(3))') self.assertEqual(repr(p.parse('3 % 3')), 'MATHBINOP(INTEGER(3) OP_MODULO INTEGER(3))') self.assertEqual(repr(p.parse('(3 + 3)')), 'MATHBINOP(INTEGER(3) OP_PLUS INTEGER(3))') self.assertEqual(repr(p.parse('(3 - 3)')), 'MATHBINOP(INTEGER(3) OP_MINUS INTEGER(3))') self.assertEqual(repr(p.parse('(3 * 3)')), 'MATHBINOP(INTEGER(3) OP_TIMES INTEGER(3))') self.assertEqual(repr(p.parse('(3 / 3)')), 'MATHBINOP(INTEGER(3) OP_DIVIDE INTEGER(3))') self.assertEqual(repr(p.parse('(3 % 3)')), 'MATHBINOP(INTEGER(3) OP_MODULO INTEGER(3))') self.assertEqual(repr(p.parse('((3 + 3))')), 'MATHBINOP(INTEGER(3) OP_PLUS INTEGER(3))') self.assertEqual(repr(p.parse('((3 - 3))')), 'MATHBINOP(INTEGER(3) OP_MINUS INTEGER(3))') self.assertEqual(repr(p.parse('((3 * 3))')), 'MATHBINOP(INTEGER(3) OP_TIMES INTEGER(3))') self.assertEqual(repr(p.parse('((3 / 3))')), 'MATHBINOP(INTEGER(3) OP_DIVIDE INTEGER(3))') self.assertEqual(repr(p.parse('((3 % 3))')), 'MATHBINOP(INTEGER(3) OP_MODULO INTEGER(3))')
def test_01_basic_logical(self): """ Test the parsing of basic logical operations. """ self.maxDiff = None p = MentatFilterParser() p.build() self.assertEqual(repr(p.parse('1 and 1')), 'LOGBINOP(INTEGER(1) OP_AND INTEGER(1))') self.assertEqual(repr(p.parse('1 AND 1')), 'LOGBINOP(INTEGER(1) OP_AND INTEGER(1))') self.assertEqual(repr(p.parse('1 && 1')), 'LOGBINOP(INTEGER(1) OP_AND_P INTEGER(1))') self.assertEqual(repr(p.parse('1 or 1')), 'LOGBINOP(INTEGER(1) OP_OR INTEGER(1))') self.assertEqual(repr(p.parse('1 OR 1')), 'LOGBINOP(INTEGER(1) OP_OR INTEGER(1))') self.assertEqual(repr(p.parse('1 || 1')), 'LOGBINOP(INTEGER(1) OP_OR_P INTEGER(1))') self.assertEqual(repr(p.parse('1 xor 1')), 'LOGBINOP(INTEGER(1) OP_XOR INTEGER(1))') self.assertEqual(repr(p.parse('1 XOR 1')), 'LOGBINOP(INTEGER(1) OP_XOR INTEGER(1))') self.assertEqual(repr(p.parse('1 ^^ 1')), 'LOGBINOP(INTEGER(1) OP_XOR_P INTEGER(1))') self.assertEqual(repr(p.parse('not 1')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('NOT 1')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('! 1')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('exists 1')), 'UNOP(OP_EXISTS INTEGER(1))') self.assertEqual(repr(p.parse('EXISTS 1')), 'UNOP(OP_EXISTS INTEGER(1))') self.assertEqual(repr(p.parse('? 1')), 'UNOP(OP_EXISTS INTEGER(1))') self.assertEqual(repr(p.parse('(1 and 1)')), 'LOGBINOP(INTEGER(1) OP_AND INTEGER(1))') self.assertEqual(repr(p.parse('(1 AND 1)')), 'LOGBINOP(INTEGER(1) OP_AND INTEGER(1))') self.assertEqual(repr(p.parse('(1 && 1)')), 'LOGBINOP(INTEGER(1) OP_AND_P INTEGER(1))') self.assertEqual(repr(p.parse('(1 or 1)')), 'LOGBINOP(INTEGER(1) OP_OR INTEGER(1))') self.assertEqual(repr(p.parse('(1 OR 1)')), 'LOGBINOP(INTEGER(1) OP_OR INTEGER(1))') self.assertEqual(repr(p.parse('(1 || 1)')), 'LOGBINOP(INTEGER(1) OP_OR_P INTEGER(1))') self.assertEqual(repr(p.parse('(1 xor 1)')), 'LOGBINOP(INTEGER(1) OP_XOR INTEGER(1))') self.assertEqual(repr(p.parse('(1 XOR 1)')), 'LOGBINOP(INTEGER(1) OP_XOR INTEGER(1))') self.assertEqual(repr(p.parse('(1 ^^ 1)')), 'LOGBINOP(INTEGER(1) OP_XOR_P INTEGER(1))') self.assertEqual(repr(p.parse('(not 1)')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('(NOT 1)')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('(! 1)')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('(exists 1)')), 'UNOP(OP_EXISTS INTEGER(1))') self.assertEqual(repr(p.parse('(EXISTS 1)')), 'UNOP(OP_EXISTS INTEGER(1))') self.assertEqual(repr(p.parse('(? 1)')), 'UNOP(OP_EXISTS INTEGER(1))') self.assertEqual(repr(p.parse('((1 and 1))')), 'LOGBINOP(INTEGER(1) OP_AND INTEGER(1))') self.assertEqual(repr(p.parse('((1 AND 1))')), 'LOGBINOP(INTEGER(1) OP_AND INTEGER(1))') self.assertEqual(repr(p.parse('((1 && 1))')), 'LOGBINOP(INTEGER(1) OP_AND_P INTEGER(1))') self.assertEqual(repr(p.parse('((1 or 1))')), 'LOGBINOP(INTEGER(1) OP_OR INTEGER(1))') self.assertEqual(repr(p.parse('((1 OR 1))')), 'LOGBINOP(INTEGER(1) OP_OR INTEGER(1))') self.assertEqual(repr(p.parse('((1 || 1))')), 'LOGBINOP(INTEGER(1) OP_OR_P INTEGER(1))') self.assertEqual(repr(p.parse('((1 xor 1))')), 'LOGBINOP(INTEGER(1) OP_XOR INTEGER(1))') self.assertEqual(repr(p.parse('((1 XOR 1))')), 'LOGBINOP(INTEGER(1) OP_XOR INTEGER(1))') self.assertEqual(repr(p.parse('((1 ^^ 1))')), 'LOGBINOP(INTEGER(1) OP_XOR_P INTEGER(1))') self.assertEqual(repr(p.parse('((not 1))')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('((NOT 1))')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('((! 1))')), 'UNOP(OP_NOT INTEGER(1))') self.assertEqual(repr(p.parse('((exists 1))')), 'UNOP(OP_EXISTS INTEGER(1))') self.assertEqual(repr(p.parse('((EXISTS 1))')), 'UNOP(OP_EXISTS INTEGER(1))') self.assertEqual(repr(p.parse('((? 1))')), 'UNOP(OP_EXISTS INTEGER(1))')
def test_02_basic_comparison(self): """ Test the parsing of basic comparison operations. """ self.maxDiff = None p = MentatFilterParser() p.build() self.assertEqual(repr(p.parse('2 like 2')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('2 LIKE 2')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('2 =~ 2')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('2 in 2')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('2 IN 2')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('2 ~~ 2')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('2 is 2')), 'COMPBINOP(INTEGER(2) OP_IS INTEGER(2))') self.assertEqual(repr(p.parse('2 IS 2')), 'COMPBINOP(INTEGER(2) OP_IS INTEGER(2))') self.assertEqual(repr(p.parse('2 eq 2')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('2 EQ 2')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('2 == 2')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('2 ne 2')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('2 NE 2')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('2 != 2')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('2 <> 2')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('2 ge 2')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('2 GE 2')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('2 >= 2')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('2 gt 2')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('2 GT 2')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('2 > 2')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('2 le 2')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('2 LE 2')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('2 <= 2')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('2 lt 2')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))') self.assertEqual(repr(p.parse('2 LT 2')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))') self.assertEqual(repr(p.parse('2 < 2')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))') self.assertEqual(repr(p.parse('(2 like 2)')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('(2 LIKE 2)')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('(2 =~ 2)')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('(2 in 2)')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('(2 IN 2)')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('(2 ~~ 2)')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('(2 is 2)')), 'COMPBINOP(INTEGER(2) OP_IS INTEGER(2))') self.assertEqual(repr(p.parse('(2 IS 2)')), 'COMPBINOP(INTEGER(2) OP_IS INTEGER(2))') self.assertEqual(repr(p.parse('(2 eq 2)')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('(2 EQ 2)')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('(2 == 2)')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('(2 ne 2)')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('(2 NE 2)')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('(2 != 2)')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('(2 <> 2)')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('(2 ge 2)')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('(2 GE 2)')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('(2 >= 2)')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('(2 gt 2)')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('(2 GT 2)')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('(2 > 2)')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('(2 le 2)')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('(2 LE 2)')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('(2 <= 2)')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('(2 lt 2)')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))') self.assertEqual(repr(p.parse('(2 LT 2)')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))') self.assertEqual(repr(p.parse('(2 < 2)')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))') self.assertEqual(repr(p.parse('((2 like 2))')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('((2 LIKE 2))')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('((2 =~ 2))')), 'COMPBINOP(INTEGER(2) OP_LIKE INTEGER(2))') self.assertEqual(repr(p.parse('((2 in 2))')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('((2 IN 2))')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('((2 ~~ 2))')), 'COMPBINOP(INTEGER(2) OP_IN INTEGER(2))') self.assertEqual(repr(p.parse('((2 is 2))')), 'COMPBINOP(INTEGER(2) OP_IS INTEGER(2))') self.assertEqual(repr(p.parse('((2 IS 2))')), 'COMPBINOP(INTEGER(2) OP_IS INTEGER(2))') self.assertEqual(repr(p.parse('((2 eq 2))')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('((2 EQ 2))')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('((2 == 2))')), 'COMPBINOP(INTEGER(2) OP_EQ INTEGER(2))') self.assertEqual(repr(p.parse('((2 ne 2))')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('((2 NE 2))')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('((2 != 2))')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('((2 <> 2))')), 'COMPBINOP(INTEGER(2) OP_NE INTEGER(2))') self.assertEqual(repr(p.parse('((2 ge 2))')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('((2 GE 2))')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('((2 >= 2))')), 'COMPBINOP(INTEGER(2) OP_GE INTEGER(2))') self.assertEqual(repr(p.parse('((2 gt 2))')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('((2 GT 2))')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('((2 > 2))')), 'COMPBINOP(INTEGER(2) OP_GT INTEGER(2))') self.assertEqual(repr(p.parse('((2 le 2))')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('((2 LE 2))')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('((2 <= 2))')), 'COMPBINOP(INTEGER(2) OP_LE INTEGER(2))') self.assertEqual(repr(p.parse('((2 lt 2))')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))') self.assertEqual(repr(p.parse('((2 LT 2))')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))') self.assertEqual(repr(p.parse('((2 < 2))')), 'COMPBINOP(INTEGER(2) OP_LT INTEGER(2))')
class Rule(): def __init__(self, rule, actions, addrGroups, parser=None, compiler=None): # Check is we got parser instance if parser is None: self.parser = MentatFilterParser() self.parser.build() else: self.parser = parser # Check is we got compiler instance if compiler is None: self.compiler = IDEAFilterCompiler() else: self.compiler = compiler # Instantiate filter self.__filter = DataObjectFilter() # Store rule condition in raw form self.__conditionRaw = rule["condition"] if not self.__matchvar(rule["condition"], addrGroups): self.__condition = self.__conditionRaw # Set inner rule ID self.id = rule["id"] if (self.__condition != None): self.parseRule() self.__actions = list() self.__elseactions = list() # Associate actions if "actions" in rule: for actionId in rule["actions"]: try: logger.debug("Rule %s inserting %s", self.id, actionId) self.__actions.append(actions[actionId]) except KeyError as e: raise Exception("Missing action with ID " + str(e)) # Associate elseactions if "elseactions" in rule: for actionId in rule["elseactions"]: try: self.__elseactions.append(actions[actionId]) except KeyError as e: raise Exception("Missing elseaction with ID " + str(e)) def parseRule(self): cond = str(self.__condition).lower() if cond in ["none", "null", "true"]: self.__condition = True elif cond == "false": self.__condition = False else: try: self.__condition = self.parser.parse(self.__condition) self.__condition = self.compiler.compile(self.__condition) except Exception as e: print( "Error while parsing condition: {0}\nOriginal exception: {1}" .format(self.__condition, e)) def filter(self, record): """ Filter given record based on rule's condition @note If the rule's condition is empty, record is always matched. @return Boolean """ # The message must be converted via idea module if not isinstance(record, lite.Idea): logger.info("Converting message to IDEA") record = lite.Idea(record) logger.debug(record) logger.debug(self.__condition) if self.__condition == None or self.__condition == True: # Rule condition is empty (tautology) - should always match the record res = True elif self.__condition == False: res = False else: # Match the record with non-empty rule's condition res = self.__filter.filter(self.__condition, record) logger.debug("RESULT: %s", res) return res def actions(self, record): for action in self.__actions: action.run(record) def elseactions(self, record): for action in self.__elseactions: action.run(record) def __repr__(self): return self.__conditionRaw def __str__(self): actions = [] for i in self.__actions: actions.append("{0} ({1})".format(i.actionId, i.actionType)) elseactions = [] for i in self.__elseactions: elseactions.append("{0} ({1})".format(i.actionId, i.actionType)) return "{0}: {1}\n{2}{3}".format( self.id, " ".join([i.strip() for i in str(self.__conditionRaw).split("\n")]), "\tActions: " + (", ".join(actions)) + "\n" if actions else "", "\tElse Actions: " + (", ".join(elseactions)) + "\n" if elseactions else "") def rule(self): return str(self.__condition) def __matchvar(self, rule, addrGroups): """ Since pyncspect doesn't support variables yet we had to provide a solution where every address group's name is matched against the rule's condition and eventually replaced with address group's values """ matched = False """ Tautology - empty rule should always match Don't try to match or replace any address group """ if rule == None or isinstance(rule, bool): return False for key in addrGroups: if key in rule: rule = re.sub(r"\b{0}\b".format(re.escape(key)), addrGroups[key].iplist(), rule) matched = True self.__condition = rule return matched
# https://packaging.python.org/en/latest/ # https://python-packaging.readthedocs.io/en/latest/index.html # Always prefer setuptools over distutils from setuptools import setup, find_packages # To use a consistent encoding from codecs import open from os import path # Generate parsetab.py in advance so it can go into package. from pynspect.jpath import * from pynspect.rules import * from pynspect.gparser import MentatFilterParser from pynspect.filters import DataObjectFilter parser = MentatFilterParser() parser.build() here = path.abspath(path.dirname(__file__)) # Get the long description from the README file with open(path.join(here, 'README.rst'), encoding='utf-8') as f: long_description = f.read() setup(name='pynspect', version='0.5', description='Python data inspection library', long_description=long_description, classifiers=[ 'Development Status :: 3 - Alpha', 'License :: OSI Approved :: MIT License',
def test_02_basic_comparison(self): """ Perform basic filtering tests. """ self.maxDiff = None flt = DataObjectFilter() psr = MentatFilterParser() psr.build() rule = ComparisonBinOpRule( 'OP_EQ', VariableRule("ID"), ConstantRule("e214d2d9-359b-443d-993d-3cc5637107a0")) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule( 'OP_EQ', VariableRule("ID"), ConstantRule("e214d2d9-359b-443d-993d-3cc5637107")) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule( 'OP_NE', VariableRule("ID"), ConstantRule("e214d2d9-359b-443d-993d-3cc5637107a0")) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule( 'OP_NE', VariableRule("ID"), ConstantRule("e214d2d9-359b-443d-993d-3cc5637107")) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_LIKE', VariableRule("ID"), ConstantRule("e214d2d9")) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_LIKE', VariableRule("ID"), ConstantRule("xxxxxxxx")) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule( 'OP_IN', VariableRule("Category"), ListRule(ConstantRule("Phishing"), ListRule(ConstantRule("Attempt.Login")))) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule( 'OP_IN', VariableRule("Category"), ListRule(ConstantRule("Phishing"), ListRule(ConstantRule("Spam")))) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule('OP_IS', VariableRule("Category"), ListRule(ConstantRule("Attempt.Login"))) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule( 'OP_IS', VariableRule("Category"), ListRule(ConstantRule("Phishing"), ListRule(ConstantRule("Attempt.Login")))) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule('OP_EQ', VariableRule("ConnCount"), IntegerRule(2)) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_EQ', VariableRule("ConnCount"), IntegerRule(4)) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule('OP_NE', VariableRule("ConnCount"), IntegerRule(2)) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule('OP_NE', VariableRule("ConnCount"), IntegerRule(4)) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_GT', VariableRule("ConnCount"), IntegerRule(2)) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule('OP_GT', VariableRule("ConnCount"), IntegerRule(1)) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_GE', VariableRule("ConnCount"), IntegerRule(2)) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_GE', VariableRule("ConnCount"), IntegerRule(1)) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_GE', VariableRule("ConnCount"), IntegerRule(3)) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule('OP_LT', VariableRule("ConnCount"), IntegerRule(2)) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = ComparisonBinOpRule('OP_LT', VariableRule("ConnCount"), IntegerRule(3)) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_LE', VariableRule("ConnCount"), IntegerRule(2)) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_LE', VariableRule("ConnCount"), IntegerRule(3)) self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = ComparisonBinOpRule('OP_LE', VariableRule("ConnCount"), IntegerRule(1)) self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ID == "e214d2d9-359b-443d-993d-3cc5637107a0"') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ID eq "e214d2d9-359b-443d-993d-3cc5637107"') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ID != "e214d2d9-359b-443d-993d-3cc5637107a0"') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ID ne "e214d2d9-359b-443d-993d-3cc5637107"') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ID like "e214d2d9"') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ID LIKE "xxxxxxxx"') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('Category in ["Phishing" , "Attempt.Login"]') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('Category IN ["Phishing" , "Spam"]') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('Category is ["Attempt.Login"]') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('Category IS ["Phishing" , "Attempt.Login"]') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ConnCount == 2') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ConnCount eq 4') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ConnCount != 2') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ConnCount ne 4') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ConnCount > 2') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ConnCount gt 1') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ConnCount >= 2') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ConnCount ge 1') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ConnCount GE 3') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ConnCount < 2') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ConnCount lt 3') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ConnCount <= 2') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ConnCount le 3') self.assertEqual(flt.filter(rule, self.test_msg1), True) rule = psr.parse('ConnCount LE 1') self.assertEqual(flt.filter(rule, self.test_msg1), False) rule = psr.parse('ConnCounts LE 1') self.assertEqual(flt.filter(rule, self.test_msg1), None)
def test_01_current_inspector_filters(self): """ Perform tests of filters currently used in mentat-inspector.py. """ self.maxDiff = None flt = DataObjectFilter() cpl = IDEAFilterCompiler() psr = MentatFilterParser() psr.build() inspection_rules = [{ "filter": "Category in ['Attempt.Login'] and Target.Port in [3389]", "str": '((Category OP_IN ["Attempt.Login"]) OP_AND (Target.Port OP_IN [3389]))', "tests": [[{ "Format": "IDEA0", "ID": "e214d2d9-359b-443d-993d-3cc5637107a0", "Source": [{ "IP4": ["188.14.166.39"] }], "Target": [{ "IP4": ["195.113.165.128/25"], "Port": ["3389"], "Proto": ["tcp", "ssh"] }], "Note": "SSH login attempt", "DetectTime": "2016-06-21 13:08:27Z", "Node": [{ "Type": ["Connection", "Honeypot"], "SW": ["Kippo"], "Name": "cz.uhk.apate.cowrie" }], "Category": ["Attempt.Login"] }, True], [{ "Format": "IDEA0", "ID": "e214d2d9-359b-443d-993d-3cc5637107a0", "Source": [{ "IP4": ["188.14.166.39"] }], "Target": [{ "IP4": ["195.113.165.128/25"], "Port": ["338"], "Proto": ["tcp", "ssh"] }], "Note": "SSH login attempt", "DetectTime": "2016-06-21 13:08:27Z", "Node": [{ "Type": ["Connection", "Honeypot"], "SW": ["Kippo"], "Name": "cz.uhk.apate.cowrie" }], "Category": ["Attempt.Login"] }, False]], }, { "filter": "Category in ['Attempt.Login'] and (Target.Proto in ['telnet'] or Source.Proto in ['telnet'] or Target.Port in [23])", "str": '((Category OP_IN ["Attempt.Login"]) OP_AND ((Target.Proto OP_IN ["telnet"]) OP_OR ((Source.Proto OP_IN ["telnet"]) OP_OR (Target.Port OP_IN [23]))))' }, { "filter": "Category in ['Attempt.Login'] and (Target.Proto in ['ssh'] or Source.Proto in ['ssh'] or Target.Port in [22])", "str": '((Category OP_IN ["Attempt.Login"]) OP_AND ((Target.Proto OP_IN ["ssh"]) OP_OR ((Source.Proto OP_IN ["ssh"]) OP_OR (Target.Port OP_IN [22]))))' }, { "filter": "Category in ['Attempt.Login'] and (Target.Proto in ['sip', 'sip-tls'] or Source.Proto in ['sip', 'sip-tls'] or Target.Port in [5060])", "str": '((Category OP_IN ["Attempt.Login"]) OP_AND ((Target.Proto OP_IN ["sip", "sip-tls"]) OP_OR ((Source.Proto OP_IN ["sip", "sip-tls"]) OP_OR (Target.Port OP_IN [5060]))))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Proto in ['sip', 'sip-tls'] or Source.Proto in ['sip', 'sip-tls'] or Target.Port in [5060])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Proto OP_IN ["sip", "sip-tls"]) OP_OR ((Source.Proto OP_IN ["sip", "sip-tls"]) OP_OR (Target.Port OP_IN [5060]))))' }, { "filter": "Category in ['Attempt.Exploit'] and Target.Port in [23]", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND (Target.Port OP_IN [23]))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Port in [80, 443] or Source.Proto in ['http', 'https', 'http-alt'] or Target.Proto in ['http', 'https', 'http-alt'])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Port OP_IN [80, 443]) OP_OR ((Source.Proto OP_IN ["http", "https", "http-alt"]) OP_OR (Target.Proto OP_IN ["http", "https", "http-alt"]))))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Port in [3306] or Source.Proto in ['mysql'] or Target.Proto in ['mysql'])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Port OP_IN [3306]) OP_OR ((Source.Proto OP_IN ["mysql"]) OP_OR (Target.Proto OP_IN ["mysql"]))))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Port in [445] or Source.Proto in ['microsoft-ds', 'smb'] or Target.Proto in ['microsoft-ds', 'smb'])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Port OP_IN [445]) OP_OR ((Source.Proto OP_IN ["microsoft-ds", "smb"]) OP_OR (Target.Proto OP_IN ["microsoft-ds", "smb"]))))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Port in [135] or Source.Proto in ['loc-srv', 'epmap'] or Target.Proto in ['loc-srv', 'epmap'])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Port OP_IN [135]) OP_OR ((Source.Proto OP_IN ["loc-srv", "epmap"]) OP_OR (Target.Proto OP_IN ["loc-srv", "epmap"]))))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Port in [1900] or Source.Proto in ['upnp', 'ssdp'] or Target.Proto in ['upnp', 'ssdp'])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Port OP_IN [1900]) OP_OR ((Source.Proto OP_IN ["upnp", "ssdp"]) OP_OR (Target.Proto OP_IN ["upnp", "ssdp"]))))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Port in [20, 21, 989, 990] or Source.Proto in ['ftp', 'ftp-data', 'ftps', 'ftps-data'] or Target.Proto in ['ftp', 'ftp-data', 'ftps', 'ftps-data'])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Port OP_IN [20, 21, 989, 990]) OP_OR ((Source.Proto OP_IN ["ftp", "ftp-data", "ftps", "ftps-data"]) OP_OR (Target.Proto OP_IN ["ftp", "ftp-data", "ftps", "ftps-data"]))))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Port in [1433, 1434] or Source.Proto in ['ms-sql-s', 'ms-sql-m'] or Target.Proto in ['ms-sql-s', 'ms-sql-m'])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Port OP_IN [1433, 1434]) OP_OR ((Source.Proto OP_IN ["ms-sql-s", "ms-sql-m"]) OP_OR (Target.Proto OP_IN ["ms-sql-s", "ms-sql-m"]))))' }, { "filter": "Category in ['Attempt.Exploit'] and (Target.Port in [42] or Source.Proto in ['nameserver'] or Target.Proto in ['nameserver'])", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND ((Target.Port OP_IN [42]) OP_OR ((Source.Proto OP_IN ["nameserver"]) OP_OR (Target.Proto OP_IN ["nameserver"]))))' }, { "filter": "Category in ['Attempt.Exploit'] and Node.SW in ['Dionaea']", "str": '((Category OP_IN ["Attempt.Exploit"]) OP_AND (Node.SW OP_IN ["Dionaea"]))' }, { "filter": "Category in ['Availability.DoS', 'Availability.DDoS'] and (Target.Proto in ['dns', 'domain'] or Source.Proto in ['dns', 'domain'] or Target.Port in [53] or Source.Port in [53])", "str": '((Category OP_IN ["Availability.DoS", "Availability.DDoS"]) OP_AND ((Target.Proto OP_IN ["dns", "domain"]) OP_OR ((Source.Proto OP_IN ["dns", "domain"]) OP_OR ((Target.Port OP_IN [53]) OP_OR (Source.Port OP_IN [53])))))' }, { "filter": "Category in ['Availability.DDoS'] and Node.Type in ['Flow'] and Node.Type in ['Statistical']", "str": '((Category OP_IN ["Availability.DDoS"]) OP_AND ((Node.Type OP_IN ["Flow"]) OP_AND (Node.Type OP_IN ["Statistical"])))' }, { "filter": "Category in ['Abusive.Spam'] and Node.SW in ['UCEPROT']", "str": '((Category OP_IN ["Abusive.Spam"]) OP_AND (Node.SW OP_IN ["UCEPROT"]))' }, { "filter": "Category in ['Abusive.Spam'] and Node.SW in ['Fail2Ban', 'IntelMQ']", "str": '((Category OP_IN ["Abusive.Spam"]) OP_AND (Node.SW OP_IN ["Fail2Ban", "IntelMQ"]))' }, { "filter": "Category in ['Vulnerable.Config'] and (Source.Proto in ['qotd'] or Source.Port in [17])", "str": '((Category OP_IN ["Vulnerable.Config"]) OP_AND ((Source.Proto OP_IN ["qotd"]) OP_OR (Source.Port OP_IN [17])))' }, { "filter": "Category in ['Vulnerable.Config'] and Source.Proto in ['ssdp']", "str": '((Category OP_IN ["Vulnerable.Config"]) OP_AND (Source.Proto OP_IN ["ssdp"]))' }, { "filter": "Category in ['Vulnerable.Config'] and (Source.Proto in ['ntp'] or Source.Port in [123])", "str": '((Category OP_IN ["Vulnerable.Config"]) OP_AND ((Source.Proto OP_IN ["ntp"]) OP_OR (Source.Port OP_IN [123])))' }, { "filter": "Category in ['Vulnerable.Config'] and (Source.Proto in ['domain'] or Source.Port in [53])", "str": '((Category OP_IN ["Vulnerable.Config"]) OP_AND ((Source.Proto OP_IN ["domain"]) OP_OR (Source.Port OP_IN [53])))' }, { "filter": "Category in ['Vulnerable.Config'] and (Source.Proto in ['netbios-ns'] or Source.Port in [137])", "str": '((Category OP_IN ["Vulnerable.Config"]) OP_AND ((Source.Proto OP_IN ["netbios-ns"]) OP_OR (Source.Port OP_IN [137])))' }, { "filter": "Category in ['Vulnerable.Config'] and (Source.Proto in ['ipmi'] or Source.Port in [623])", "str": '((Category OP_IN ["Vulnerable.Config"]) OP_AND ((Source.Proto OP_IN ["ipmi"]) OP_OR (Source.Port OP_IN [623])))' }, { "filter": "Category in ['Vulnerable.Config'] and (Source.Proto in ['chargen'] or Source.Port in [19])", "str": '((Category OP_IN ["Vulnerable.Config"]) OP_AND ((Source.Proto OP_IN ["chargen"]) OP_OR (Source.Port OP_IN [19])))' }, { "filter": "Category in ['Anomaly.Traffic']", "str": '(Category OP_IN ["Anomaly.Traffic"])' }, { "filter": "Category in ['Anomaly.Connection'] and Source.Type in ['Booter']", "str": '((Category OP_IN ["Anomaly.Connection"]) OP_AND (Source.Type OP_IN ["Booter"]))' }, { "filter": "Category in ['Intrusion.Botnet'] and Source.Type in ['Botnet']", "str": '((Category OP_IN ["Intrusion.Botnet"]) OP_AND (Source.Type OP_IN ["Botnet"]))' }, { "filter": "Category in ['Recon.Scanning']", "str": '(Category OP_IN ["Recon.Scanning"])' }] for ir in inspection_rules: rule = psr.parse(ir['filter']) rule = cpl.compile(rule) self.assertEqual(str(rule), ir['str']) if 'tests' in ir: for t in ir['tests']: msg_idea = lite.Idea(t[0]) self.assertEqual( [ir['filter'], flt.filter(rule, msg_idea)], [ir['filter'], t[1]])