Пример #1
0
    def range2bdd(min_value, max_value, index, interval=(0, 2**8 - 1)):
        """Static method for construction ROBDD range

        Parameters
        ----------
        min_value : int. the start of the range
        max_value : the end of the range
        index : the index for ROBDD construction variable name
        interval : (int, int). the interval to check (used for recursivity)

        Return
        ------
        Return the corresponding ROBDD
        """
        if interval[0] > max_value or interval[1] < min_value:
            return Robdd.false()

        if interval[0] >= min_value and interval[1] <= max_value:
            return Protocol(interval[0]).toBDD(index, int(math.log(interval[1] + 1 - interval[0], 2)))

        def new_min_interval(inter):
            min_v = inter[0]
            max_v = inter[0] + 2**(int(math.log(inter[1] + 1 - inter[0], 2)) - 1) - 1
            return (min_v, max_v)

        def new_max_interval(inter):
            min_v = inter[0] + 2**(int(math.log(inter[1] + 1 - inter[0], 2)) - 1)
            max_v = inter[1]
            return (min_v, max_v)

        return synthesize(Protocol.range2bdd(min_value, max_value, index, new_min_interval(interval)),
                          Bdd.OR,
                          Protocol.range2bdd(min_value, max_value, index, new_max_interval(interval)))
Пример #2
0
    def _tree_parse_detection(self, tree_path):
        """Detect anomalies given a rooted tree

        Parameters
        ----------
        tree_path : nested list. Rooted tree representation

        Return
        ------
        Return a tuple containing the accepted paquet and a list of detected errors
        """
        error_list = []
        parent = tree_path[0]
        remain = Robdd.false()
        for i in xrange(1, len(tree_path)):
            acl_list = NetworkGraph.NetworkGraph().get_acl_list(
                src=tree_path[i][0], dst=parent)
            # test is leaf
            if len(tree_path[i]) == 1:
                res_remain, res_error = self._distributed_detection(
                    acl_list, Robdd.true(), tree_path[i])
                res_error = []
            else:
                res_remain, res_error = self._tree_parse_detection(
                    tree_path[i])
                error_list += res_error
                res_remain, res_error = self._distributed_detection(
                    acl_list, res_remain, tree_path[i])
            error_list += res_error
            remain = synthesize(remain, Bdd.OR, res_remain)

        return remain, error_list
    def _tree_parse_detection(self, tree_path):
        """Detect anomalies given a rooted tree

        Parameters
        ----------
        tree_path : nested list. Rooted tree representation

        Return
        ------
        Return a tuple containing the accepted packets and a list of detected errors
        """
        error_list = []
        parent = tree_path[0]
        remain = Robdd.false()
        for i in xrange(1, len(tree_path)):
            acl_list = NetworkGraph.NetworkGraph().get_acl_list(src=tree_path[i][0], dst=parent)
            # test is leaf
            if len(tree_path[i]) == 1:
                res_remain, res_error = self._distributed_detection(acl_list, Robdd.true(), tree_path[i])
                res_error = []
            else:
                res_remain, res_error = self._tree_parse_detection(tree_path[i])
                error_list += res_error
                res_remain, res_error = self._distributed_detection(acl_list, res_remain, tree_path[i])
            error_list += res_error
            remain = synthesize(remain, Bdd.OR, res_remain)

        return remain, error_list
Пример #4
0
    def range2bdd(min_value, max_value, index, interval=(0, 2**8 - 1)):
        """Static method for construction ROBDD range

        Parameters
        ----------
        min_value : int. the start of the range
        max_value : the end of the range
        index : the index for ROBDD construction variable name
        interval : (int, int). the interval to check (used for recursivity)

        Return
        ------
        Return the corresponding ROBDD
        """
        if interval[0] > max_value or interval[1] < min_value:
            return Robdd.false()

        if interval[0] >= min_value and interval[1] <= max_value:
            return Protocol(interval[0]).toBDD(index, int(math.log(interval[1] + 1 - interval[0], 2)))

        def new_min_interval(inter):
            min_v = inter[0]
            max_v = inter[0] + 2**(int(math.log(inter[1] + 1 - inter[0], 2)) - 1) - 1
            return (min_v, max_v)

        def new_max_interval(inter):
            min_v = inter[0] + 2**(int(math.log(inter[1] + 1 - inter[0], 2)) - 1)
            max_v = inter[1]
            return (min_v, max_v)

        return synthesize(Protocol.range2bdd(min_value, max_value, index, new_min_interval(interval)),
                          Bdd.OR,
                          Protocol.range2bdd(min_value, max_value, index, new_max_interval(interval)))
