def run(self):
        try:
            while True:
                # Wait for a message from the channel that a TW was modified
                message = self.c1.get_message(timeout=self.timeout)
                #print('Message received from channel {} with data {}'.format(message['channel'], message['data']))
                if message['data'] == 'stop_process':
                    return True
                elif message['channel'] == 'tw_modified':
                    # Get the profileid and twid
                    try:
                        profileid = message['data'].split(':')[0]
                        twid = message['data'].split(':')[1]

                        # Start of the port scan detection
                        self.print(
                            'Running the detection of portscans in profile {} TW {}'
                            .format(profileid, twid), 6, 0)
                        # For port scan detection, we will measure different things:
                        # 1. Vertical port scan:
                        # - 1 srcip sends not established flows to > 3 dst ports in the same dst ip. Any number of packets
                        # 2. Horizontal port scan:
                        # - 1 srcip sends not established flows to the same dst ports in > 3 dst ip.
                        # 3. Too many connections???:
                        # - 1 srcip sends not established flows to the same dst ports, > 3 pkts, to the same dst ip
                        # 4. Slow port scan. Same as the others but distributed in multiple time windows

                        # Remember that in slips all these port scans can happen for traffic going IN to an IP or going OUT from the IP.

                        # Get the list of dports that we connected as client using TCP not established
                        direction = 'Dst'
                        state = 'NotEstablished'
                        protocol = 'TCP'
                        role = 'Client'
                        type_data = 'Ports'
                        data = __database__.getDataFromProfileTW(
                            profileid, twid, direction, state, protocol, role,
                            type_data)
                        # For each port, see if the amount is over the threshold
                        for dport in data.keys():
                            """
                            ###
                            # PortScan Type 3. Direction OUT
                            # Considering all the flows in this TW, for all the Dst IP, get the sum of all the pkts send to each dst port TCP No tEstablished
                            totalpkts = int(data[dport]['totalpkt'])
                            # If for each port, more than X amount of packets were sent, report an evidence
                            if totalpkts > 3:
                                # Type of evidence
                                type_evidence = 'PortScanType3'
                                # Key
                                key = 'dport' + ':' + dport + ':' + type_evidence
                                # Description
                                description = 'Too Many Not Estab TCP to same port {} from IP: {}. Amount: {}'.format(dport, profileid.split('_')[1], totalpkts)
                                # Threat level
                                threat_level = 50
                                # Confidence. By counting how much we are over the threshold. 
                                if totalpkts >= 10:
                                    # 10 pkts or more, receive the max confidence
                                    confidence = 1
                                else:
                                    # Between 3 and 10 pkts compute a kind of linear grow
                                    confidence = totalpkts / 10.0
                                __database__.setEvidence(profileid, twid, type_evidence, threat_level, confidence)
                                self.print('Too Many Not Estab TCP to same port {} from IP: {}. Amount: {}'.format(dport, profileid.split('_')[1], totalpkts),6,0)

                            """
                            ### PortScan Type 2. Direction OUT
                            dstips = data[dport]['dstips']
                            amount_of_dips = len(dstips)
                            # If we contacted more than 3 dst IPs on this port with not established connections.. we have evidence
                            #self.print('Horizontal Portscan check. Amount of dips: {}. Threshold=3'.format(amount_of_dips), 3, 0)

                            # Type of evidence
                            type_evidence = 'PortScanType2'
                            # Key
                            key = 'dport' + ':' + dport + ':' + type_evidence
                            # Threat level
                            threat_level = 50
                            # Compute the confidence
                            pkts_sent = 0
                            # We detect a scan every Threshold. So we detect when there is 3, 6, 9, 12, etc. dips per port.
                            # The idea is that after X dips we detect a connection. And then we 'reset' the counter until we see again X more.
                            cache_key = profileid + ':' + twid + ':' + key
                            try:
                                prev_amount_dips = self.cache_det_thresholds[
                                    cache_key]
                            except KeyError:
                                prev_amount_dips = 0
                            #self.print('Key: {}. Prev dips: {}, Current: {}'.format(cache_key, prev_amount_dips, amount_of_dips))
                            if amount_of_dips % 3 == 0 and prev_amount_dips < amount_of_dips:
                                for dip in dstips:
                                    # Get the total amount of pkts sent to the same port to all IPs
                                    pkts_sent += dstips[dip]
                                if pkts_sent > 10:
                                    confidence = 1
                                else:
                                    # Between 3 and 10 pkts compute a kind of linear grow
                                    confidence = pkts_sent / 10.0
                                # Description
                                description = 'New horizontal port scan detected to port {}. Not Estab TCP from IP: {}. Tot pkts sent all IPs: {}'.format(
                                    dport,
                                    profileid.split(self.fieldseparator)[1],
                                    pkts_sent, confidence)
                                __database__.setEvidence(key,
                                                         threat_level,
                                                         confidence,
                                                         description,
                                                         profileid=profileid,
                                                         twid=twid)
                                self.print(description, 3, 0)
                                # Store in our local cache how many dips were there:
                                self.cache_det_thresholds[
                                    cache_key] = amount_of_dips

                        # Get the list of dstips that we connected as client using TCP not established, and their ports

                        direction = 'Dst'
                        state = 'NotEstablished'
                        protocol = 'TCP'
                        role = 'Client'
                        type_data = 'IPs'
                        data = __database__.getDataFromProfileTW(
                            profileid, twid, direction, state, protocol, role,
                            type_data)

                        # For each dstip, see if the amount of ports connections is over the threshold
                        for dstip in data.keys():
                            ### PortScan Type 1. Direction OUT
                            # dstports is a dict
                            dstports = data[dstip]['dstports']
                            amount_of_dports = len(dstports)
                            #self.print('Vertical Portscan check. Amount of dports: {}. Threshold=3'.format(amount_of_dports), 3, 0)
                            # Type of evidence
                            type_evidence = 'PortScanType1'
                            # Key
                            key = 'dstip' + ':' + dstip + ':' + type_evidence
                            # Threat level
                            threat_level = 50
                            # We detect a scan every Threshold. So we detect when there is 3, 6, 9, 12, etc. dports per dip.
                            # The idea is that after X dips we detect a connection. And then we 'reset' the counter until we see again X more.
                            cache_key = profileid + ':' + twid + ':' + key
                            try:
                                prev_amount_dports = self.cache_det_thresholds[
                                    cache_key]
                            except KeyError:
                                prev_amount_dports = 0
                            #self.print('Key: {}, Prev dports: {}, Current: {}'.format(cache_key, prev_amount_dports, amount_of_dports))
                            if amount_of_dports % 3 == 0 and prev_amount_dports < amount_of_dports:
                                # Compute the confidence
                                pkts_sent = 0
                                for dport in dstports:
                                    # Get the total amount of pkts sent to the same port to all IPs
                                    pkts_sent += dstports[dport]
                                if pkts_sent > 10:
                                    confidence = 1
                                else:
                                    # Between 3 and 10 pkts compute a kind of linear grow
                                    confidence = pkts_sent / 10.0
                                # Description
                                description = 'New vertical port scan detected to IP {} from {}. Total {} dst ports. Not Estab TCP. Tot pkts sent all ports: {}'.format(
                                    dstip,
                                    profileid.split(self.fieldseparator)[1],
                                    amount_of_dports, pkts_sent, confidence)
                                __database__.setEvidence(key,
                                                         threat_level,
                                                         confidence,
                                                         description,
                                                         profileid=profileid,
                                                         twid=twid)
                                self.print(description, 3, 0)
                                # Store in our local cache how many dips were there:
                                self.cache_det_thresholds[
                                    cache_key] = amount_of_dports

                    except AttributeError:
                        # When the channel is created the data '1' is sent
                        continue

        except KeyboardInterrupt:
            self.print('Stopping the process', 0, 1)
            return True
        except Exception as inst:
            self.print('Error in run() of {}'.format(inst), 0, 1)
            self.print(type(inst), 0, 1)
            self.print(inst, 0, 1)
