Exemplo n.º 1
0
    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')))"
        )
Exemplo n.º 2
0
    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))
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
    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)
Exemplo n.º 5
0
    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)
Exemplo n.º 6
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`.")
Exemplo n.º 7
0
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
Exemplo n.º 8
0
    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'))"
        )
Exemplo n.º 9
0
    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))')
Exemplo n.º 10
0
    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))')
Exemplo n.º 11
0
    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))')
Exemplo n.º 12
0
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
Exemplo n.º 13
0
#   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',
Exemplo n.º 14
0
    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)
Exemplo n.º 15
0
    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]])