Пример #5
0
    def toBDD(self):
        """Compute rhe ROBDD of the rule if rule_robdd is None else return rule_robdd

        Return
        ------
        Return the ROBDD
        """
        if self.rule_robdd is None:
            rule_robdd = Robdd.true()
            protocol_bdd = Robdd.false()
            ip_src_bdd = Robdd.false()
            port_src_bdd = Robdd.false()
            ip_dst_bdd = Robdd.false()
            port_dst_bdd = Robdd.false()

            for i in self.protocol:
                protocol_bdd = synthesize(protocol_bdd, Bdd.OR, i.toBDD(0))
            if self.protocol:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, protocol_bdd)

            for i in self.ip_source:
                ip_src_bdd = synthesize(ip_src_bdd, Bdd.OR, i.toBDD(8))
            if self.ip_source:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, ip_src_bdd)

            for i in self.port_source:
                port_src_bdd = synthesize(port_src_bdd, Bdd.OR, i.toBDD(40))
            if self.port_source:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, port_src_bdd)

            for i in self.ip_dest:
                ip_dst_bdd = synthesize(ip_dst_bdd, Bdd.OR, i.toBDD(56))
            if self.ip_dest:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, ip_dst_bdd)

            for i in self.port_dest:
                port_dst_bdd = synthesize(port_dst_bdd, Bdd.OR, i.toBDD(88))
            if self.port_dest:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, port_dst_bdd)

            self.rule_robdd = rule_robdd

        return self.rule_robdd
Пример #6
0
    def toBDD(self):
        """Compute rhe ROBDD of the rule if rule_robdd is None else return rule_robdd

        Return
        ------
        Return the ROBDD
        """
        if self.rule_robdd is None:
            rule_robdd = Robdd.true()
            protocol_bdd = Robdd.false()
            ip_src_bdd = Robdd.false()
            port_src_bdd = Robdd.false()
            ip_dst_bdd = Robdd.false()
            port_dst_bdd = Robdd.false()

            for i in self.protocol:
                protocol_bdd = synthesize(protocol_bdd, Bdd.OR, i.toBDD(0))
            if self.protocol:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, protocol_bdd)

            for i in self.ip_source:
                ip_src_bdd = synthesize(ip_src_bdd, Bdd.OR, i.toBDD(8))
            if self.ip_source:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, ip_src_bdd)

            for i in self.port_source:
                port_src_bdd = synthesize(port_src_bdd, Bdd.OR, i.toBDD(40))
            if self.port_source:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, port_src_bdd)

            for i in self.ip_dest:
                ip_dst_bdd = synthesize(ip_dst_bdd, Bdd.OR, i.toBDD(56))
            if self.ip_dest:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, ip_dst_bdd)

            for i in self.port_dest:
                port_dst_bdd = synthesize(port_dst_bdd, Bdd.OR, i.toBDD(88))
            if self.port_dest:
                rule_robdd = synthesize(rule_robdd, Bdd.AND, port_dst_bdd)

            self.rule_robdd = rule_robdd

        return self.rule_robdd
Пример #7
0
    def toBDD(self, index):
        """Compute the corresponding ROBDD of the Ip

        Parameters
        ----------
        index : int. The start point of the variable name

        Return
        ------
        Return the corresponding ROBDD
        """
        # Ip: 32 bits
        res = Robdd.true()
        ip_size = 32
        for i in range(ip_size - (32 - Ip.MaskToCidr(self.mask))):
            if (self.ip >> (ip_size - i - 1)) & 1:
                res = synthesize(res, Bdd.AND, Robdd.make_x(index + i))
            else:
                res = synthesize(res, Bdd.AND, Robdd.make_not_x(index + i))
        return res
Пример #8
0
    def toBDD(self, index):
        """Compute the corresponding ROBDD of the Ip

        Parameters
        ----------
        index : int. The start point of the variable name

        Return
        ------
        Return the corresponding ROBDD
        """
        # Ip: 32 bits
        res = Robdd.true()
        ip_size = 32
        for i in range(ip_size - (32 - Ip.MaskToCidr(self.mask))):
            if (self.ip >> (ip_size - i - 1)) & 1:
                res = synthesize(res, Bdd.AND, Robdd.make_x(index + i))
            else:
                res = synthesize(res, Bdd.AND, Robdd.make_not_x(index + i))
        return res