Ejemplo n.º 2
0
    def process_global_data(self):
        """ 
        This is the main function called by the timer process
        Read the global data and output it on logs 
        """
        try:
            #1. Get the list of profiles modified
            # How many profiles we have?
            profilesLen = str(__database__.getProfilesLen())
            # Get the list of all the modifed TW for all the profiles
            TWModifiedforProfile = __database__.getModifiedTWLogs()
            amount_of_modified = len(TWModifiedforProfile)
            self.outputqueue.put(
                '20|logs|[Logs] Number of Profiles in DB: {}. Modified TWs: {}. ({})'
                .format(profilesLen, amount_of_modified,
                        datetime.now().strftime('%Y-%m-%d--%H:%M:%S')))
            last_profile_id = None
            description_of_malicious_ip_profile = None
            for profileTW in TWModifiedforProfile:

                # Get the profileid and twid
                profileid = profileTW.split(
                    self.fieldseparator
                )[0] + self.fieldseparator + profileTW.split(
                    self.fieldseparator)[1]
                twid = profileTW.split(self.fieldseparator)[2]
                # Get the time of this TW. For the file name
                twtime = __database__.getTimeTW(profileid, twid)
                twtime = time.strftime('%Y-%m-%dT%H:%M:%S',
                                       time.localtime(twtime))
                self.print(
                    '\tStoring Profile: {}. TW {}. Time: {}'.format(
                        profileid, twid, twtime), 0, 2)
                #self.print('\tProfile: {} has {} timewindows'.format(profileid, twLen), 0, 3)

                # Create the folder for this profile if it doesn't exist
                profilefolder = self.createProfileFolder(profileid)

                # Create the TW log file
                twlog = twtime + '.' + twid
                # First Erase its file and save the data again
                self.addDataToFile(profilefolder + '/' + twlog,
                                   '',
                                   file_mode='w+',
                                   data_mode='raw')

                # Save in the log file all parts of the profile

                # 0. Write the profileID for people getting know what they see in the file.
                self.addDataToFile(profilefolder + '/' + twlog,
                                   'ProfileID: {}\n'.format(profileid),
                                   file_mode='a+',
                                   data_type='text')

                # 0. Is a ip of this profile stored as malicious?
                # If it still one profile do not ask again the database for each new time_window.
                if last_profile_id != profileid:
                    description_of_malicious_ip_profile = __database__.is_profile_malicious(
                        profileid)
                if description_of_malicious_ip_profile:
                    ip_of_profile = profileid.split(self.separator)[1]
                    text_data = '[THREAT INTELIGENCE] IP of this profile: {} was detected as malicious. Description: "{}"\n'.format(
                        ip_of_profile, description_of_malicious_ip_profile)
                    self.addDataToFile(profilefolder + '/' + twlog,
                                       text_data,
                                       file_mode='a+',
                                       data_type='text')

                # 1. Detections to block. The getBlockingRequest function return {True, False}
                blocking = __database__.getBlockingRequest(profileid, twid)
                if blocking:
                    text_data = 'Was requested to block in this time window: ' + str(
                        blocking)
                    self.addDataToFile(profilefolder + '/' + twlog,
                                       text_data,
                                       file_mode='a+',
                                       data_type='json')
                    self.outputqueue.put(
                        '03|logs|\t\t[Logs] Blocking Request: ' +
                        str(blocking))

                # 2. Info about the evidence so far for this TW.
                evidence = __database__.getEvidenceForTW(profileid, twid)
                if evidence:
                    evidence = json.loads(evidence)
                    self.addDataToFile(profilefolder + '/' + twlog,
                                       'Evidence of detections in this TW:',
                                       file_mode='a+',
                                       data_type='text')
                    self.outputqueue.put(
                        '03|logs|\t\t[Logs] Evidence of detections in this TW:'
                    )
                    for data in evidence:
                        self.addDataToFile(profilefolder + '/' + twlog,
                                           '\tEvidence: {}'.format(data[0]),
                                           file_mode='a+',
                                           data_type='text')
                        self.outputqueue.put(
                            '03|logs|\t\t\t Evidence: {}'.format(data[0]))

                # 3. DstIPs
                dstips = __database__.getDstIPsfromProfileTW(profileid, twid)
                if dstips:
                    # Add dstips to log file
                    self.addDataToFile(profilefolder + '/' + twlog,
                                       'DstIP:',
                                       file_mode='a+',
                                       data_type='text')
                    self.outputqueue.put('03|logs|\t\t[Logs] DstIP:')
                    data = json.loads(dstips)
                    # Better printing of data
                    for key in data:
                        ip_info = __database__.getIPData(key)
                        if ip_info:
                            printable_ip_info = ', '.join(
                                '{} {}'.format(k, v)
                                for k, v in ip_info.items())
                        else:
                            printable_ip_info = '-'
                        self.addDataToFile(profilefolder + '/' + twlog,
                                           '\t{} ({} times). Info: {}'.format(
                                               key, data[key],
                                               printable_ip_info),
                                           file_mode='a+',
                                           data_type='text')
                    self.outputqueue.put('03|logs|\t\t[Logs] DstIP: ' + dstips)

                # 4. SrcIPs
                srcips = __database__.getSrcIPsfromProfileTW(profileid, twid)
                if srcips:
                    # Add srcips
                    self.addDataToFile(profilefolder + '/' + twlog,
                                       'SrcIP:',
                                       file_mode='a+',
                                       data_type='text')
                    self.outputqueue.put('03|logs|\t\t[Logs] SrcIP:')
                    data = json.loads(srcips)
                    for key in data:
                        ip_info = __database__.getIPData(key)
                        if ip_info:
                            printable_ip_info = ', '.join(
                                '{} {}'.format(k, v)
                                for k, v in ip_info.items())
                        else:
                            printable_ip_info = '-'
                        self.addDataToFile(profilefolder + '/' + twlog,
                                           '\t{} ({} times). Info: {}'.format(
                                               key, data[key],
                                               printable_ip_info),
                                           file_mode='a+',
                                           data_type='text')
                        self.outputqueue.put(
                            '03|logs|\t\t\t[Logs] {} ({} times)'.format(
                                key, data[key]))

                # 5. OutTuples
                out_tuples = __database__.getOutTuplesfromProfileTW(
                    profileid, twid)
                if out_tuples:
                    # Add tuples
                    self.addDataToFile(profilefolder + '/' + twlog,
                                       'OutTuples:',
                                       file_mode='a+',
                                       data_type='text')
                    self.outputqueue.put('03|logs|\t\t[Logs] OutTuples:')
                    data = json.loads(out_tuples)
                    for key in data:
                        self.addDataToFile(profilefolder + '/' + twlog,
                                           '\t{} ({})'.format(key, data[key]),
                                           file_mode='a+',
                                           data_type='text')
                        self.outputqueue.put(
                            '03|logs|\t\t\t[Logs] {} ({})'.format(
                                key, data[key]))
                    self.outputqueue.put('03|logs|\t\t[Logs] Tuples: ' +
                                         out_tuples)

                # 6. InTuples
                in_tuples = __database__.getInTuplesfromProfileTW(
                    profileid, twid)
                if in_tuples:
                    # Add in tuples
                    self.addDataToFile(profilefolder + '/' + twlog,
                                       'InTuples:',
                                       file_mode='a+',
                                       data_type='text')
                    self.outputqueue.put('03|logs|\t\t[Logs] InTuples:')
                    data = json.loads(in_tuples)
                    for key in data:
                        self.addDataToFile(profilefolder + '/' + twlog,
                                           '\t{} ({})'.format(key, data[key]),
                                           file_mode='a+',
                                           data_type='text')
                        self.outputqueue.put(
                            '03|logs|\t\t\t[Logs] {} ({})'.format(
                                key, data[key]))

                # 7. Print the port data
                all_roles = ['Client', 'Server']
                all_protocols = ['TCP', 'UDP', 'ICMP', 'IPV6ICMP']
                all_states = ['Established', 'NotEstablished']
                all_directions = ['Dst', 'Src']
                type_data = 'Ports'
                for role in all_roles:
                    for protocol in all_protocols:
                        for state in all_states:
                            for direction in all_directions:
                                text_data = 'As {}, {} {} {} ports:'.format(
                                    role, protocol, state, direction)
                                self.outputqueue.put('03|logs|\t\t\t[Logs]: ' +
                                                     text_data)
                                data = __database__.getDataFromProfileTW(
                                    profileid, twid, direction, state,
                                    protocol, role, type_data)
                                #self.print('LOGING data: {}'.format(data))
                                if data:
                                    self.addDataToFile(profilefolder + '/' +
                                                       twlog,
                                                       text_data,
                                                       file_mode='a+',
                                                       data_type='text')
                                    for port in data:
                                        text_data = '\tPort {}. Total Flows: {}. Total Pkts: {}. TotalBytes: {}.'.format(
                                            port, data[port]['totalflows'],
                                            data[port]['totalpkt'],
                                            data[port]['totalbytes'])
                                        self.addDataToFile(profilefolder +
                                                           '/' + twlog,
                                                           text_data,
                                                           file_mode='a+',
                                                           data_type='text')
                                        self.outputqueue.put(
                                            '03|logs|\t\t\t[Logs]: ' +
                                            text_data)

                # 8. Info about the evidence so far for this TW.
                evidence = __database__.getEvidenceForTW(profileid, twid)
                if evidence:
                    evidence = json.loads(evidence)
                    self.addDataToFile(profilefolder + '/' + twlog,
                                       'Evidence of detections in this TW:',
                                       file_mode='a+',
                                       data_type='text')
                    for key in evidence:
                        self.addDataToFile(
                            profilefolder + '/' + twlog,
                            '\tEvidence Description: {}. Confidence: {}. Threat Level: {} (key:{})'
                            .format(evidence[key][2], evidence[key][0],
                                    evidence[key][1], key),
                            file_mode='a+',
                            data_type='text')

                # Add free line between tuple info and information about ports and IP.
                self.addDataToFile(profilefolder + '/' + twlog,
                                   '',
                                   file_mode='a+',
                                   data_type='text')
                """
                Dst ports and Src ports
                """
                """     
                flow_type_key = [Src,Dst] + [Port,IP] + [Client,Server] + [TCP,UDP, ICMP, ICMP6] + [Established, NotEstablished] 
                Example: flow_type_key = 'SrcPortClientTCPEstablished'
                """
                flow_types_dict = self.create_all_flow_possibilities()
                hash_key = profileid + self.separator + twid
                for flow_type_key, sentence in flow_types_dict.items():
                    data = __database__.get_data_from_profile_tw(
                        hash_key, flow_type_key)
                    if data:
                        self.addDataToFile(profilefolder + '/' + twlog,
                                           sentence,
                                           file_mode='a+',
                                           data_type='text')
                        for port, sample in data.items():
                            type = 'IP' if 'ip' in flow_type_key.lower(
                            ) else 'Port'
                            text_data = '\t{} {}. Total Flows: {}. Total Pkts: {}. TotalBytes: {}.'.format(
                                type, port, sample['totalflows'],
                                sample['totalpkt'], sample['totalbytes'])
                            self.addDataToFile(profilefolder + '/' + twlog,
                                               text_data,
                                               file_mode='a+',
                                               data_type='text')
                            self.outputqueue.put('03|logs|\t\t\t[Logs]: ' +
                                                 text_data)

                # 9. This should be last. Detections to block
                blocking = __database__.getBlockingRequest(profileid, twid)
                if blocking:
                    self.addDataToFile(
                        profilefolder + '/' + twlog,
                        'Was requested to block in this time window: ' +
                        str(blocking),
                        file_mode='a+',
                        data_type='json')
                    self.outputqueue.put(
                        '03|logs|\t\t[Logs] Blocking Request: ' +
                        str(blocking))

                # Mark it as not modified anymore
                __database__.markProfileTWAsNotModifiedLogs(profileid, twid)

                ###########
                # Create Timeline for each profile
                # Store the timeline from the DB in a file
                # The timeline file is unique for all timewindows. Much easier to read this way.

                # Get all the TW for this profile
                tws = __database__.getTWsfromProfile(profileid)
                ip = profileid.split('_')[1]

                timeline_path = profilefolder + '/' + 'Complete-timeline-outgoing-actions.txt'
                # If the file does not exists yet, create it
                if not os.path.isfile(timeline_path):
                    self.addDataToFile(
                        timeline_path,
                        'Complete TimeLine of IP {}\n'.format(ip),
                        file_mode='w+')

                for twid_tuple in tws:
                    (twid, starttime) = twid_tuple
                    hash_key = profileid + self.separator + twid
                    first_index = self.timeline_first_index.get(hash_key, 0)
                    data, first_index = __database__.get_timeline_last_lines(
                        profileid, twid, first_index)
                    self.timeline_first_index[hash_key] = first_index
                    if data:
                        self.print(
                            'Adding to the profile line {} {}, data {}'.format(
                                profileid, twid, data), 6, 0)
                        self.addDataToFile(
                            profilefolder + '/' +
                            'Complete-timeline-outgoing-actions.txt',
                            data,
                            file_mode='a+',
                            data_type='lines',
                            data_mode='raw')

                last_profile_id = profileid

            # Create the file of the blocked profiles and TW
            TWforProfileBlocked = __database__.getBlockedTW()
            # Create the file of blocked data
            if TWforProfileBlocked:
                self.addDataToFile('Blocked.txt',
                                   'Detections:\n',
                                   file_mode='w+',
                                   data_type='text')
                for blocked in TWforProfileBlocked:
                    self.addDataToFile('Blocked.txt',
                                       '\t' + str(blocked).split('_')[1] +
                                       ': ' + str(blocked).split('_')[2],
                                       file_mode='a+',
                                       data_type='json')
                    #self.outputqueue.put('03|logs|\t\t[Logs]: Blocked file updated: {}'.format(TWforProfileBlocked))

            # Create a file with information about the capture in general
            #self.addDataToFile('Information.txt', 'Information about this slips run', file_mode='w+', data_type='text')
            #self.addDataToFile('Information.txt', '================================\n', file_mode='a+', data_type='text')
            #self.addDataToFile('Information.txt', 'Type of input: ' + , file_mode='a+', data_type='text')

        except KeyboardInterrupt:
            return True
        except Exception as inst:
            self.outputqueue.put(
                '01|logs|\t[Logs] Error in process_global_data in LogsProcess')
            self.outputqueue.put('01|logs|\t[Logs] {}'.format(type(inst)))
            self.outputqueue.put('01|logs|\t[Logs] {}'.format(inst))
            sys.exit(1)