예제 #1
0
    def attack(self, block):
        """Attack a given Range Query with a distinguishable first block

        This function can only be used under specific circumstances, which is why it is not the default function.
        To use it, change the Dictionary of the getAttackerFor-function in DRQPatternAttack.py to point to
        DFBPatternBRQ instead of DFBPatternPRQ, but be aware that it will not always work on small data sets.

        @param fb: The first block, as set
        @param rq: The remaining range query, as set
        @return: List of possible results
        """
        fb, rq = block
        res = []
        suspected_n = float(len(fb))
        rq.update(fb)
        rqlen = len(rq)
        pattern_length_max = math.ceil(rqlen / suspected_n)
        pattern_length_max += 2 * math.ceil(pattern_length_max / suspected_n)
        # Increase maximum pattern length, because duplicates could lead to a miscalculation of up to floor(real_pattern_length/real_N).
        # We are using ceil() to avoid border cases where the real M would lead to x in that calculation, while our detected M
        # only leads to x-1. Those cases would be few and far between, considering the chances of actually getting so many duplicates,
        # but nevertheless, they should be dealt with.
        pattern_length_min = math.floor(rqlen / (suspected_n+1))
        for key in fb: # Iterate through all elements of the first block
            if DB.isValidTarget(key) and (pattern_length_min <= DB.getPatternLengthForHost(key) <= pattern_length_max):
                # if the current element is a beginning of a pattern with the correct length...
                if DB.getPatternForHost(key) <= rq: # Check if the pattern is a subset of the remaining range query.
                    res.append(key)
        return res
예제 #2
0
    def generateBaseDRQ(self, domain):
        """Generator for Basic DNS Range Queries (randomly generated query sets)

        Queries are unique inside their respective sets, but may appear more than once across different
        query blocks.

        @param domain: Domain for which a DNS Range Query should be generated
        @return: List of Sets, in order, each set representing a query block
        """
        if not DB.isValidTarget(domain):
            Error.printErrorAndExit(domain + " is not a valid target")
        patlen = DB.getPatternLengthForHost(domain)
        block = [set()]
        pattern = DB.getPatternForHost(domain) # Get the actual pattern of the target
        randoms = DB.getRandomHosts((Config.RQSIZE-1)*len(pattern)) # Get random hosts (dummies)
        pattern.remove(domain)
        block[0].add(domain)
        i = 1
        for subquery in pattern: # Create the blocks that will hold dummies and actual queries
            block.append(set())
            block[i].add(subquery) # Add the actual query to its respective block
            i += 1
        for query, index in zip(randoms, cycle(range(patlen))): 
            # distribute the randomly chosen dummy queries as evenly as possible across the blocks
            block[index].add(query)
        return block
예제 #3
0
    def attack(self, rq):
        """Attack a given Range Query using the assumption from the class description.

        @param rq: A Range Query, as returned by generate.DRQ
        @return: list of possible results
        """
        res = []
        for element in rq: # Iterate through all elements (queries) of the given range query
            if DB.isValidTarget(element): # If the current element is the beginning of a pattern...
                # This checks if the pattern of the current element is a subset of the range query
                inter = rq & DB.getPatternForHost(element) 
                if len(inter) == DB.getPatternLengthForHost(element):
                    res.append(element)
        return res
예제 #4
0
    def attack(self, block):
        """Attack a given Range Query with a distinguishable first block

        @param fb: The first block, as set
        @param rq: The remaining range query, as set
        @return: List of possible results
        """
        fb, rq = block
        res = []
        rq.update(fb)
        for key in fb: # Iterate through all queries in the first block
            if DB.isValidTarget(key): # If the current query is a valid beginning of a pattern...
                if DB.getPatternForHost(key) <= rq: # Check if the pattern is a subset of the second block.
                    res.append(key)
        return res