Пример #9
0
    def toBDD(self, index, limit=0):
        """Compute the ROBDD.

        Parameters
        ----------
        index : int. Used for ROBDD variable index
        limit : int (optional, default=0). The limit bit used for range representation.

        Return
        ------
        Return the comuted ROBDD
        """
        # Port: 16 bits
        res = Robdd.true()
        port_size = 16
        for i in range(port_size - limit):
            if (self.port >> (port_size - i - 1)) & 1:
                res = synthesize(res, Bdd.AND, Robdd.make_x(index + i))
            else:
                res = synthesize(res, Bdd.AND, Robdd.make_not_x(index + i))

        return res
Пример #10
0
    def toBDD(self, index, limit=0):
        """Construct the ROBDD.

        Parameters
        ----------
        index : int. Used for ROBDD variable index
        limit : int (optional, default=0). The limit bit used for range representation

        Return
        ------
        Return the computed ROBDD.
        """
        # Protocol : 8 bits
        res = Robdd.true()
        protocol_size = 8
        for i in range(protocol_size - limit):
            if (self.protocol >> (protocol_size - i - 1)) & 1:
                res = synthesize(res, Bdd.AND, Robdd.make_x(index + i))
            else:
                res = synthesize(res, Bdd.AND, Robdd.make_not_x(index + i))

        return res
Пример #11
0
    def toBDD(self, index, limit=0):
        """Compute the ROBDD.

        Parameters
        ----------
        index : int. Used for ROBDD variable index
        limit : int (optional, default=0). The limit bit used for range representation.

        Return
        ------
        Return the comuted ROBDD
        """
        # Port: 16 bits
        res = Robdd.true()
        port_size = 16
        for i in range(port_size - limit):
            if (self.port >> (port_size - i - 1)) & 1:
                res = synthesize(res, Bdd.AND, Robdd.make_x(index + i))
            else:
                res = synthesize(res, Bdd.AND, Robdd.make_not_x(index + i))

        return res
Пример #12
0
    def toBDD(self, index, limit=0):
        """Construct the ROBDD.

        Parameters
        ----------
        index : int. Used for ROBDD variable index
        limit : int (optional, default=0). The limit bit used for range representation

        Return
        ------
        Return the computed ROBDD.
        """
        # Protocol : 8 bits
        res = Robdd.true()
        protocol_size = 8
        for i in range(protocol_size - limit):
            if (self.protocol >> (protocol_size - i - 1)) & 1:
                res = synthesize(res, Bdd.AND, Robdd.make_x(index + i))
            else:
                res = synthesize(res, Bdd.AND, Robdd.make_not_x(index + i))

        return res
Пример #13
0
def _detect_anomaly(acl, stack, parsed_rule, visited, remain, accept, deny, result_queue, processed_id_rules, deep_search):
    """Recursive algorithm for ACL graph traversal.
    This recursive algorithm construct the list of all possible list of rule for the ACL chained model.
    Then it launch the _classify_anomaly function on each rule and try to detect anomaly if any.

    Parameters
    ----------
    acl : ACL. The acl to inspect.
    stack : list of Rule list. A stack of rule list.
    parsed_rule : Rule list. A list of parse rule.
    visisted : ACL list. List of visited ACL.
    remain : ROBDD. Remain ROBDD.
    accept : ROBDD. Accept ROBDD.
    deny : ROBDD. Deny ROBDD.
    result_queue : list. List of error.
    processed_id_rules : list. List of processed rules.
    deep_search : Bool. If true find blamed rules.
    """
    if acl not in visited:
        visited.append(acl)
        stack.append(list(acl.rules))

    while stack:
        rule_list = stack[-1]
        while rule_list:
            rule = rule_list.pop(0)
            processed_id_rules.put(rule.identifier)
            _classify_anomaly(rule, parsed_rule, remain, accept, deny, result_queue, deep_search)
            parsed_rule.append([rule, rule.action.chain, rule.toBDD()])
            if rule.action.is_chained() or rule.action.is_return():
                # a = accept & True -> copy of accept
                a = synthesize(accept, Bdd.AND, Robdd.true())
                # d = D ∪ (R ∩ ¬P)
                d = synthesize(deny, Bdd.OR, synthesize(remain, Bdd.AND, negate_bdd(rule.toBDD())))
                # r = I ∩ ¬(a ∪ d)
                r = synthesize(Robdd.true(), Bdd.AND, negate_bdd(synthesize(a, Bdd.OR, d)))
                # copy stack of rules
                stack_copy = [list(i) for i in stack]
                visited_copy = list(visited)
                parsed_rule_copy = list(parsed_rule)
                parsed_rule_copy[-1] = [parsed_rule_copy[-1][0], False, negate_bdd(parsed_rule_copy[-1][0].toBDD())]

                if rule.action.is_chained():
                    _detect_anomaly(rule.action.chain, stack_copy, parsed_rule_copy, visited_copy, r, a, d,
                                    result_queue, processed_id_rules, deep_search)
                else:
                    # remove current stack rule
                    stack_copy.pop()
                    visited_copy.pop()
                    # special case RETURN in first ACL
                    if not visited_copy:
                        stack_copy = [[acl.rules[-1]]]
                        visited_copy.append(acl)
                    _detect_anomaly(visited_copy[-1], stack_copy, parsed_rule_copy, visited_copy, r, a, d,
                                    result_queue, processed_id_rules, deep_search)
            else:  # rule is Permit or Deny
                if rule.action.chain:
                    # accept = A ∪ (R ∩ P)
                    accept = synthesize(accept, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD()))
                else:
                    # d = D ∪ (R ∩ P)
                    deny = synthesize(deny, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD()))
            # remain = I ∩ ¬(a ∪ d)
            remain = synthesize(Robdd.true(), Bdd.AND, negate_bdd(synthesize(accept, Bdd.OR, deny)))
        stack.pop()
        visited.pop()
