Esempio n. 1
0
 def checkMISPHashEventExist(self, filename):
     try:
         LibIoC_DK.debugging(
             "Checking the MISP hash event existence: %s" % (filename),
             main._DEBUG_, main._LOGGING_, main.hFile)
         response = self.misp_connection.search_all(filename)
     except requests.exceptions.HTTPError:
         LibIoC_DK.debugging("HTTPError occurred", main._DEBUG_,
                             main._LOGGING_, main.hFile)
         return False
     if (main.is_py2 and not response.has_key('response')) or (
             main.is_py3 and 'response' not in response):
         #if not response.has_key('response'):
         LibIoC_DK.debugging("The MISP hash event NOT exist", main._DEBUG_,
                             main._LOGGING_, main.hFile)
         return False
     for r in response['response']:
         if r['Event']['info'] == filename:
             LibIoC_DK.debugging("The MISP hash event ALREADY exists",
                                 main._DEBUG_, main._LOGGING_, main.hFile)
             return True
         for attr in r['Event']['Attribute']:
             if attr['category'] == 'Payload installation':
                 if attr['value'] == filename:
                     LibIoC_DK.debugging(
                         "The hash value ALREADY stored as an attribute of : %s"
                         % (r['Event']['info']), main._DEBUG_,
                         main._LOGGING_, main.hFile)
                     return True
     return False
Esempio n. 2
0
def processFile(misp, f, config_value):
    # Adding MISP by APT report-wise manner: one MISP event is consisted by one API report. 
    if _MISP_EVENT_GENERATION_TYPE == 1: 
        # check if the event data is already in MISP server 
        if misp.checkEventExist(LibIoC_DK.getFileName(f)) == True:
            return
        LibIoC_DK.debugging("Processing file: %s"%(LibIoC_DK.getFileName(f)), _DEBUG_, _LOGGING_, hFile) 
        # extract IoCs in the report file
        ioc = parse_ioc(f)
        if ioc is not None and len(ioc) > 0:
            date = getFileDate(f, config_value)
            misp.createMISPEvent(ioc, f, date)
            
            if _STAT_:
                ioc_stat.finalizeTempStatistics()
                ioc_stat.reset()
                ioc_stat.saveIoCStatistics()
        
    # Adding MISP by malware-wise manner. MISP events are consisted by each malware hashes in APT report
    # if further analysis results could be retrieved from malware repository, 
    # otherwise rest of IoCs are stored in one MISP event under the event name as the title of the report.
    elif _MISP_EVENT_GENERATION_TYPE == 2:
        if misp.checkMISPReportEventExist(LibIoC_DK.getFileName(f)):
            return
        nonHash_IoC = []
        hash_IoC = []
        ioc = parse_ioc(f)
        if ioc is not None and len(ioc) > 0:
            for attr in ioc:
                # if the IoC is a hash value and the analysis result of the hash could be retrieved,
                # create a MISP event of the hash value 
                if attr[0] == 'MD5' or attr[0] == 'SHA1' or attr[0] == 'SHA256':
                    if _STAT_:
                        ioc_stat.increaseHashInReport()

                # if the IoC is not a hash value or the analysis result of a hash could not be retrieved,
                # keep the IoC to store under the MISP event of the API report
                else:
                    nonHash_IoC.append(('report',attr[0],attr[1]))
        
            # add hash IoCs in each MISP events
            if (_MODE_==2 or _MODE_==3) and len(hash_IoC) > 0:
                for attr in hash_IoC:
                    misp.createMISPEvent(attr[2], f)
            
            # add non-hash IoCs in one MISP event
            if (_MODE_==1 or _MODE_==3) and len(nonHash_IoC) > 0:
                date = getFileDate(f, config_value)
                misp.createMISPEvent(nonHash_IoC+hash_IoC, f, date)
                                     
            if _STAT_:
                ioc_stat.finalizeTempStatistics()
                ioc_stat.reset()
                ioc_stat.saveIoCStatistics()
    return
Esempio n. 3
0
    def getMISPEvent_of_month(self, year, month):
        retval = []
        from_date = ''
        to_date = ''
        if month < 10:
            from_date = year + "-0%d-01" % (month)
            to_date = year + "-0%d-31" % (month)
        else:
            from_date = year + "-%d-01" % (month)
            to_date = year + "-%d-31" % (month)

        try:
            ee = self.misp.misp_connection.search(date_from=from_date,
                                                  date_to=to_date)['response']
        except Exception as e:
            print('error misp_connection.search (month=%s, year=%s)' %
                  (month, year))
            return

        for e in ee:
            if LibIoC_DK.isHash(e['Event']['info']):
                continue
            else:
                retval.append(e)

        hash_event = []
        for r in retval:
            for yy in range(2008, 3000):
                for mm in range(1, 13):
                    if mm < 10:
                        from_date = str(yy) + "-0%d-01" % (mm)
                        to_date = str(yy) + "-0%d-31" % (mm)
                    else:
                        from_date = str(yy) + "-%d-01" % (mm)
                        to_date = str(yy) + "-%d-31" % (mm)
                    try:
                        ee = self.misp.misp_connection.search(
                            values=r['Event']['info'],
                            category="Other",
                            type_attribute="comment",
                            date_from=from_date,
                            date_to=to_date)['response']
                        for e in ee:
                            if LibIoC_DK.isHash(e['Event']['info']):
                                hash_event.append(e)
                    except Exception as e:
                        print('error %s / %s (month=%d, year=%d)' %
                              (str(e), r['Event']['info'], mm, yy))
                        continue

        return retval + hash_event

        return
 def getMalwareInfo(self, _hash, misp_event=False, misp=False):
     
     LibIoC_DK.debugging("Getting the malware info: %s" %(_hash) , main._DEBUG_, main._LOGGING_, main.hFile)
     result1 = self.getMalwareStaticInfo(_hash, misp_event, ) 
     if result1:
         result2 = self.getMalwareBehaviorInfo(_hash, misp_event, misp)
         if misp_event and misp:
             return result1 or result2
         else:
             if result2:
                 return result1 + result2
             else:
                 return result1
     else:
         LibIoC_DK.debugging("NO the malware info found: %s" %(_hash), main._DEBUG_, main._LOGGING_, main.hFile)
         return False