예제 #5
0
    def attack(self, blocklist):
        """Attack a given range query with fully distinguishable blocks

        @param blocklist: A list of sets, each set representing a block, the main target in the first block.
        @return: List of possible results
        """
        res = []
        length = len(blocklist)
        for key in blocklist[0]: # Iterate through all candidates for the main target (as it must be in the first block)
            if DB.isValidTarget(key) and DB.getPatternLengthForHost(key) == length: # If it is the beginning of a pattern of the correct length...
                # The following is a method of determining if every block contains exactly one element of the pattern of the current candidate.
                tmp = blocklist[1:]
                cnt = {}
                for i in range(length-1):
                    cnt[i] = 0
                for query in DB.getPatternForHost(key):
                    if query != key:
                        for i in range(len(tmp)):
                            if query in tmp[i]:
                                cnt[i] += 1
                if not 0 in cnt.values():
                    res.append(key)
        return res
예제 #6
0
    def generateBaseDRQ(self, domain):
        """Generator for Pattern-Based DNS Range Queries (trying to fill the query blocks with patterns)

        Queries are unique inside their respective sets, but may appear more than once across different
        query blocks.

        @param domain: Domain for which a DNS Range Query should be generated
        @return: List of Sets, in order, each set representing a query block
        """
        if not DB.isValidTarget(domain):
            Error.printErrorAndExit(domain + " is not a valid target")
        pattern_length = len(DB.PATTERNS[domain])
        block = [set()]
        num_of_available_patterns = DB.getNumberOfHostsWithPatternLength(pattern_length) - 1
        if num_of_available_patterns >= Config.RQSIZE:
            hosts = set([domain])
            hosts.update(set(DB.getRandomHostsByPatternLengthB(pattern_length, Config.RQSIZE-1, hosts)))
            pattern_copy = {}
            for host in hosts:
                pattern_copy[host] = DB.getPatternForHost(host)
                pattern_copy[host].remove(host) 
                block[0].add(host)
            for i in range(1, pattern_length, 1):
                block.append(set())
                for host in pattern_copy:
                    block[i].add(pattern_copy[host].pop())
        else: 
            num_of_needed_patterns = Config.RQSIZE - (num_of_available_patterns+1)
            padding = []
            for i in range(num_of_needed_patterns):
                # Find patterns whose lengths sum to pattern_length (if any exist that have not been chosen yet)
                pad1_len = pad2_len = -1
                for pad1_len, pad2_len in zip(range(1, pattern_length/2+1, 1), range(pattern_length-1, pattern_length/2-1, -1)):
                    # This is a construct that generates numbers that sum to pattern_length. It is used instead of truly random
                    # numbers because it will not get stuck when no more patterns are available.
                    if ((DB.getNumberOfHostsWithPatternLengthB(pad1_len, block[0]) > 0) and \
                        (DB.getNumberOfHostsWithPatternLength(pad2_len) > 0)):
                        break
                    elif pad1_len == pattern_length/2: # No patterns of the correct length have been found, abort
                        pad1_len = -1
                if (pad1_len == -1): # Break out of loop as no further patterns can be found.
                    break
                # The following few lines get the dummy patterns from the database and saves them to the list of dummy-patterns
                pad1_host = DB.getRandomHostsByPatternLengthB(pad1_len, 1, block[0])[0]
                pad1_pattern = DB.getPatternForHost(pad1_host)
                pad1_pattern.remove(pad1_host)
                block[0].add(pad1_host)
                padding.append([pad1_host])
                for host in pad1_pattern:
                    padding[i].append(host)
                pad2_host = DB.getRandomHostsByPatternLength(pad2_len, 1)[0]
                pad2_pattern = DB.getPatternForHost(pad2_host)
                pad2_pattern.remove(pad2_host)
                padding[i].append(pad2_host)
                for host in pad2_pattern:
                    padding[i].append(host)
            # We now have as many dummy patterns as we will get. Start distributing them.
            pattern_copy = {}
            block[0].add(domain)
            pattern_copy[domain] = DB.getPatternForHost(domain)
            pattern_copy[domain].remove(domain)
            for element in DB.getRandomHostsByPatternLengthB(pattern_length, num_of_available_patterns, block[0]):
                # Get all patterns with the correct length and add them to the range query
                pattern_copy[element] = DB.getPatternForHost(element)
                pattern_copy[element].remove(element)
                block[0].add(element)
            for i in range(1, pattern_length, 1):
                # Distribute the remaining patterns (those whose lengths sum to the correct length)
                block.append(set())
                for host in pattern_copy:
                    block[i].add(pattern_copy[host].pop())
                for pattern in padding:
                    block[i].add(pattern[i])
        return block