Пример #14
0
def _detect_anomaly(rules, result_queue, processed_id_rules, deep_search):
    """Detect anomaly of the given rule set.
    This algorithm is derived from the algorithm of Fireman.
    It uses ROBDD to compare each rules.
    The complexity of this algorithm is in O(n).

    For more informations read :
    - Firewall Policy Advisor for Anomaly Detection and rules analysis,
    http://www.arc.uncc.edu/pubs/im03-cr.pdf
    - FIREMAN : A Toolkit for FIREwall Modeling and ANalysis,
    http://www.cs.ucdavis.edu/~su/publications/fireman.pdf

    Parameters
    ----------
    rules : Rule list. The list of rule to inspect
    result_queue : multiprocessing Queue. A queue to put errors
    """
    remain = Robdd.true()
    accept = Robdd.false()
    deny = Robdd.false()
    error_list = deque()
    error_list_append = error_list.append

    for rule in rules:
        processed_id_rules.put(rule.identifier)
        error_rules = deque()
        # Pj ⊆ Rj
        if compare_bdd(rule.toBDD(), Bdd.IMPL, remain):
            pass
        else:
            # Pj ∩ Rj = ∅
            if not compare_bdd(rule.toBDD(), Bdd.AND, remain):
                # Pj ⊆ Dj
                if compare_bdd(rule.toBDD(), Bdd.IMPL, (deny if rule.action else accept)):
                    if deep_search:
                        for r in rules:
                            if r == rule:
                                break
                            # ∀ x < j, ∃ <Px, deny> such that Px ∩ Pj != ∅
                            if r.action != rule.action and compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()):
                                error_rules.append(r)
                    error_list_append(AnomalyError.error_message(ErrorType.INT_MASK_SHADOW, ErrorType.ERROR, rule, error_rules))
                # Pj ∩ Dj = ∅
                elif not compare_bdd(rule.toBDD(), Bdd.AND, (deny if rule.action else accept)):
                    if deep_search:
                        for r in rules:
                            if r == rule:
                                break
                            # ∀ x < j, ∃ <Px, accept> such that Px ∩ Pj != ∅
                            if r.action == rule.action and compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()):
                                error_rules.append(r)
                    error_list_append(AnomalyError.error_message(ErrorType.INT_MASK_REDUNDANT, ErrorType.ERROR, rule, error_rules))
                else:
                    if deep_search:
                        for r in rules:
                            if r == rule:
                                break
                            # ∀ x < j, ∃ Px such that Px ∩ Pj != ∅
                            if compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()):
                                error_rules.append(r)
                    error_list_append(AnomalyError.error_message(ErrorType.INT_MASK_REDUNDANT_CORRELATION, ErrorType.ERROR, rule, error_rules))
            else:
                error_redudant = deque()
                error_generalization = deque()
                if deep_search:
                    # if deep search try to distinguish overlap of generalization or redundancy
                    for r in rules:
                        if r == rule:
                            break
                        # ∀ x < j, ∃ <Px, deny> such that Px ⊆ Pj
                        if r.action != rule.action and compare_bdd(r.toBDD(), Bdd.IMPL, rule.toBDD()):
                            error_generalization.append(r)
                        # ∀ x < j, ∃ <Px, accept> such that Px ⊆ Pj
                        elif r.action == rule.action and compare_bdd(r.toBDD(), Bdd.IMPL, rule.toBDD()):
                            error_redudant.append(r)
                        elif compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()):
                            error_rules.append(r)
                    if error_redudant:
                        error_list_append(AnomalyError.error_message(ErrorType.INT_PART_REDUNDANT, ErrorType.ERROR, rule, error_redudant))
                    if error_generalization:
                        error_list_append(AnomalyError.error_message(ErrorType.INT_PART_GENERALIZATION, ErrorType.WARNING, rule, error_generalization))
                    if error_rules:
                        error_list_append(AnomalyError.error_message(ErrorType.INT_PART_CORRELATION, ErrorType.WARNING, rule, error_rules))
                else:
                    error_list_append(AnomalyError.error_message(ErrorType.INT_PART_CORRELATION, ErrorType.WARNING, rule, error_rules))

        if rule.action:
            accept = synthesize(accept, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD()))
        else:
            deny = synthesize(deny, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD()))
        remain = synthesize(Robdd.true(), Bdd.AND, negate_bdd(synthesize(accept, Bdd.OR, deny)))

    result_queue.put(error_list)
