# 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()
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()
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()