Example #1
0
# can also try getting all emails not in inbox
mail.select("INBOX", readonly)
result, data = mail.search(None, "ALL")

id_list=data[0].split(' ')


# process the last 50 emails
for id_current in id_list[-200:]:
	result, data = mail.fetch(id_current, "(RFC822)") # fetch the email body (RFC822) for the given ID
	print(id_current,email_message['To'],email_message['From'],email_message['Subject'])
	raw_email=data[0][1]
	email_message = email.message_from_string(raw_email)
	if 'CEF analysis' in email_message['Subject'] and email_message['From']=='*****@*****.**':
		msg = email.message_from_string(raw_email)
		for part in list(msg.walk()):
			#if part.get('Content-Disposition') is None:
			if part.get_filename()==None:
				# print part.as_string()
				continue
			fileName = part.get_filename()
			print(fileName)
			fileName=email_message['Date']+'_'+fileName
			# can create new folders with os
			fp = open(fileName, 'wb')
			fp.write(part.get_payload(decode=True))
			fp.close()



Example #2
0
class CuckooRequest(object):

    def __init__(self, message):
        self.message = message
        
        '''cuckooinbox config variables'''
        config = Config(cfg=os.path.join(CUCKOO_ROOT,"cuckooinbox","cuckooinbox.conf"))
        config = config.get('cuckooinbox')
        self.username = config['username']
        self.passwd = config['passwd']
        self.imap = config['imap']
        self.imap_ssl = config['imap_ssl']
        self.smtp_server = config['smtp']
        self.interval = config['interval']
        self.archive_folder = config['archive_folder']
        self.email_whitelist = config['email_whitelist']
        self.url_limit = config['url_limit']
        self.attachment_limit = config['attachment_limit'] 
        self.zip_reports = config['zip_reports']
        self.zip_password = config['zip_password']
        self.url_blacklist = config['url_blacklist']
        self.url_file_backlist = config['url_file_backlist']
        self.machine = config['machine']
        
        '''imap variables'''
        self.server = IMAPClient(self.imap, use_uid=True, ssl=self.imap_ssl)
        self.server.login(self.username, self.passwd)
        self.attachment_counter = 0
        
        '''message variables'''
        self.msg = MIMEMultipart()
        self.response_msg = MIMEMultipart()
        self.response_urls = []
        self.response_attachments = []
        self.sender = ''
        self.subject = ''
        self.cc_list = []

        '''logging object'''
        self.log_entry = Logger('cuckooinbox.log')

        '''cuckoo variables'''
        self.taskids = []
        self.db  = Database()
        self.url_counter = 0 # tracks url count to not exceed url_limit
    
    def fetch(self, message):
        
        '''set retrieve folder'''
        select_info = self.server.select_folder('INBOX')
        '''fetch mail'''
        response = self.server.fetch(self.message, ['RFC822'])
    
        '''parse received email'''
        for msgid, data in response.iteritems():
            msg_string = data['RFC822']
            self.msg = email.message_from_string(msg_string)
            
            '''parse 'Name <*****@*****.**>' format'''
            if '<' in self.msg['From']: self.sender = self.msg['From'].split('<'[0])[-1][:-1]            
            else: self.sender = self.msg['From']
            self.subject = self.msg['Subject']
            
            '''print and log successful receive'''
            self.log_entry.logEvent('[+] Received email ID: %d from %s [%s]' % (msgid, self.msg['From'], self.msg['Subject']))
            
            '''save CC info for reply later'''
            if self.msg['Cc']:
                for address in  self.msg['Cc'].split(', '): self.cc_list.append(address)
                self.log_entry.logEvent( '[*] Email \"%s\" from %s cc\'d the following addresses: %s' % (self.msg['Subject'],self.msg['From'],', '.join(str(copies) for copies in self.cc_list)))
            
            file_whitelist = ['exe', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'zip']
            
            '''parse message elements'''
            for part in self.msg.walk():
                if part.get_content_type() == 'text/plain':
                    self.log_entry.logEvent( '[*] Email ID: %d has a plain text object.' % msgid)
                    content = part.get_payload()
                    self.processText(content)
                elif part.get_content_type() == 'text/html':
                    self.log_entry.logEvent('[*] Email ID: %d has a html object.' % msgid)
                    content = part.get_payload()
                    self.processText(content)
                elif 'application' in part.get_content_type():
                    # email attachment has no filename
                    if not part.get_param('name'): return 0
                    # cuckoo file analysis whitelist
                    if not part.get_param('name').split('.'[0])[-1] in file_whitelist: break
                    # increment and break if limit is reached 
                    if (self.attachment_limit != 0 and self.attachment_counter == self.attachment_limit): break
                    self.attachment_counter += 1
                    self.log_entry.logEvent('[*] Email ID: %d has an attachment object.' % msgid)
                    content = part.get_payload()
                    file_name = part.get_param('name')
                    self.processAttachment(content, file_name)
                    
            '''archive email when done submitting cuckoo tasks'''
            try:
                self.archive(self.message)
            except:
                self.server.delete_messages(self.message)
                self.server.expunge()

    def processText(self, content):
        
        '''reformat quoted string mail to plain html'''
        body = quopri.decodestring(content)
        soup = BeautifulSoup(body)
        # todo analyze href spoof
        
        '''parse and analyze hyperlinks'''
        for url in soup.findAll('a'):
            # strip mailto links
            if url['href'].split(':'[0])[0] == 'mailto' : continue
            # strip blacklist links
            for item in self.url_blacklist.split(','):
                if item in url['href']: return 0
            # strip blacklist link filetypes
            for item in self.url_file_backlist.split(','):
                if item in url['href'].split('.'[0])[-1]: return 0
            else:
                self.response_urls.append(url['href'])
		if self.machine:
                    task_id = self.db.add_url(url['href'], package="ie", timeout=15, machine=self.machine)
                else: task_id = self.db.add_url(url['href'], package="ie", timeout=15)
                if task_id:
                    self.taskids.append(task_id)
                    self.log_entry.logEvent('[+] URL \"%s\" added as task with ID %d' % (url['href'],task_id))
                    # increment counter and exit loop if limit is reached
                    self.url_counter += 1
                    if (self.url_limit != 0 and self.url_counter == self.url_limit): return 0
                else:
                    self.log_entry.logEvent("[!] Error: adding task to database" % (url['href'],task_id))
                    break

    def processAttachment(self, content, filename):
        '''create temp file for analysis'''
        temp_file = tempfile.NamedTemporaryFile(prefix=filename.split('.'[0])[0], suffix='.' + filename.split('.'[0])[1])
        temp_file.write(content)
        self.response_attachments.append(filename)
        
        '''add to cuckoo tasks'''
        task_id = self.db.add_path(temp_file.name, timeout=10, package=filename.split('.'[0])[1])
        temp_file.flush()
        if task_id:
            self.taskids.append(task_id)
            self.log_entry.logEvent('[+] File \"%s\" added as task with ID %d' % (filename,task_id))
        else:
            self.taskids.append(task_id)
            self.log_entry.logEvent("[!] Error adding task to database")
            
        '''make sure file gets submitted before we toss it'''
        timeout = time.time() + 120
        while time.time() < timeout:
            if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(task_id),"reports","report.html")): continue
            time.sleep(.25)
        temp_file.close()


    def archive(self, message):

        select_info = self.server.select_folder('INBOX')
        '''cleanup mailbox'''
        self.server.copy(self.message,self.archive_folder)
        self.server.delete_messages(self.message)
        self.server.expunge()
        
    def expunge(self, message):

        select_info = self.server.select_folder('INBOX')
        '''expunge cuckooinbox request'''
        self.server.delete_messages(self.message)
        self.server.expunge()


    def zipResults(self,):
        
        '''create temporary zip file'''
        temp_zip = tempfile.TemporaryFile(prefix='report',suffix='.zip')
        zip_file = zipfile.ZipFile(temp_zip, 'w')
        if self.zip_password: zip_file.setpassword(self.zip_password)
        
        '''set zip to compress'''
        try:
            import zlib
            compression = zipfile.ZIP_DEFLATED
        except:
            compression = zipfile.ZIP_STORED
        modes = { zipfile.ZIP_DEFLATED: 'deflated',
                zipfile.ZIP_STORED:   'stored',}
        
        '''wait for reports to finish then add to list'''
        for id in self.taskids:
            # timeout error handling
            if not os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html")):
                self.log_entry.logEvent('cuckooinbox error: report timeout reached on task ID %d.' % id)
            else: 
                zip_file.write(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html"),\
                arcname = 'report' + str(id) + '.html', compress_type=compression)
        zip_file.close()
            
        '''attach zip to email message'''
        temp_zip.seek(0)
        email_file = MIMEBase('application', 'zip')
        email_file.set_payload(temp_zip.read())
        Encoders.encode_base64(email_file)
        email_file.add_header('Content-Disposition', 'attachment; filename="report.zip"')
        self.response_msg.attach(email_file)

    def sendReport(self,):

        '''create email header'''
        assert type(self.cc_list)==list
        assert type(self.taskids)==list
        self.response_msg['From'] = self.username
        self.response_msg['To'] = self.sender
        self.response_msg['Cc'] = ", ".join(self.cc_list)
        self.response_msg['Date'] = formatdate(localtime=True)
        self.response_msg['Subject'] = 'cuckooinbox report: ' + self.subject

        '''attach cuckooinbox email body'''
        for id in self.taskids:
	    '''wait for reports to finish before sending'''
	    timeout = time.time() + 120
            while time.time() < timeout:
                if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html")): continue
            	time.sleep(.25)
            if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","inbox.html")):
                file = open(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","inbox.html"))
                body = '<html>' + \
                    '<div class="section-title">'+ \
                    '<h2>Task ID %d <small></small></h2>' % id + \
                    '</div>'+ \
                    '<table class="table table-striped table-bordered">'+ \
                    file.read() + \
                    '</html>'
                file.close()
                response_text = ''.join(body)
                self.response_msg.attach(MIMEText(response_text,'html'))
            else: print '[!] Could not find cuckoobox report files.'

        '''wait for analysis to finish and zip the reports'''
        self.zipResults()
        
        '''send the message'''
	if '@gmail.com' in self.username:
	    smtp = smtplib.SMTP('smtp.gmail.com',587)
	    smtp.starttls()
	    smtp.login(self.username, self.passwd)
	else:
            smtp = smtplib.SMTP(self.smtp_server)
            try: smtp.login(self.username,self.passwd)
            except:
                self.log_entry.logEvent('[!] SMTP login failed.')
        try: smtp.sendmail(self.username, self.sender, self.response_msg.as_string())
        except:
            self.log_entry.logEvent('SMTP message %s failed to send.' % self.subject)
        smtp.close()
        self.log_entry.logEvent('[-] Sent "%s" report to %s' % (self.subject, self.sender))
        self.server.logout()
Example #3
0
class CuckooRequest(object):

    def __init__(self, message):

        self.message = message
        
        '''cuckooinbox config variables'''
        config = Config(cfg=os.path.join(CUCKOO_ROOT,"cuckooinbox","cuckooinbox.conf"))
        config = config.get('cuckooinbox')
        self.username = config['username']
        self.passwd = config['passwd']
        self.imap = config['imap']
        self.imap_ssl = config['imap_ssl']
        self.smtp_server = config['smtp']
        self.interval = config['interval']
        self.email_whitelist = config['email_whitelist']
        self.url_limit = config['url_limit']
        self.attachment_limit = config['attachment_limit'] 
        self.zip_reports = config['zip_reports']
        self.zip_password = config['zip_password']
        self.url_blacklist = config['url_blacklist']
        self.url_file_backlist = config['url_file_backlist']
        self.machine = config['machine']
        
        '''imap variables'''
        self.server = IMAPClient(self.imap, use_uid=True, ssl=self.imap_ssl)
        self.server.login(self.username, self.passwd)
        self.attachment_counter = 0
        
        '''message variables'''
        self.msg = MIMEMultipart()
        self.response_msg = MIMEMultipart()
        self.response_urls = []
        self.response_attachments = []
        self.sender = ''
        self.subject = ''
        self.cc_list = []

        '''logging object'''
        self.log_entry = Logger('cuckooinbox.log')

        '''cuckoo variables'''
        self.taskids = []
        self.db  = Database()
        self.url_counter = 0 # tracks url count to not exceed url_limit
   
 
    def fetch(self, message):
        
        '''set retrieve folder'''
        select_info = self.server.select_folder('INBOX')
        '''fetch mail'''
        response = self.server.fetch(self.message, ['RFC822'])
    
        '''parse received email'''
        for msgid, data in response.iteritems():
            msg_string = data['RFC822']
            self.msg = email.message_from_string(msg_string)
            
            '''parse 'Name <*****@*****.**>' format'''
            if '<' in self.msg['From']: self.sender = self.msg['From'].split('<'[0])[-1][:-1]            
            else: self.sender = self.msg['From']
            self.subject = self.msg['Subject']
            
            '''print and log successful receive'''
            self.log_entry.logEvent('[+] Received email ID: %d from %s [%s]' % (msgid, self.msg['From'], self.msg['Subject']))
            
            '''save CC info for reply later'''
            if self.msg['Cc']:
                for address in  self.msg['Cc'].split(', '): self.cc_list.append(address)
                self.log_entry.logEvent( '[*] Email \"%s\" from %s cc\'d the following addresses: %s' % (self.msg['Subject'],self.msg['From'],', '.join(str(copies) for copies in self.cc_list)))
            
            file_whitelist = ['exe', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'zip']
            
            '''parse message elements'''
            for part in self.msg.walk():

                if part.get_content_type() == 'text/plain':
                    self.log_entry.logEvent( '[*] Email ID: %d has a plain text object.' % msgid)
                    content = part.get_payload()
                    self.processPlainText(content)

                elif part.get_content_type() == 'text/html':
                    self.log_entry.logEvent('[*] Email ID: %d has a html object.' % msgid)
                    content = part.get_payload()
                    self.processText(content)

                elif 'application' in part.get_content_type():
                    # email attachment has no filename
                    if not part.get_param('name'): return 0
                    # cuckoo file analysis whitelist
                    if not part.get_param('name').split('.'[0])[-1] in file_whitelist: break
                    # increment and break if limit is reached 
                    if (self.attachment_limit != 0 and self.attachment_counter == self.attachment_limit): break
                    self.attachment_counter += 1
                    self.log_entry.logEvent('[*] Email ID: %d has an attachment object.' % msgid)
                    content = part.get_payload()
                    file_name = part.get_param('name')
                    self.processAttachment(content, file_name)
                    

    def processPlainText(self, content):

	url_list = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', content)

	for url in url_list:

            # strip blacklist links and filetypes
	    if url in self.url_blacklist.split(','): return 0
	    if url in self.url_file_backlist.split(','): return 0

            self.response_urls.append(url)

            if self.machine:
                task_id = self.db.add_url(url, package="ie", timeout=15, machine=self.machine)
            else: task_id = self.db.add_url(url, package="ie", timeout=15)
            if task_id:
                self.taskids.append(task_id)
                self.log_entry.logEvent('[+] URL \"%s\" added as task with ID %d' % (url, task_id))
                # increment counter and exit loop if limit is reached
                self.url_counter += 1
                if (self.url_limit != 0 and self.url_counter == self.url_limit): return 0
            else:
                self.log_entry.logEvent("[!] Error: adding task to database" % (url, task_id))
                break	

		
    def processText(self, content):

        '''reformat quoted string mail to plain html'''
        body = quopri.decodestring(content)
        soup = BeautifulSoup(body)
        # todo analyze href spoof
	
        '''parse and analyze hyperlinks'''
        for url in soup.findAll('a'):
            # strip mailto links
            if url['href'].split(':'[0])[0] == 'mailto' : continue
	    url = url['href'] 

            # strip blacklist links and filetypes
	    if url in self.url_blacklist.split(','): return 0 
	    if url in self.url_file_backlist.split(','): return 0

            else:
                self.response_urls.append(url)
                if self.machine:
                    task_id = self.db.add_url(url, package="ie", timeout=15, machine=self.machine)
                else: task_id = self.db.add_url(url, package="ie", timeout=15)
                if task_id:
                    self.taskids.append(task_id)
                    self.log_entry.logEvent('[+] URL \"%s\" added as task with ID %d' % (url, task_id))
                    # increment counter and exit loop if limit is reached
                    self.url_counter += 1
                    if (self.url_limit != 0 and self.url_counter == self.url_limit): return 0
                else:
                    self.log_entry.logEvent("[!] Error: adding task to database" % (url, task_id))
                    break


    def processAttachment(self, content, filename):

        '''create temp file for analysis'''
        temp_file = tempfile.NamedTemporaryFile(prefix=filename.split('.'[0])[0], suffix='.' + filename.split('.'[0])[1])
        temp_file.write(content)

        '''add to cuckoo tasks'''
        task_id = self.db.add_path(temp_file.name, timeout=10, package=filename.split('.'[0])[1])
        if task_id:
            self.taskids.append(task_id)
            self.log_entry.logEvent('[+] File \"%s\" added as task with ID %d' % (filename,task_id))
        else:
            self.taskids.append(task_id)
            self.log_entry.logEvent("[!] Error adding task to database")
	    return 0
            
        '''make sure file gets submitted before we toss it'''
        timeout = time.time() + 120
        while time.time() < timeout:
            if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(task_id),"reports","report.html")): continue
            time.sleep(.25)

	self.response_attachments.append(filename)
	temp_file.flush()
        temp_file.close()


    def zipResults(self,):
        
        '''create temporary zip file'''
        temp_zip = tempfile.TemporaryFile(prefix='report',suffix='.zip')
        zip_file = zipfile.ZipFile(temp_zip, 'w')
        if self.zip_password: zip_file.setpassword(self.zip_password)
        
        '''set zip to compress'''
        try:
            import zlib
            compression = zipfile.ZIP_DEFLATED
        except:
            compression = zipfile.ZIP_STORED
        modes = { zipfile.ZIP_DEFLATED: 'deflated',
                zipfile.ZIP_STORED:   'stored',}
        
        '''wait for reports to finish then add to list'''
        for id in self.taskids:
            # timeout error handling
            if not os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html")):
                self.log_entry.logEvent('cuckooinbox error: report timeout reached on task ID %d.' % id)
            else: 
                zip_file.write(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html"),\
                arcname = 'report' + str(id) + '.html', compress_type=compression)
        zip_file.close()
            
        '''attach zip to email message'''
        temp_zip.seek(0)
        email_file = MIMEBase('application', 'zip')
        email_file.set_payload(temp_zip.read())
        Encoders.encode_base64(email_file)
        email_file.add_header('Content-Disposition', 'attachment; filename="report.zip"')
        self.response_msg.attach(email_file)


    def sendReport(self,):

        '''create email header'''
        assert type(self.cc_list)==list
        assert type(self.taskids)==list
        self.response_msg['From'] = self.username
        self.response_msg['To'] = self.sender
        self.response_msg['Cc'] = ", ".join(self.cc_list)
        self.response_msg['Date'] = formatdate(localtime=True)
        self.response_msg['Subject'] = 'cuckooinbox report: ' + self.subject

        '''attach cuckooinbox email body'''
        for id in self.taskids:
            '''wait for reports to finish before sending'''
            timeout = time.time() + 120
            while time.time() < timeout:
                if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html")): continue
                time.sleep(.25)
            if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","inbox.html")):
                file = open(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","inbox.html"))
                body = '<html>' + \
                    '<div class="section-title">'+ \
                    '<h2>Task ID %d <small></small></h2>' % id + \
                    '</div>'+ \
                    '<table class="table table-striped table-bordered">'+ \
                    file.read() + \
                    '</html>'
                file.close()
                response_text = ''.join(body)
                self.response_msg.attach(MIMEText(response_text,'html'))
            else: print '[!] Could not find cuckoobox report files.'

        '''wait for analysis to finish and zip the reports'''
        self.zipResults()
        
        '''send the message'''
        if '@gmail.com' in self.username:
            smtp = smtplib.SMTP('smtp.gmail.com',587)
            smtp.starttls()
            smtp.login(self.username, self.passwd)
        else:
            smtp = smtplib.SMTP(self.smtp_server)
            try: smtp.login(self.username,self.passwd)
            except:
                self.log_entry.logEvent('[!] SMTP login failed.')
        try: smtp.sendmail(self.username, self.sender, self.response_msg.as_string())
        except:
            self.log_entry.logEvent('SMTP message %s failed to send.' % self.subject)
        smtp.close()
        self.log_entry.logEvent('[-] Sent "%s" report to %s' % (self.subject, self.sender))
        self.server.logout()