Пример #15
0
 def is_subset(self, rule, test_rule):
     return len(synthesize(test_rule.toBDD(), Bdd.IMPL, rule.toBDD()).items) <= 2
Пример #16
0
def is_subset(rule, test_rule):
    """return True if rule is a subset of test_rule, false otherwise (use ROBDD)"""
    return len(synthesize(test_rule.toBDD(), Bdd.IMPL, rule.toBDD()).items) <= 2
Пример #17
0
def _detect_anomaly(rules, result_queue, processed_id_rules, deep_search):
    """Detect anomaly of the given rule set.
    This algorithm is derived from the algorithm of Fireman.
    It uses ROBDD to compare each rules.
    The complexity of this algorithm is in O(n).

    For more informations read :
    - Firewall Policy Advisor for Anomaly Detection and rules analysis,
    http://www.arc.uncc.edu/pubs/im03-cr.pdf
    - FIREMAN : A Toolkit for FIREwall Modeling and ANalysis,
    http://www.cs.ucdavis.edu/~su/publications/fireman.pdf

    Parameters
    ----------
    rules : Rule list. The list of rule to inspect
    result_queue : multiprocessing Queue. A queue to put errors
    """
    remain = Robdd.true()
    accept = Robdd.false()
    deny = Robdd.false()
    error_list = deque()
    error_list_append = error_list.append

    for rule in rules:
        processed_id_rules.put(rule.identifier)
        error_rules = deque()
        # Pj ⊆ Rj
        if compare_bdd(rule.toBDD(), Bdd.IMPL, remain):
            pass
        else:
            # Pj ∩ Rj = ∅
            if not compare_bdd(rule.toBDD(), Bdd.AND, remain):
                # Pj ⊆ Dj
                if compare_bdd(rule.toBDD(), Bdd.IMPL,
                               (deny if rule.action else accept)):
                    if deep_search:
                        for r in rules:
                            if r == rule:
                                break
                            # ∀ x < j, ∃ <Px, deny> such that Px ∩ Pj != ∅
                            if r.action != rule.action and compare_bdd(
                                    r.toBDD(), Bdd.AND, rule.toBDD()):
                                error_rules.append(r)
                    error_list_append(
                        AnomalyError.error_message(ErrorType.INT_MASK_SHADOW,
                                                   ErrorType.ERROR, rule,
                                                   error_rules))
                # Pj ∩ Dj = ∅
                elif not compare_bdd(rule.toBDD(), Bdd.AND,
                                     (deny if rule.action else accept)):
                    if deep_search:
                        for r in rules:
                            if r == rule:
                                break
                            # ∀ x < j, ∃ <Px, accept> such that Px ∩ Pj != ∅
                            if r.action == rule.action and compare_bdd(
                                    r.toBDD(), Bdd.AND, rule.toBDD()):
                                error_rules.append(r)
                    error_list_append(
                        AnomalyError.error_message(
                            ErrorType.INT_MASK_REDUNDANT, ErrorType.ERROR,
                            rule, error_rules))
                else:
                    if deep_search:
                        for r in rules:
                            if r == rule:
                                break
                            # ∀ x < j, ∃ Px such that Px ∩ Pj != ∅
                            if compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()):
                                error_rules.append(r)
                    error_list_append(
                        AnomalyError.error_message(
                            ErrorType.INT_MASK_REDUNDANT_CORRELATION,
                            ErrorType.ERROR, rule, error_rules))
            else:
                error_redudant = deque()
                error_generalization = deque()
                if deep_search:
                    # if deep search try to distinguish overlap of generalization or redundancy
                    for r in rules:
                        if r == rule:
                            break
                        # ∀ x < j, ∃ <Px, deny> such that Px ⊆ Pj
                        if r.action != rule.action and compare_bdd(
                                r.toBDD(), Bdd.IMPL, rule.toBDD()):
                            error_generalization.append(r)
                        # ∀ x < j, ∃ <Px, accept> such that Px ⊆ Pj
                        elif r.action == rule.action and compare_bdd(
                                r.toBDD(), Bdd.IMPL, rule.toBDD()):
                            error_redudant.append(r)
                        elif compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()):
                            error_rules.append(r)
                    if error_redudant:
                        error_list_append(
                            AnomalyError.error_message(
                                ErrorType.INT_PART_REDUNDANT, ErrorType.ERROR,
                                rule, error_redudant))
                    if error_generalization:
                        error_list_append(
                            AnomalyError.error_message(
                                ErrorType.INT_PART_GENERALIZATION,
                                ErrorType.WARNING, rule, error_generalization))
                    if error_rules:
                        error_list_append(
                            AnomalyError.error_message(
                                ErrorType.INT_PART_CORRELATION,
                                ErrorType.WARNING, rule, error_rules))
                else:
                    error_list_append(
                        AnomalyError.error_message(
                            ErrorType.INT_PART_CORRELATION, ErrorType.WARNING,
                            rule, error_rules))

        if rule.action:
            accept = synthesize(accept, Bdd.OR,
                                synthesize(remain, Bdd.AND, rule.toBDD()))
        else:
            deny = synthesize(deny, Bdd.OR,
                              synthesize(remain, Bdd.AND, rule.toBDD()))
        remain = synthesize(Robdd.true(), Bdd.AND,
                            negate_bdd(synthesize(accept, Bdd.OR, deny)))

    result_queue.put(error_list)