Esempio n. 5
0
    def getEventIoCStatistics(self, event_list):
        if event_list == None:
            return
        s = PostStat()
        for e in event_list:
            if LibIoC_DK.isHash(e['Event']['info']):
                s.add_hash_events()
            else:
                s.add_report_events()

            for attr in e['Event']['Attribute']:
                if 'md5' in attr['type'] or 'sha1' in attr[
                        'type'] or 'sha256' in attr['type']:
                    s.add_hash()
                elif 'ip' in attr['type']:
                    s.add_IP()
                elif 'url' in attr['type']:
                    s.add_URL()
                elif 'email' in attr['type']:
                    s.add_email()
                elif 'vulnerability' in attr['type']:
                    s.add_cve()
                elif 'filename' in attr['type']:
                    s.add_filename()
                elif 'pdb' in attr['type']:
                    s.add_pdb()
                elif 'text' in attr['type']:
                    if 'TimeStamp' in attr['comment']:
                        s.add_date()
                    elif 'digital sign serial number' in attr['comment']:
                        s.add_codesign()
                    else:
                        s.add_string()
        return s.stat
Esempio n. 6
0
    def createMISPEvent(self, val, filename='', _date=''):

        if type(val) == tuple and LibIoC_DK.isHash(val[2]):
            if not self.checkMISPHashEventExist(val[2]):
                if self.createMISPEventFromHash(val[2], filename):
                    return True
                else:
                    LibIoC_DK.debugging("Failed to create the MISP hash event",
                                        main._DEBUG_, main._LOGGING_,
                                        main.hFile)
                    return False
            else:
                eid = self.getMISPEventID(val[2])
                e = self.misp_connection.get_event(eid)
                self.misp_connection.add_named_attribute(
                    e,
                    category='Other',
                    type_value='comment',
                    value=LibIoC_DK.getFileName(
                        filename))  # this will work as the ground truth of IoC
            return True
        elif type(val) == list:
            if self.createMISPEventFromReport(val, filename, _date):
                return True
            LibIoC_DK.debugging(
                "Failed to create the MISP event: val(%s), filename(%s)" %
                (val, LibIoC_DK.getFileName(filename)), main._DEBUG_,
                main._LOGGING_, main.hFile)
            return False
Esempio n. 7
0
    def getMISPEventID(self, filename):
        try:
            response = self.misp_connection.search_all(filename)
        except requests.exceptions.HTTPError:
            LibIoC_DK.debugging("[getMISPEventID] HTTPError occurred",
                                main._DEBUG_, main._LOGGING_, main.hFile)
            return False

        if not response.has_key('response'):
            return False
        for r in response['response']:
            if r['Event']['info'] == filename:
                return r['Event']['id']
            if LibIoC_DK.isHash(filename):
                for attr in r['Event']['Attribute']:
                    if attr['category'] == 'Payload installation':
                        if attr['value'] == filename:
                            return r['Event']['id']
        return False
Esempio n. 8
0
    def checkAttribute(self, attr, eid=None):
        if eid == None:
            try:
                response = self.misp_connection.search(attr)
            except requests.exceptions.HTTPError:
                LibIoC_DK.debugging(
                    "[checkAttribute] HTTPError while searching " + attr,
                    main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            except:
                return False

            if response.has_key('response'):
                retval = []
                for e in response['response']:
                    found = False
                    for i in range(len(e['Event']['Attribute'])):
                        if e['Event']['Attribute'][i]['value'] == attr.lower():
                            retval.append(e['Event']['id'])
                            found = True
                            break
                        if found:
                            break
                    if found:
                        break
                return retval
            else:
                return False
        else:
            if type(eid) != 'str':
                eid = str(eid)

            response = self.misp_connection.get(eid)
            if not response.has_key('Event'):
                return False

            if len(response) > 0 and len(response['Event']['Attribute']) > 0:
                for val in response['Event']['Attribute']:
                    for i in val:
                        if i['value'] == attr.lower():
                            return True
        return False
    def getMalwareCollectedDate(self, _hash):
           
        _params = {
        'api_key': self.key,
        'hash': _hash,
        'env_type': 2
        }
        
        response = None
        try:
            LibIoC_DK.debugging("Getting the malware collection date: %s"%(_hash), main._DEBUG_, main._LOGGING_, main.hFile)
            response = requests.get('https://private.api.malwares.com/v3/file/mwsinfo', params=_params)
            self.query_counter = self.query_counter + 1
        except:
            print('getMalwareCollectedDate exception!')
            return False

        try:
            summary = response.json()
        except:
            LibIoC_DK.debugging("Exception occurred during decoding response", main._DEBUG_, main._LOGGING_, main.hFile)
            return False        
        
        if summary['result_code'] <= 0 and summary['result_code'] != 2:
            LibIoC_DK.debugging("Error returned while getting the malware collection date", main._DEBUG_, main._LOGGING_, main.hFile)
            return False
         
        return summary['first_seen'].encode('utf-8')[0:10]
 def downloadMalware(self, _hash, save=False):
     
     _params = {
     'api_key': self.key,
     'hash': _hash,
     }
     
     try:
         LibIoC_DK.debugging("Downloading the malware: %s"%(_hash), main._DEBUG_, main._LOGGING_, main.hFile)
         response = requests.get('https://private.api.malwares.com/v3/file/download', params=_params)
         self.query_counter = self.query_counter + 1
     except:
         print('downloadMalware exception!')
         return False
     
     if response == None or response == '':
         LibIoC_DK.debugging("NO response returned while downloading the malware", main._DEBUG_, main._LOGGING_, main.hFile)
         return False
              
     if response.status_code < 0 or 'Invalid type of hash' in response.content:
         LibIoC_DK.debugging("Error returned while downloading the malware", main._DEBUG_, main._LOGGING_, main.hFile)
         return False
     
     downloaded_file = response.content
 
     # Save Malware File
     if save:
         f = open(_hash, 'w')
         f.write(downloaded_file)
         f.close()
         self.unzipMalware(_hash)
         return True
     
     return downloaded_file
Esempio n. 11
0
    def getMISPEvent_of_Year(self, year):
        retval = []
        ee = self.misp.misp_connection.search(date_from=year + "-01-01",
                                              date_to=year +
                                              "-12-31")['response']
        for e in ee:
            if LibIoC_DK.isHash(e['Event']['info']):
                continue
            else:
                retval.append(e)

        hash_event = []
        for r in retval:
            print(r['Event']['info'] + '\n')
            ee = self.misp.misp_connection.search(
                values=r['Event']['info'],
                category="Other",
                type_attribute="comment")['response']
            for e in ee:
                if LibIoC_DK.isHash(e['Event']['info']):
                    hash_event.append(e)

        return retval + hash_event
 def waitToNextMidnight_UTC(self):
     LibIoC_DK.debugging("current time : %s UTC" % (str(datetime.utcnow())), main._DEBUG_, main._LOGGING_, main.hFile)
     LibIoC_DK.debugging("Wait to tomorrow 00:00 am. UTC", main._DEBUG_, main._LOGGING_, main.hFile)
     stop_d = datetime.utcnow().day
     while True:
         time.sleep(600)
         if datetime.utcnow().day > stop_d:
             break
     LibIoC_DK.debugging("Waked up!!!!", main._DEBUG_, main._LOGGING_, main.hFile)
     return
Esempio n. 13
0
 def checkMISPReportEventExist(self, filename):
     try:
         LibIoC_DK.debugging(
             "Checking the MISP file event existence: %s" % (filename),
             main._DEBUG_, main._LOGGING_, main.hFile)
         response = self.misp_connection.search_all(filename)
     except requests.exceptions.HTTPError:
         LibIoC_DK.debugging("HTTPError while querying " + filename,
                             main._DEBUG_, main._LOGGING_, main.hFile)
         return False
     if (main.is_py2 and not response.has_key('response')) or (
             main.is_py3 and 'response' not in response):
         LibIoC_DK.debugging("The MISP file event NOT exist", main._DEBUG_,
                             main._LOGGING_, main.hFile)
         return False
     for r in response['response']:
         if r['Event']['info'] == filename:
             LibIoC_DK.debugging("The MISP file event ALREADY exists",
                                 main._DEBUG_, main._LOGGING_, main.hFile)
             return True
     return False
Esempio n. 14
0
    def exportXML_Date(self, year, event_type, output_filename):
        #import xml.etree.ElementTree as ET
        from lxml import etree as ET
        root = ET.Element('CTIMinerDataset')

        report_event = []
        for mm in range(1, 13):
            if mm < 10:
                from_date = str(year) + "-0%d-01" % (mm)
                to_date = str(year) + "-0%d-31" % (mm)
            else:
                from_date = str(year) + "-%d-01" % (mm)
                to_date = str(year) + "-%d-31" % (mm)
            try:
                ee = self.misp_connection.search(date_from=from_date,
                                                 date_to=to_date)['response']
            except Exception as e:
                print('error %s / (year=%d, month=%d)' % (str(e), year, mm))
                continue

            for e in ee:
                if LibIoC_DK.isHash(e['Event']['info']):
                    continue
                else:
                    if event_type == 'report':
                        root = self.addEventDataToElementTree(root, e)
                    elif event_type == 'malware':
                        report_event.append(e)

        if event_type == 'report':
            tree = ET.ElementTree(root)
            f = open(output_filename, 'wb')
            f.write(ET.tostring(tree, pretty_print=True))
            f.close()
            return

        for r in report_event:
            for yy in range(2008, 3000):
                for mm in range(1, 13):
                    try:
                        if mm < 10:
                            from_date = str(yy) + "-0%d-01" % (mm)
                            to_date = str(yy) + "-0%d-31" % (mm)
                        else:
                            from_date = str(yy) + "-%d-01" % (mm)
                            to_date = str(yy) + "-%d-31" % (mm)
                        ee = self.misp_connection.search(
                            values=r['Event']['info'],
                            category="Other",
                            type_attribute="comment",
                            date_from=from_date,
                            date_to=to_date)['response']
                        for e in ee:
                            if LibIoC_DK.isHash(e['Event']['info']):
                                root = self.addEventDataToElementTree(root, e)
                    except Exception as e:
                        print('error %s / %s (month=%d, year=%d)' %
                              (str(e), r['Event']['info'], mm, yy))
                        continue

        tree = ET.ElementTree(root)
        f = open(output_filename, 'wb')
        f.write(ET.tostring(tree, pretty_print=True))
        f.close()
        return
Esempio n. 15
0
def processFileList(misp, file_names, config_value):
    processed_list_root = openFileProcessingResult()
    # Adding MISP by APT report-wise manner: one MISP event is consisted by one API report. 
    if _MISP_EVENT_GENERATION_TYPE == 1: 
        for f in file_names:
            
            # check if the event data is already in MISP server 
            if misp.checkEventExist(LibIoC_DK.getFileName(f)) == True:
                LibIoC_DK.debugging("The MISP file event ALREADY exists: %s" %(LibIoC_DK.getFileName(f)), _DEBUG_, _LOGGING_, hFile)
                continue
            # extract IoCs in the report file
            ioc = parse_ioc(f)
            if ioc is not None and len(ioc) > 0:
                date = getFileDate(f, config_value)
                misp.createMISPEvent(ioc, f, date)
                
                if _STAT_:
                    ioc_stat.finalizeTempStatistics()
                    ioc_stat.reset()
                    ioc_stat.saveIoCStatistics()
        
    # Adding MISP by malware-wise manner. MISP events are consisted by each malware hashes in APT report
    # if further analysis results could be retrieved from malware repository, 
    # otherwise rest of IoCs are stored in one MISP event under the event name as the title of the report.
    elif _MISP_EVENT_GENERATION_TYPE == 2:
        for f in file_names:
            
            if isFileProcessedBefore(processed_list_root, LibIoC_DK.getFileName(f)) or misp.checkMISPReportEventExist(LibIoC_DK.getFileName(f)):
                continue
            nonHash_IoC = []
            hash_IoC = []

            LibIoC_DK.debugging("Parsing IoC...", _DEBUG_, _LOGGING_, hFile) 
            ioc = parse_ioc(f)
            if ioc is not None and len(ioc) > 0:
                for attr in ioc:
                    # if the IoC is a hash value and the analysis result of the hash could be retrieved,
                    # create a MISP event of the hash value 
                    if attr[0] == 'MD5' or attr[0] == 'SHA1' or attr[0] == 'SHA256':
                        hash_IoC.append(('report',attr[0],attr[1]))
                        if _STAT_:
                            ioc_stat.increaseHashInReport()
                        
                    # if the IoC is not a hash value or the analysis result of a hash could not be retrieved,
                    # keep the IoC to store under the MISP event of the API report
                    else:
                        nonHash_IoC.append(('report',attr[0],attr[1]))
            
                # add hash IoCs in each MISP events
                if (_MODE_==2 or _MODE_==3) and len(hash_IoC) > 0:
                    for attr in hash_IoC:
                        if misp.createMISPEvent(attr, f) and _STAT_:
                            misp.ioc_stat.increaseAnalyzedHash()
                        else:
                            nonHash_IoC.append(attr)
                # add non-hash IoCs in one MISP event
                if (_MODE_==1 or _MODE_==3) and len(nonHash_IoC) > 0:
                    date = getFileDate(f, config_value)
                    if misp.createMISPEvent(nonHash_IoC, f, date):
                        addFileProcessingResult(processed_list_root, LibIoC_DK.getFileName(f), 'success')
                    else:
                        addFileProcessingResult(processed_list_root, LibIoC_DK.getFileName(f), 'fault')
                    
                if _STAT_:
                    ioc_stat.finalizeTempStatistics()
                    ioc_stat.reset()
                    ioc_stat.saveIoCStatistics()
            else:
                LibIoC_DK.debugging("NO IoC found in %s" %(LibIoC_DK.getFileName(f)), _DEBUG_, _LOGGING_, hFile) 
                addFileProcessingResult(processed_list_root, LibIoC_DK.getFileName(f), 'noIoC')

            saveFileProcessingResult(processed_list_root)
    return
Esempio n. 16
0
    def createMISPEventFromHash(self, _hash, filename, additional_hash=False):
        LibIoC_DK.debugging("Creating the MISP hash event: %s" % (_hash),
                            main._DEBUG_, main._LOGGING_, main.hFile)

        _hash = _hash.lower()
        # if the MISP event for the hash value already exists, stop the further process.
        if self.checkMISPHashEventExist(_hash):
            LibIoC_DK.debugging("The MISP hash event ALREADY exists",
                                main._DEBUG_, main._LOGGING_, main.hFile)
            return False

        result = self.malware_repo_connector.getMalwareInfo(_hash)

        if not result:
            return False

        event = self.misp_connection.new_event(0, 1, 2, _hash)
        self.misp_connection.add_named_attribute(
            event,
            category='Other',
            type_value='comment',
            value=LibIoC_DK.getFileName(
                filename))  # this will work as the ground truth of IoCs

        # the first three attributes in the result is md5, sha1, and sha256 representation malware hash, so manually store them in the event.
        md5 = result.pop(0)[2]
        sha1 = result.pop(0)[2]
        sha256 = result.pop(0)[2]

        self.misp_connection.add_hashes(event,
                                        category='Payload installation',
                                        md5=md5)
        if main._STAT_:
            self.ioc_stat.addCategory2('hash')
        self.misp_connection.add_hashes(event,
                                        category='Payload installation',
                                        sha1=sha1)
        if main._STAT_:
            self.ioc_stat.addCategory2('hash')
        self.misp_connection.add_hashes(event,
                                        category='Payload installation',
                                        sha256=sha256)
        if main._STAT_:
            self.ioc_stat.addCategory2('hash')

        if main._DOWNLOAD_MALWARE_:
            sample_path = self.config[
                'SampleRoot'] + '/' + LibIoC_DK.getReportPublicationYear(
                    filename)
            if not os.path.exists(sample_path + '/' + _hash):
                malware_buffer = self.malware_repo_connector.downloadMalware(
                    sha256, False)
                if malware_buffer:
                    if not os.path.exists(sample_path):
                        os.makedirs(sample_path)
                    f = open(sample_path + '/' + _hash, 'wb')
                    f.write(malware_buffer)
                    f.close()
                    extracted = self.malware_repo_connector.unzipMalware(
                        sample_path + '/' + _hash, sample_path)
                    if extracted.lower() != _hash.lower():
                        os.remove(sample_path + '/' + _hash)
                        _hash = extracted

                header_info = LibIoC_DK.getMalwareHeaderInfo(sample_path +
                                                             '/' + _hash)
                if header_info is not None:
                    self.addMalwareHeaderInfo(header_info, event)

        if main._STAT_ and self.ioc_stat.report_name != filename:
            self.ioc_stat.setReportBuffer(filename)

        if main._PARALLELIZE_ATTRIB_ADDITION_:
            # Parallelized Version
            print('[Hash] Parallelized attribute storing...')
            joblib.Parallel(joblib.cpu_count())(
                delayed(addAttribute)(self, event, attr) for attr in result)
        else:
            # Sequential Version
            for attr in result:
                self.addAttribute(event, attr, filename)

        LibIoC_DK.debugging("The MISP hash event created", main._DEBUG_,
                            main._LOGGING_, main.hFile)
        return True
Esempio n. 17
0
 def addAttribute(self, event, attr, filepath):
     LibIoC_DK.debugging(
         "Adding Attribute: filename(%s), attribute(%s)" %
         (LibIoC_DK.getFileName(filepath), attr), main._DEBUG_,
         main._LOGGING_, main.hFile)
     return addAttribute(self, event, attr, filepath)
Esempio n. 18
0
    def createMISPEventFromReport(self, ioc, filename, _date):
        LibIoC_DK.debugging(
            "Creating the MISP report event: %s" %
            (LibIoC_DK.getFileName(filename)), main._DEBUG_, main._LOGGING_,
            main.hFile)
        '''
        # if the MISP event for the filename already exists, add ioc in the event
        eid = self.getMISPEventID(LibIoC_DK.getFileName(filename))
        if eid:
            event = self.misp_connection.get_event(eid)
            for attr in ioc:
                self.addAttribute(event, attr)
            return False           
        '''
        if self.checkMISPReportEventExist(filename):
            LibIoC_DK.debugging("The MISP report event ALREADY exists",
                                main._DEBUG_, main._LOGGING_, main.hFile)
            return False

        try:
            if _date is not None:
                #_date = datetime.datetime.strptime(_date, "%m/%d/%Y").strftime("%Y-%m-%d")
                _date = _date.split("/")
                if int(_date[0]) > 12:
                    _date = datetime.date(int(_date[0]), int(_date[1]),
                                          int(_date[2])).isoformat()
                else:
                    _date = datetime.date(int(_date[2]), int(_date[0]),
                                          int(_date[1])).isoformat()
        except Exception as e:
            print e

        event = self.misp_connection.new_event(0,
                                               1,
                                               2,
                                               LibIoC_DK.getFileName(filename),
                                               date=_date)
        self.misp_connection.add_named_attribute(
            event,
            category='Other',
            type_value='comment',
            value=LibIoC_DK.getFileName(
                filename))  # this will work as the ground truth of IoC

        if main._STAT_ and self.ioc_stat.report_name != filename:
            self.ioc_stat.setReportBuffer(filename)

        if main._PARALLELIZE_ATTRIB_ADDITION_:
            # Parallelized Version
            print('[Report] Parallelized attribute storing...')
            attr_added = joblib.Parallel(joblib.cpu_count())(
                delayed(addAttribute)(self, event, attr, filename)
                for attr in ioc)
        else:
            # Sequential Version
            attr_added = False
            for attr in ioc:
                attr_added = self.addAttribute(event, attr,
                                               filename) or attr_added

        if (type(attr_added) is bool and not attr_added):
            self.misp_connection.delete_event(event['Event']['id'])
            LibIoC_DK.debugging(
                "NO attribute added for the report: %s" %
                (LibIoC_DK.getFileName(filename)), main._DEBUG_,
                main._LOGGING_, main.hFile)
            return False
        if type(attr_added) is list:
            if not (True in attr_added):
                self.misp_connection.delete_event(event['Event']['id'])
                LibIoC_DK.debugging(
                    "NO attribute added for the report: %s" %
                    (LibIoC_DK.getFileName(filename)), main._DEBUG_,
                    main._LOGGING_, main.hFile)
                return False

        LibIoC_DK.debugging("The MISP report event created", main._DEBUG_,
                            main._LOGGING_, main.hFile)
        return True
    def getMalwareStaticInfo(self, _hash, misp_event=False, misp=False):
        add_result_to_system = False
        if misp_event and misp:
            add_result_to_system = True
        retval = []
        
        _params = {
        'api_key': self.key,
        'hash': _hash
        }

        response = None
        static = None
        
        if self.getAIScore(_hash) < 60:
            return False
        
        while True:
            try:
                LibIoC_DK.debugging("Getting the malware static info", main._DEBUG_, main._LOGGING_, main.hFile)
                response = requests.get('https://private.api.malwares.com/v3/file/staticinfo', params=_params)
                self.query_counter = self.query_counter + 1
            except:
                LibIoC_DK.debugging("Exception occurred during the malware static info request", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            
            if response == None or response == '':
                LibIoC_DK.debugging("NO response returned as the malware static info", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            
            try:
                static = response.json()
            except:
                LibIoC_DK.debugging("Exception occurred during decoding response", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            
            if static['result_code'] == 1: # Data exists
                break
            elif static['result_code'] == 2: # Analyzing
                print("[Static Info] Analyzing ("+_hash+")")
                return False
            elif static['result_code'] == -14:  # Over the daily request limit
                LibIoC_DK.debugging("Over the daily request limit", main._DEBUG_, main._LOGGING_, main.hFile)
                LibIoC_DK.debugging("Accumulated the number of query: %d" %(self.query_counter), main._DEBUG_, main._LOGGING_, main.hFile)
                self.waitToNextMidnight_UTC()
                self.query_counter = 0
            elif static['result_code'] <= 0:
                LibIoC_DK.debugging("Error returned while getting the malware static info", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
                
        # add all different hash representations of the malware 
        if 'md5' in static:
            static_input = ('static','md5',static['md5'])
            retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
        if 'sha1' in static:
            static_input = ('static','sha1',static['sha1'])
            retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
        if 'sha256' in static:
            static_input = ('static','sha256',static['sha256'])
            retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
            
        # add string information in the malware
        if 'strings_result' in static and static['strings_result'] is not None:
            prev_offset = 0
            for _str in static['strings_result']['strings']:
                # The concatenated attribute the right after previous one without null string, we ignore it. 
                offset_distance = int(_str['offset'],16) - prev_offset
                prev_offset = int(_str['offset'],16)
                charset = _str['charset']
                if charset == 'ascii':
                    charset_len = 1
                elif charset == 'unicode':
                    charset_len = 2
                    
                if offset_distance <= len(_str['strings'])*charset_len:
                    continue
                
                if _str['pattern'] == 'url':
                    # since the returned string results does not always contain clear ioc, filter the outputs.
                    ioc = LibIoC_DK.filterRegularIoC(_str['strings'], _str['pattern'])
                    if ioc is not None:
                        for _ioc in ioc:
                            static_input = ('static','url',_ioc)
                            retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
                                    
                elif _str['pattern'] == 'ip':                    
                    # since the returned string results does not always contain clear ioc, filter the outputs.
                    ioc = LibIoC_DK.filterRegularIoC(_str['strings'], _str['pattern'])
                    if ioc is not None:
                        for _ioc in ioc:
                            if _ioc.endswith('0.0'):
                                continue
                            static_input = ('static','ip',_ioc)
                            retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
                                
                elif _str['pattern'] == 'path':
                    if LibIoC_DK.isFileofInterest(_str['strings']):
                        static_input = ('static','filepath',_str['strings'])
                        retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
 
                # We found the almost the hash attribute returned as static analysis is errornous and meaningless,
                # since it is very unusual to insert hashes with in the malware code.
                elif _str['pattern'] == 'hash':
                    None
# 
#                     # since the returned string results does not always contain clear ioc, filter the outputs.
#                     ioc = LibIoC_DK.filterRegularIoC(_str['strings'], _str['pattern'])
#                     if ioc is not None:
#                         # this condition filters irrelevant strings look like hash values
#                         if len(ioc) > 1:
#                             remove_val = []
#                             for i in range(len(ioc)-1):
#                                 if remove_val.count(ioc[i]) != 0:
#                                     continue
#                                 for j in range(i+1,len(ioc)):
#                                     tmp1 = ioc[i].encode('utf-8')
#                                     tmp2 = ioc[j].encode('utf-8')
#                                     if tmp1 in tmp2:
#                                         if remove_val.count(ioc[i]) == 0:
#                                             remove_val.append(ioc[i])
#                                         if remove_val.count(ioc[j]) == 0:
#                                             remove_val.append(ioc[j])
#                             for r in range(len(remove_val)):
#                                 while ioc.count(remove_val[r]) != 0:
#                                     ioc.remove(remove_val[r])
#                         
#                         for _ioc in ioc:
#                             _ioc = _ioc.encode('utf-8')
#                             if len(_ioc) == 32:
#                                 static_input = ('static','md5',_ioc)
#                                 retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
#                             elif len(_ioc) == 40:
#                                 static_input = ('static','sha1',_ioc)
#                                 retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
#                             elif len(_ioc) == 64:
#                                 static_input = ('static','sha256',_ioc)
#                                 retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
                                
                elif _str['pattern'] == 'email':        
                    static_input = ('static','email',_str['strings'])
                    retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
                else:
                    if _str['strings']:
                        static_input = ('static','string',_str['strings'])
                        retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
            
        # store digital signature information of the malware if available
        if 'peinfo' in static:
#            if 'internal_name' in static['peinfo']['file_info']:
#                static_input = ('static','filename/internal_name',static['peinfo']['file_info']['internal_name'])
#                retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
                                      
            if 'original_filename' in static['peinfo']['file_info'] and static['peinfo']['file_info']['original_filename']:
                static_input = ('static','filename/original_filename',static['peinfo']['file_info']['original_filename'])
                retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
                                      
            if static['peinfo']['signcheck']['verified'] != 'Unsigned':
                for s in static['peinfo']['signcheck']['signers_details']:
					if '00:00:00:00:00' in s['serial_number']:
						continue
					static_input = ('static','signcheck/digital sign serial number',s['serial_number'])
					retval = self.addExtractedInfo(static_input, add_result_to_system, retval, misp, misp_event)
                      
        if type(retval) and len(retval) > 0:  
            LibIoC_DK.debugging("The malware static info returned", main._DEBUG_, main._LOGGING_, main.hFile)
            return retval
        else:
            LibIoC_DK.debugging("The malware static info NOT returned", main._DEBUG_, main._LOGGING_, main.hFile)
            return False
 def isFileofInterest(self, target):
     return LibIoC_DK.isFileofInterest(target)
    def getMalwareBehaviorInfo(self, _hash, misp_event=False, misp=False):
        add_result_to_system = False
        if misp_event and misp:
            add_result_to_system = True
            
        retval = []
        
        _params = {
        'api_key': self.key,
        'hash': _hash,
        'env_type': 2
        }
        
        response = None
        behavior = None
        while True:
            try:
                LibIoC_DK.debugging("Getting the malware behavior info", main._DEBUG_, main._LOGGING_, main.hFile)
                response = requests.get('https://private.api.malwares.com/v3/file/behaviorinfo', params=_params)
                self.query_counter = self.query_counter + 1
            except:
                LibIoC_DK.debugging("Exception occurred during the malware behavior info request", main._DEBUG_, main._LOGGING_, main.hFile)
                return False

            try:
                behavior = response.json()
            except:
                LibIoC_DK.debugging("Exception occurred during decoding response", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            
            if behavior['result_code'] == 1: # Data exists
                break
            elif behavior['result_code'] == 2:  # Analyzing
                LibIoC_DK.debugging("Analyzing the malware behavior info", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            elif behavior['result_code'] == -14:  # Over the daily request limit
                LibIoC_DK.debugging("Over the daily request limit", main._DEBUG_, main._LOGGING_, main.hFile)
                LibIoC_DK.debugging("Accumulated the number of query: %d" %(self.query_counter), main._DEBUG_, main._LOGGING_, main.hFile)
                self.waitToNextMidnight_UTC()
                self.query_counter = 0
            elif behavior['result_code'] <= 0:
                LibIoC_DK.debugging("Error returned while getting the malware behavior info", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            
        # add all different malware hash representations 
        if 'md5' in behavior:
            behavior_input = ('behavior','md5',behavior['md5'])
            retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
        if 'sha1' in behavior:
            behavior_input = ('behavior','sha1',behavior['sha1'])
            retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
        if 'sha256' in behavior:
            behavior_input = ('behavior','sha256',behavior['sha256'])
            retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
            
        # add behavior analysis results
        if 'behavior' in behavior:
            for bb in behavior['behavior']:
                if 'file_write_event' in bb and bb['file_write_event'] is not None:
                    for _filename in bb['file_write_event']:
                        if LibIoC_DK.isFileofInterest(_filename['filename']):
                            behavior_input = ('behavior','filename/file_write_event',_filename['filename'])
                            retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
                            
                if 'service_create_event' in bb and bb['service_create_event'] is not None:
                    for service in bb['service_create_event']:
                        if service['displayname']:
                            behavior_input = ('behavior','string/service display name',service['displayname'])
                            retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
                            
                if 'process_create_event' in  bb and bb['process_create_event'] is not None:
                    for process in bb['process_create_event']:
                        if 'sha256' in process and process['sha256'].lower() != behavior['sha256'].lower():
                            if self.isNormalProcess(self.normal_process_list_root, process['sha256'].lower()):
                                continue
                            ai_score = self.getAIScore(process['sha256'])
                            if ai_score >= 70:
                                behavior_input = ('behavior','sha256',process['sha256'])
                                retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
                            else:
                                LibIoC_DK.debugging("Normal process", main._DEBUG_, main._LOGGING_, main.hFile)
                                self.addNormalProcessList(self.normal_process_list_root, process['newprocessname'], process['sha256'].lower(), str(ai_score))
                                self.saveNormalProcessList(self.normal_process_list_root)
                    
        # add network analysis results
        if 'network' in behavior and behavior['network'] is not None:
            for flow in behavior['network']['flow']:
                flow_type = flow['protocol']
                if flow['application']:
                    flow_type += '_'+flow['application']
                
                if flow['application'] == 'DNS' and 'detail_info' in flow:
                    for detail in flow['detail_info']:
                        if detail['dns_msg_type'] == 'QUERY':
                            behavior_input = ('behavior','host/'+flow_type,detail['query_name'])
                            retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
                        elif detail['dns_msg_type'] == 'ANSWER_IPV4':
                            behavior_input = ('behavior','dest_ip/'+flow_type,detail['ipv4_address'])
                            retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
                elif 'protocol' in flow and (flow['protocol'] == 'TCP' or flow['protocol']=='UDP' or flow['protocol']=='IGMP' or flow['protocol']=='IGMP'):
                    if flow['dest_ip'] != '<MWS_GUEST_IP>':   # malwares.com virtual machine IP
                        behavior_input = ('behavior','dest_ip/'+flow_type,flow['dest_ip'])
                        retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
                    elif flow['src_ip'] != '<MWS_GUEST_IP>':   # malwares.com virtual machine IP
                        behavior_input = ('behavior','src_ip/'+flow_type,flow['src_ip'])
                        retval = self.addExtractedInfo(behavior_input, add_result_to_system, retval, misp, misp_event)
                    
        if type(retval)==list and len(retval) > 0:  
            LibIoC_DK.debugging("The malware behavior info returned", main._DEBUG_, main._LOGGING_, main.hFile)
            return retval
        else:
            LibIoC_DK.debugging("The malware behavior info NOT returned", main._DEBUG_, main._LOGGING_, main.hFile)
            False
Esempio n. 22
0
def addAttribute(connector, event, attr, filepath):
    # if attr[0], the attribute type, is written in large character, the attr comes from the ioc parser,
    # otherwise from the malware repository.
    attribute_info = attr[1].split('/')
    attribute_type = attribute_info[0].lower()
    if len(attribute_info) == 2:
        attribute_comment = attribute_info[1]
    else:
        attribute_comment = ''
    attr_lower_case = attr[2].lower().replace('[.]', '.')

    attribute_added = False
    event_name, source_name = connector.getEventFileName(event=event)

    if not event_name:
        return False

    try:
        event_name = event_name.encode('utf-8')
        source_name = source_name.encode('utf-8')
    except:
        return False

    # if the attribute is already stored in the MISP event, skip it
    tmp_id = connector.checkAttribute(attr=attr[2])
    sharedIoC = False
    if tmp_id:
        for curr_id in tmp_id:
            if str(event['Event']['id']) == curr_id:
                return False
            else:
                if LibIoC_DK.isHash(event_name):
                    for a in event['Event']['Attribute']:
                        if a['category'] == 'Other' and a[
                                'value'] == connector.misp_connection.get_event(
                                    curr_id)['Event']['info']:
                            if main._STAT_:
                                connector.ioc_stat.addCategory3(
                                    attr_lower_case,
                                    connector.ioc_stat.convertIoCType(
                                        attribute_type))  # category 3
                            sharedIoC = True
                elif LibIoC_DK.isHash(
                        connector.misp_connection.get_event(curr_id)['Event']
                    ['info']):
                    e = connector.misp_connection.get_event(curr_id)
                    for a in e['Event']['Attribute']:
                        if a['category'] == 'Other' and a['value'] == event[
                                'Event']['info']:
                            if main._STAT_:
                                connector.ioc_stat.addCategory3(
                                    attr_lower_case,
                                    connector.ioc_stat.convertIoCType(
                                        attribute_type))  # category 3
                            sharedIoC = True

                if sharedIoC:
                    break

    if attr[0] == 'report' or attr[0] == 'static':
        attribute_category = 'External analysis'
    elif attr[0] == 'behavior':
        attribute_category = 'Artifacts dropped'

    if main._MODE_ == 1 or main._MODE_ == 3:
        if attribute_type == 'host':  # or attribute_type == 'url':
            connector.misp_connection.add_url(event,
                                              attr[2],
                                              comment=attribute_comment)
            attribute_added = True
        elif attribute_type == 'ip' or attribute_type == 'src_ip':
            connector.misp_connection.add_ipsrc(event,
                                                attr[2],
                                                comment=attribute_comment)
            attribute_added = True
        elif attribute_type == 'dest_ip':
            connector.misp_connection.add_ipdst(event,
                                                attr[2],
                                                comment=attribute_comment)
            attribute_added = True
        elif attribute_type == 'email':
            connector.misp_connection.add_email_src(event,
                                                    attr[2],
                                                    comment=attribute_comment)
            attribute_added = True
        elif attribute_type == 'cve':
            connector.misp_connection.add_named_attribute(
                event,
                category=attribute_category,
                type_value='vulnerability',
                value=attr[2],
                comment=attribute_comment)
            attribute_added = True
#        elif attribute_type == 'registry':
#            connector.misp_connection.add_named_attribute(event, category=attribute_category, type_value='regkey', value=attr[2], comment=attribute_comment)
#            attribute_added = True
        elif attribute_type == 'filename':
            if LibIoC_DK.isFileofInterest(attr[2]):
                connector.misp_connection.add_named_attribute(
                    event,
                    category=attribute_category,
                    type_value='filename',
                    value=attr[2],
                    comment=attribute_comment)
                attribute_added = True
#        elif attr[0] == 'Filepath':
#            connector.misp_connection.add_named_attribute(event, category='External analysis', type_value='text', value=attr[1], comment='file path')
#            attribute_added = True
        elif attribute_type == 'pdb':
            connector.misp_connection.add_named_attribute(
                event,
                category='Artifacts dropped',
                type_value='pdb',
                value=attr[2],
                comment=attribute_comment)
            attribute_added = True
        elif attribute_type == 'signcheck':
            connector.misp_connection.add_named_attribute(
                event,
                category=attribute_category,
                type_value='text',
                value=attr[2],
                comment=attribute_comment)
            attribute_added = True

        # If a malware hash is found, check if it is already stored in MISP as an attribute.
        # If MISP has already stored it, just add it as an attribute of the current event.
        # Otherwise, create new MISP event if the analysis result could be found from malware repository.
        # If no the analysis result found from the repository, just add it as an attribute of the current event.
        elif attribute_type == 'md5' or attribute_type == 'sha1' or attribute_type == 'sha256':
            if connector.checkAttribute(attr_lower_case):
                if attribute_type == 'md5':
                    connector.misp_connection.add_hashes(
                        event,
                        category=attribute_category,
                        md5=attr_lower_case,
                        comment=attribute_comment)
                elif attribute_type == 'sha1':
                    connector.misp_connection.add_hashes(
                        event,
                        category=attribute_category,
                        sha1=attr_lower_case,
                        comment=attribute_comment)
                elif attribute_type == 'sha256':
                    connector.misp_connection.add_hashes(
                        event,
                        attribute_category,
                        sha256=attr_lower_case,
                        comment=attribute_comment)
                attribute_added = True
            elif LibIoC_DK.isHash(
                    event['Event']
                ['info']) and connector.createMISPEventFromHash(
                    attr_lower_case, filepath) and main._STAT_:
                connector.ioc_stat.increaseAnalyzedAdditionalHash()

        elif attribute_type == 'string':
            connector.misp_connection.add_named_attribute(
                event,
                category=attribute_category,
                type_value='text',
                value=attr[2],
                comment=attribute_comment)
            attribute_added = True

    # IoC statistics calculation.
    if main._STAT_:
        if not sharedIoC:  # and attribute_added:
            if LibIoC_DK.isHash(event_name):
                if attribute_added:
                    if connector.ioc_stat.checkIoCInReport(
                            attr[2]) or connector.ioc_stat.checkIoCInReport(
                                attr_lower_case):
                        connector.ioc_stat.addCategory2(
                            connector.ioc_stat.convertIoCType(
                                attribute_type))  # category 2
                    else:
                        connector.ioc_stat.addCategory4(
                            connector.ioc_stat.convertIoCType(
                                attribute_type))  # category 4
            else:
                if attribute_added:
                    connector.ioc_stat.addCategory1(
                        connector.ioc_stat.convertIoCType(
                            attribute_type))  # category 1
                else:
                    connector.ioc_stat.addcategory5(
                        connector.ioc_stat.convertIoCType(
                            attribute_type))  # category 5

    return attribute_added
    def getAIScore(self, _hash):
        _params = {
        'api_key': self.key,
        'hash': _hash}
        response = None
        ai_score = None
        while True:
            try:
                LibIoC_DK.debugging("Getting the malware MAX score", main._DEBUG_, main._LOGGING_, main.hFile)
                response = requests.get('https://private.api.malwares.com/v3/file/mwsinfo', params=_params)
                self.query_counter = self.query_counter + 1
            except:
                LibIoC_DK.debugging("Exception occurred during the malware MAX score request", main._DEBUG_, main._LOGGING_, main.hFile)
                return False

            try:
                ai_score = response.json()
            except:
                LibIoC_DK.debugging("Exception occurred during decoding response", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            
            if ai_score['result_code'] == 1: # Data exists
                break
            elif ai_score['result_code'] == 2:  # Analyzing
                LibIoC_DK.debugging("Analyzing the malware MAX score", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            elif ai_score['result_code'] == -14:  # Over the daily request limit
                LibIoC_DK.debugging("Over the daily request limit", main._DEBUG_, main._LOGGING_, main.hFile)
                LibIoC_DK.debugging("Accumulated the number of query: %d" %(self.query_counter), main._DEBUG_, main._LOGGING_, main.hFile)
                self.waitToNextMidnight_UTC()
                self.query_counter = 0
            elif ai_score['result_code'] <= 0:
                LibIoC_DK.debugging("Error returned while getting the malware MAX score", main._DEBUG_, main._LOGGING_, main.hFile)
                return False
            
        return ai_score['ai_score']
Esempio n. 24
0
                    
def addFileProcessingResult(root, fName, result):
    ET.SubElement(root, 'file', {'title':fName.decode('utf-8'),'result':result})
    return
 
def saveFileProcessingResult(root):
    tree = ET.ElementTree(root)
    tree.write(fileProcessingResult_file)
    return

'''
 The main routine
'''
if __name__ == '__main__':
    if _DEBUG_:
        LibIoC_DK.debugging("**********************************************************", _DEBUG_, _LOGGING_, hFile)
        LibIoC_DK.debugging("******System Execution at %s******"%(str(datetime.now())), _DEBUG_, _LOGGING_, hFile)
        LibIoC_DK.debugging("**********************************************************", _DEBUG_, _LOGGING_, hFile)

    # Load configuration file
    config_value = getConfig(config_file)
    file_names = getFileName(config_value['ReportRoot'])
    misp = MISPConnector.MISPConnector(config_value, ioc_stat)
    
    if _PARALLELIZE_FILE_PROCESSING_:
        joblib.Parallel(joblib.cpu_count())(delayed(processFile)(misp, f, config_value) for f in file_names)
    else:
        processFileList(misp, file_names, config_value)
        
    if _DEBUG_:
        LibIoC_DK.debugging("All file processing FINISHED!!!", _DEBUG_, _LOGGING_, hFile)