Пример #18
0
def _detect_anomaly(
    acl, stack, parsed_rule, visited, remain, accept, deny, result_queue, processed_id_rules, deep_search
):
    """Recursive algorithm for ACL graph traversal.
    This recursive algorithm construct the list of all possible list of rule for the ACL chained model.
    Then it launch the _classify_anomaly function on each rule and try to detect anomaly if any.

    Parameters
    ----------
    acl : ACL. The acl to inspect.
    stack : list of Rule list. A stack of rule list.
    parsed_rule : Rule list. A list of parse rule.
    visisted : ACL list. List of visited ACL.
    remain : ROBDD. Remain ROBDD.
    accept : ROBDD. Accept ROBDD.
    deny : ROBDD. Deny ROBDD.
    result_queue : list. List of error.
    processed_id_rules : list. List of processed rules.
    deep_search : Bool. If true find blamed rules.
    """
    if acl not in visited:
        visited.append(acl)
        stack.append(list(acl.rules))

    while stack:
        rule_list = stack[-1]
        while rule_list:
            rule = rule_list.pop(0)
            processed_id_rules.put(rule.identifier)
            _classify_anomaly(rule, parsed_rule, remain, accept, deny, result_queue, deep_search)
            parsed_rule.append([rule, rule.action.chain, rule.toBDD()])
            if rule.action.is_chained() or rule.action.is_return():
                # a = accept & True -> copy of accept
                a = synthesize(accept, Bdd.AND, Robdd.true())
                # d = D ∪ (R ∩ ¬P)
                d = synthesize(deny, Bdd.OR, synthesize(remain, Bdd.AND, negate_bdd(rule.toBDD())))
                # r = I ∩ ¬(a ∪ d)
                r = synthesize(Robdd.true(), Bdd.AND, negate_bdd(synthesize(a, Bdd.OR, d)))
                # copy stack of rules
                stack_copy = [list(i) for i in stack]
                visited_copy = list(visited)
                parsed_rule_copy = list(parsed_rule)
                parsed_rule_copy[-1] = [parsed_rule_copy[-1][0], False, negate_bdd(parsed_rule_copy[-1][0].toBDD())]

                if rule.action.is_chained():
                    _detect_anomaly(
                        rule.action.chain,
                        stack_copy,
                        parsed_rule_copy,
                        visited_copy,
                        r,
                        a,
                        d,
                        result_queue,
                        processed_id_rules,
                        deep_search,
                    )
                else:
                    # remove current stack rule
                    stack_copy.pop()
                    visited_copy.pop()
                    # special case RETURN in first ACL
                    if not visited_copy:
                        stack_copy = [[acl.rules[-1]]]
                        visited_copy.append(acl)
                    _detect_anomaly(
                        visited_copy[-1],
                        stack_copy,
                        parsed_rule_copy,
                        visited_copy,
                        r,
                        a,
                        d,
                        result_queue,
                        processed_id_rules,
                        deep_search,
                    )
            else:  # rule is Permit or Deny
                if rule.action.chain:
                    # accept = A ∪ (R ∩ P)
                    accept = synthesize(accept, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD()))
                else:
                    # d = D ∪ (R ∩ P)
                    deny = synthesize(deny, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD()))
            # remain = I ∩ ¬(a ∪ d)
            remain = synthesize(Robdd.true(), Bdd.AND, negate_bdd(synthesize(accept, Bdd.OR, deny)))
        stack.pop()
        visited.pop()
Пример #19
0
    def _distributed_detection(self, acl_list, remain, tree_path):
        """Detection method for a given acl with a given remain ROBDD.
        This algorithm is derived from the algorithm of Fireman.

        For more informations read :
        - Firewall Policy Advisor for Anomaly Detection and rules analysis,
        http://www.arc.uncc.edu/pubs/im03-cr.pdf
        - FIREMAN : A Toolkit for FIREwall Modeling and ANalysis,
        http://www.cs.ucdavis.edu/~su/publications/fireman.pdf

        Parameters
        ----------
        acl : Rule list. The rule list to test
        remain : ROBDD. The remaining ROBDD

        Return
        ------
        Return a tuple of remaining rules and the list error found in this context
        """
        accept_robdd_list = []
        error_list = deque()
        error_list_append = error_list.append

        for acl in acl_list:
            for rule_path in acl.get_rules_path():
                accept = Robdd.false()
                deny = Robdd.false()
                if self.cancel:
                    break
                for rule, action in rule_path:
                    if self.cancel:
                        break
                    Gtk.Gtk_Main.Gtk_Main().update_progress_bar(1)
                    Gtk.Gtk_Main.Gtk_Main().update_interface()
                    error_rules = []
                    rule_action = rule.action.chain if isinstance(
                        rule.action.chain, bool) else action
                    if rule_action:
                        # P ⊆ I
                        if compare_bdd(rule.toBDD(), Bdd.IMPL, remain):
                            pass
                        # P ⊆ ¬I
                        elif compare_bdd(rule.toBDD(), Bdd.IMPL,
                                         negate_bdd(remain)):
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, deny> such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(
                                    rule, Bdd.AND, False, tree_path)
                            error_list_append(
                                AnomalyError.error_message(
                                    ErrorType.DIST_SHADOW, ErrorType.ERROR,
                                    rule, error_rules))
                        # P ∩ I != ∅
                        else:
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ Px such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(
                                    rule, Bdd.AND, None, tree_path)
                            error_list_append(
                                AnomalyError.error_message(
                                    ErrorType.DIST_CORRELATE,
                                    ErrorType.WARNING, rule, error_rules))
                    else:
                        # P ⊆ I
                        if compare_bdd(rule.toBDD(), Bdd.IMPL, remain):
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, accept> such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(
                                    rule, Bdd.AND, True, tree_path)
                            error_list_append(
                                AnomalyError.error_message(
                                    ErrorType.DIST_RAISED, ErrorType.WARNING,
                                    rule, error_rules))
                        # P ⊆ ¬I
                        elif compare_bdd(rule.toBDD(), Bdd.IMPL,
                                         negate_bdd(remain)):
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, deny> such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(
                                    rule, Bdd.AND, False, tree_path)
                            error_list_append(
                                AnomalyError.error_message(
                                    ErrorType.DIST_REDUNDANT,
                                    ErrorType.WARNING, rule, error_rules))
                        # P ∩ I != ∅
                        else:
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(
                                    rule, Bdd.AND, None, tree_path)
                            error_list_append(
                                AnomalyError.error_message(
                                    ErrorType.DIST_CORRELATE,
                                    ErrorType.WARNING, rule, error_rules))

                    # update value
                    if rule.action.is_chained() or rule.action.is_return():
                        if action:
                            # D = D ∪ ¬(A ∪ P) = D ∪ (¬A ∩ ¬P)
                            deny = synthesize(
                                deny, Bdd.OR,
                                negate_bdd(
                                    synthesize(accept, Bdd.OR, rule.toBDD())))
                        else:
                            # D = D ∪ (¬A ∩ P)
                            deny = synthesize(
                                deny, Bdd.OR,
                                synthesize(negate_bdd(accept), Bdd.AND,
                                           rule.toBDD()))
                    else:
                        if rule.action.chain:
                            # A = A ∪ (¬D ∩ P)
                            accept = synthesize(
                                accept, Bdd.OR,
                                synthesize(negate_bdd(deny), Bdd.AND,
                                           rule.toBDD()))
                        else:
                            # D = D ∪ (¬A ∩ P)
                            deny = synthesize(
                                deny, Bdd.OR,
                                synthesize(negate_bdd(accept), Bdd.AND,
                                           rule.toBDD()))
                accept_robdd_list.append(accept)

        res_accept = Robdd.false()
        for a in accept_robdd_list:
            res_accept = synthesize(res_accept, Bdd.OR, a)

        return res_accept, error_list
    def _distributed_detection(self, acl_list, remain, tree_path):
        """Detection method for a given acl with a given remain ROBDD.
        This algorithm is derived from the algorithm of Fireman.

        For more informations read :
        - Firewall Policy Advisor for Anomaly Detection and rules analysis,
        http://www.arc.uncc.edu/pubs/im03-cr.pdf
        - FIREMAN : A Toolkit for FIREwall Modeling and ANalysis,
        http://www.cs.ucdavis.edu/~su/publications/fireman.pdf

        Parameters
        ----------
        acl : Rule list. The rule list to test
        remain : ROBDD. The remaining ROBDD

        Return
        ------
        Return a tuple of remaining rules and the list error found in this context
        """
        accept_robdd_list = []
        error_list = deque()
        error_list_append = error_list.append

        for acl in acl_list:
            for rule_path in acl.get_rules_path():
                accept = Robdd.false()
                deny = Robdd.false()
                if self.cancel:
                    break
                for rule, action in rule_path:
                    if self.cancel:
                        break
                    Gtk.Gtk_Main.Gtk_Main().update_progress_bar(1)
                    Gtk.Gtk_Main.Gtk_Main().update_interface()
                    error_rules = []
                    rule_action = rule.action.chain if isinstance(rule.action.chain, bool) else action
                    if rule_action:
                        # P ⊆ I
                        if compare_bdd(rule.toBDD(), Bdd.IMPL, remain):
                            pass
                        # P ⊆ ¬I
                        elif compare_bdd(rule.toBDD(), Bdd.IMPL, negate_bdd(remain)):
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, deny> such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(rule, Bdd.AND, False, tree_path)
                            error_list_append(
                                AnomalyError.error_message(ErrorType.DIST_SHADOW, ErrorType.ERROR, rule, error_rules))
                        # P ∩ I != ∅
                        else:
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ Px such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(rule, Bdd.AND, None, tree_path)
                            error_list_append(
                                AnomalyError.error_message(ErrorType.DIST_CORRELATE, ErrorType.WARNING, rule, error_rules))
                    else:
                        # P ⊆ I
                        if compare_bdd(rule.toBDD(), Bdd.IMPL, remain):
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, accept> such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(rule, Bdd.AND, True, tree_path)
                            error_list_append(
                                AnomalyError.error_message(ErrorType.DIST_RAISED, ErrorType.WARNING, rule, error_rules))
                        # P ⊆ ¬I
                        elif compare_bdd(rule.toBDD(), Bdd.IMPL, negate_bdd(remain)):
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, deny> such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(rule, Bdd.AND, False, tree_path)
                            error_list_append(
                                AnomalyError.error_message(ErrorType.DIST_REDUNDANT, ErrorType.WARNING, rule, error_rules))
                        # P ∩ I != ∅
                        else:
                            if self.deep_search:
                                # ∀ ACLx < ACLj, ∀ x ∈ ACLx such that Px ∩ Pj != ∅
                                error_rules = self.search_rules(rule, Bdd.AND, None, tree_path)
                            error_list_append(
                                AnomalyError.error_message(ErrorType.DIST_CORRELATE, ErrorType.WARNING, rule, error_rules))

                    # update value
                    if rule.action.is_chained() or rule.action.is_return():
                        if action:
                            # D = D ∪ ¬(A ∪ P) = D ∪ (¬A ∩ ¬P)
                            deny = synthesize(deny, Bdd.OR, negate_bdd(synthesize(accept, Bdd.OR, rule.toBDD())))
                        else:
                            # D = D ∪ (¬A ∩ P)
                            deny = synthesize(deny, Bdd.OR, synthesize(negate_bdd(accept), Bdd.AND, rule.toBDD()))
                    else:
                        if rule.action.chain:
                            # A = A ∪ (¬D ∩ P)
                            accept = synthesize(accept, Bdd.OR, synthesize(negate_bdd(deny), Bdd.AND, rule.toBDD()))
                        else:
                            # D = D ∪ (¬A ∩ P)
                            deny = synthesize(deny, Bdd.OR, synthesize(negate_bdd(accept), Bdd.AND, rule.toBDD()))
                accept_robdd_list.append(accept)

        res_accept = Robdd.false()
        for a in accept_robdd_list:
            res_accept = synthesize(res_accept, Bdd.OR, a)

        return res_accept, error_list